diff --git a/.eslintrc.js b/.eslintrc.js index 6c072c326..4d573688f 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -52,6 +52,6 @@ module.exports = { 'error', { default: ['signature', 'field', 'constructor', 'method'] } ], - 'no-unused-vars': ['error', { "destructuredArrayIgnorePattern": "^_" }] + '@typescript-eslint/no-unused-vars': ['error'] }, }; diff --git a/docs/docs/api/model/document-model.md b/docs/docs/api/model/document-model.md index 4da765d30..b609f0050 100644 --- a/docs/docs/api/model/document-model.md +++ b/docs/docs/api/model/document-model.md @@ -220,7 +220,7 @@ checkNesting( **@since v1.0.16** ### isDetectingNode -检查拖拽放置的目标节点是否可以放置该拖拽对象 +判断是否当前节点处于被探测状态 ```typescript /** diff --git a/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx b/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx index da3c73ae5..75b4a3488 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx +++ b/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx @@ -13,9 +13,9 @@ import { observer, computed, Tip, globalContext } from '@alilc/lowcode-editor-co import { createIcon, isReactComponent, isActionContentObject } from '@alilc/lowcode-utils'; import { IPublicTypeActionContentObject } from '@alilc/lowcode-types'; import { BuiltinSimulatorHost } from '../host'; -import { OffsetObserver } from '../../designer'; -import { Node } from '../../document'; +import { INode, OffsetObserver } from '../../designer'; import NodeSelector from '../node-selector'; +import { ISimulatorHost } from '../../simulator'; @observer export class BorderSelectingInstance extends Component<{ @@ -116,8 +116,8 @@ class Toolbar extends Component<{ observed: OffsetObserver }> { } } -function createAction(content: ReactNode | ComponentType | IPublicTypeActionContentObject, key: string, node: Node) { - if (isValidElement(content)) { +function createAction(content: ReactNode | ComponentType | IPublicTypeActionContentObject, key: string, node: INode) { + if (isValidElement<{ key: string; node: INode }>(content)) { return cloneElement(content, { key, node }); } if (isReactComponent(content)) { @@ -130,7 +130,7 @@ function createAction(content: ReactNode | ComponentType | IPublicTypeActio key={key} className="lc-borders-action" onClick={() => { - action && action(node); + action && action(node.internalToShellNode()!); const workspace = globalContext.get('workspace'); const editor = workspace.isActive ? workspace.window.editor : globalContext.get('editor'); const npm = node?.componentMeta?.npm; @@ -153,8 +153,8 @@ function createAction(content: ReactNode | ComponentType | IPublicTypeActio } @observer -export class BorderSelectingForNode extends Component<{ host: BuiltinSimulatorHost; node: Node }> { - get host(): BuiltinSimulatorHost { +export class BorderSelectingForNode extends Component<{ host: ISimulatorHost; node: INode }> { + get host(): ISimulatorHost { return this.props.host; } diff --git a/packages/designer/src/builtin-simulator/host.ts b/packages/designer/src/builtin-simulator/host.ts index 6415a1b4c..91ab1a17b 100644 --- a/packages/designer/src/builtin-simulator/host.ts +++ b/packages/designer/src/builtin-simulator/host.ts @@ -6,6 +6,7 @@ import { getPublicPath, focusTracker, engineConfig, + globalLocale, IReactionPublic, IReactionOptions, IReactionDisposer, @@ -47,26 +48,26 @@ import { getRectTarget, CanvasPoint, Designer, + IDesigner, } from '../designer'; import { parseMetadata } from './utils/parse-metadata'; import { getClosestClickableNode } from './utils/clickable'; import { IPublicTypeComponentMetadata, - IPublicTypeComponentSchema, IPublicTypePackage, IPublicEnumTransitionType, IPublicEnumDragObjectType, - IPublicTypeDragNodeObject, IPublicTypeNodeInstance, IPublicTypeComponentInstance, IPublicTypeLocationChildrenDetail, IPublicTypeLocationDetailType, IPublicTypeRect, + IPublicModelNode, } from '@alilc/lowcode-types'; import { BuiltinSimulatorRenderer } from './renderer'; import { clipboard } from '../designer/clipboard'; import { LiveEditing } from './live-editing/live-editing'; -import { Project } from '../project'; +import { IProject, Project } from '../project'; import { IScroller } from '../designer/scroller'; import { isElementNode, isDOMNodeVisible } from '../utils/misc'; import { debounce } from 'lodash'; @@ -164,9 +165,9 @@ const defaultRaxEnvironment = [ export class BuiltinSimulatorHost implements ISimulatorHost { readonly isSimulator = true; - readonly project: Project; + readonly project: IProject; - readonly designer: Designer; + readonly designer: IDesigner; readonly viewport = new Viewport(); @@ -198,7 +199,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost { - this.project.currentDocument && detecting.leave(this.project.currentDocument) + this.project.currentDocument && detecting.leave(this.project.currentDocument); }; doc.addEventListener('mouseover', hover, true); @@ -812,7 +813,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost { const onMoveHook = node.componentMeta?.advanced.callbacks?.onMoveHook; const canMove = onMoveHook && typeof onMoveHook === 'function' ? onMoveHook(node.internalToShellNode()) : true; - let parentContainerNode: Node | null = null; + let parentContainerNode: INode | null = null; let parentNode = node.parent; while (parentNode) { @@ -1254,7 +1256,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost, - e: ILocateEvent, ) { const { children } = container; - const document = this.project.currentDocument!; if (!children || children.isEmpty()) { return null; } - const nearDistance: any = null; const nearBy: any = null; for (let i = 0, l = children.size; i < l; i++) { let child = children.get(i); diff --git a/packages/designer/src/builtin-simulator/node-selector/index.tsx b/packages/designer/src/builtin-simulator/node-selector/index.tsx index 27211f224..09c8f1262 100644 --- a/packages/designer/src/builtin-simulator/node-selector/index.tsx +++ b/packages/designer/src/builtin-simulator/node-selector/index.tsx @@ -1,19 +1,19 @@ import { Overlay } from '@alifd/next'; -import React from 'react'; +import React, { MouseEvent } from 'react'; import { Title, globalContext } from '@alilc/lowcode-editor-core'; import { canClickNode } from '@alilc/lowcode-utils'; import './index.less'; -import { Node, INode } from '@alilc/lowcode-designer'; +import { INode } from '@alilc/lowcode-designer'; const { Popup } = Overlay; export interface IProps { - node: Node; + node: INode; } export interface IState { - parentNodes: Node[]; + parentNodes: INode[]; } type UnionNode = INode | null; @@ -26,14 +26,18 @@ export default class InstanceNodeSelector extends React.Component { + getParentNodes = (node: INode) => { const parentNodes: any[] = []; - const { focusNode } = node.document; + const focusNode = node.document?.focusNode; + + if (!focusNode) { + return null; + } if (node.contains(focusNode) || !focusNode.contains(node)) { return parentNodes; @@ -53,12 +57,12 @@ export default class InstanceNodeSelector extends React.Component (e: unknown) => { + onSelect = (node: INode) => (event: MouseEvent) => { if (!node) { return; } - const canClick = canClickNode(node, e as MouseEvent); + const canClick = canClickNode(node.internalToShellNode()!, event); if (canClick && typeof node.select === 'function') { node.select(); @@ -76,19 +80,19 @@ export default class InstanceNodeSelector extends React.Component (_: any, flag = true) => { + onMouseOver = (node: INode) => (_: any, flag = true) => { if (node && typeof node.hover === 'function') { node.hover(flag); } }; - onMouseOut = (node: Node) => (_: any, flag = false) => { + onMouseOut = (node: INode) => (_: any, flag = false) => { if (node && typeof node.hover === 'function') { node.hover(flag); } }; - renderNodes = (/* node: Node */) => { + renderNodes = () => { const nodes = this.state.parentNodes; if (!nodes || nodes.length < 1) { return null; @@ -136,7 +140,7 @@ export default class InstanceNodeSelector extends React.Component -
{this.renderNodes(node)}
+
{this.renderNodes()}
); diff --git a/packages/designer/src/designer/designer.ts b/packages/designer/src/designer/designer.ts index a1d05a8dd..74c1f51b2 100644 --- a/packages/designer/src/designer/designer.ts +++ b/packages/designer/src/designer/designer.ts @@ -16,17 +16,15 @@ import { IPublicModelScroller, IPublicTypeLocationData, IPublicEnumTransformStage, - IPublicModelDragon, - IPublicModelDropLocation, IPublicModelLocateEvent, } from '@alilc/lowcode-types'; import { megreAssets, IPublicTypeAssetsJson, isNodeSchema, isDragNodeObject, isDragNodeDataObject, isLocationChildrenDetail, Logger } from '@alilc/lowcode-utils'; -import { Project } from '../project'; +import { IProject, Project } from '../project'; import { Node, DocumentModel, insertChildren, INode } from '../document'; import { ComponentMeta, IComponentMeta } from '../component-meta'; import { INodeSelector, Component } from '../simulator'; import { Scroller } from './scroller'; -import { Dragon, IDragon, ILocateEvent } from './dragon'; +import { Dragon, IDragon } from './dragon'; import { ActiveTracker, IActiveTracker } from './active-tracker'; import { Detecting } from './detecting'; import { DropLocation } from './location'; @@ -64,7 +62,11 @@ export interface DesignerProps { export interface IDesigner { readonly shellModelFactory: IShellModelFactory; - get dragon(): IPublicModelDragon; + viewName: string | undefined; + + readonly project: IProject; + + get dragon(): IDragon; get activeTracker(): IActiveTracker; @@ -78,6 +80,10 @@ export interface IDesigner { createScroller(scrollable: IPublicTypeScrollable): IPublicModelScroller; + refreshComponentMetasMap(): void; + + createOffsetObserver(nodeInstance: INodeSelector): OffsetObserver | null; + /** * 创建插入位置,考虑放到 dragon 中 */ @@ -92,6 +98,8 @@ export interface IDesigner { generateMetadata?: () => IPublicTypeComponentMetadata | null, ): IComponentMeta; + clearLocation(): void; + createComponentMeta(data: IPublicTypeComponentMetadata): IComponentMeta | null; getComponentMetasMap(): Map; @@ -118,7 +126,7 @@ export class Designer implements IDesigner { readonly detecting = new Detecting(); - readonly project: Project; + readonly project: IProject; readonly editor: IPublicModelEditor; @@ -140,7 +148,7 @@ export class Designer implements IDesigner { @obx.ref private _simulatorComponent?: ComponentType; - @obx.ref private _simulatorProps?: Record | ((project: Project) => object); + @obx.ref private _simulatorProps?: Record | ((project: IProject) => object); @obx.ref private _suspensed = false; diff --git a/packages/designer/src/designer/dragon.ts b/packages/designer/src/designer/dragon.ts index 2fc0ca3e5..8dcce2b4a 100644 --- a/packages/designer/src/designer/dragon.ts +++ b/packages/designer/src/designer/dragon.ts @@ -11,9 +11,9 @@ import { IPublicModelSensor, } from '@alilc/lowcode-types'; import { setNativeSelection, cursor } from '@alilc/lowcode-utils'; -import { Node } from '../document'; +import { INode, Node } from '../document'; import { ISimulatorHost, isSimulatorHost } from '../simulator'; -import { Designer } from './designer'; +import { IDesigner } from './designer'; import { makeEventsHandler } from '../utils/misc'; export interface ILocateEvent extends IPublicModelLocateEvent { @@ -88,14 +88,17 @@ function getSourceSensor(dragObject: IPublicModelDragObject): ISimulatorHost | n if (!isDragNodeObject(dragObject)) { return null; } - return dragObject.nodes[0]?.document.simulator || null; + return dragObject.nodes[0]?.document?.simulator || null; } function isDragEvent(e: any): e is DragEvent { return e?.type?.startsWith('drag'); } -export interface IDragon extends IPublicModelDragon { +export interface IDragon extends IPublicModelDragon< + INode, + ILocateEvent +> { emitter: IEventBus; } @@ -130,7 +133,7 @@ export class Dragon implements IDragon { emitter: IEventBus = createModuleEventBus('Dragon'); - constructor(readonly designer: Designer) { + constructor(readonly designer: IDesigner) { makeObservable(this); this.viewName = designer.viewName; } @@ -167,7 +170,7 @@ export class Dragon implements IDragon { * @param dragObject 拖拽对象 * @param boostEvent 拖拽初始时事件 */ - boost(dragObject: IPublicModelDragObject, boostEvent: MouseEvent | DragEvent, fromRglNode?: Node | IPublicModelNode) { + boost(dragObject: IPublicModelDragObject, boostEvent: MouseEvent | DragEvent, fromRglNode?: INode | IPublicModelNode) { const { designer } = this; const masterSensors = this.getMasterSensors(); const handleEvents = makeEventsHandler(boostEvent, masterSensors); @@ -264,7 +267,7 @@ export class Dragon implements IDragon { this.emitter.emit('rgl.add.placeholder', { rglNode, fromRglNode, - node: locateEvent.dragObject.nodes[0], + node: locateEvent.dragObject?.nodes[0], event: e, }); designer.clearLocation(); diff --git a/packages/designer/src/designer/offset-observer.ts b/packages/designer/src/designer/offset-observer.ts index d9dd07dba..2cf5bfee2 100644 --- a/packages/designer/src/designer/offset-observer.ts +++ b/packages/designer/src/designer/offset-observer.ts @@ -2,7 +2,7 @@ import requestIdleCallback, { cancelIdleCallback } from 'ric-shim'; import { obx, computed, makeObservable } from '@alilc/lowcode-editor-core'; import { uniqueId } from '@alilc/lowcode-utils'; import { INodeSelector, IViewport } from '../simulator'; -import { Node } from '../document'; +import { INode } from '../document'; export class OffsetObserver { readonly id = uniqueId('oobx'); @@ -93,11 +93,11 @@ export class OffsetObserver { private pid: number | undefined; - readonly viewport: IViewport; + readonly viewport: IViewport | undefined; private isRoot: boolean; - readonly node: Node; + readonly node: INode; readonly compute: () => void; @@ -105,10 +105,10 @@ export class OffsetObserver { const { node, instance } = nodeInstance; this.node = node; const doc = node.document; - const host = doc.simulator!; - const focusNode = doc.focusNode; + const host = doc?.simulator; + const focusNode = doc?.focusNode; this.isRoot = node.contains(focusNode!); - this.viewport = host.viewport; + this.viewport = host?.viewport; makeObservable(this); if (this.isRoot) { this.hasOffset = true; @@ -118,7 +118,7 @@ export class OffsetObserver { return; } - let pid: number; + let pid: number | undefined; const compute = () => { if (pid !== this.pid) { return; diff --git a/packages/designer/src/document/document-model.ts b/packages/designer/src/document/document-model.ts index e44e21d35..2731aa5e6 100644 --- a/packages/designer/src/document/document-model.ts +++ b/packages/designer/src/document/document-model.ts @@ -35,7 +35,7 @@ import { isDragNodeDataObject, isNode, } from '@alilc/lowcode-utils'; -import { IProject, Project } from '../project'; +import { IProject } from '../project'; import { ISimulatorHost } from '../simulator'; import { IComponentMeta } from '../component-meta'; import { IDesigner, IHistory } from '../designer'; @@ -56,7 +56,7 @@ export type GetDataType = T extends undefined export interface IDocumentModel extends Omit< IPublicModelDocumentModel< ISelection, IHistory, - INode | IRootNode, + INode, IDropLocation, IModalNodesManager, IProject @@ -81,6 +81,8 @@ export interface IDocumentModel extends Omit< IPublicModelDocumentModel< readonly designer: IDesigner; + selection: ISelection; + get rootNode(): INode | null; get simulator(): ISimulatorHost | null; @@ -98,8 +100,6 @@ export interface IDocumentModel extends Omit< IPublicModelDocumentModel< get currentRoot(): INode | null; - selection: ISelection; - isBlank(): boolean; /** diff --git a/packages/designer/src/plugin/plugin-types.ts b/packages/designer/src/plugin/plugin-types.ts index 837fae4b1..f76e20827 100644 --- a/packages/designer/src/plugin/plugin-types.ts +++ b/packages/designer/src/plugin/plugin-types.ts @@ -6,7 +6,6 @@ import { IPublicApiMaterial, IPublicApiEvent, IPublicApiCommon, - IPublicTypeCompositeObject, IPublicApiPlugins, IPublicTypePluginConfig, IPublicApiLogger, @@ -16,7 +15,9 @@ import { IPublicApiCanvas, IPublicApiWorkspace, IPublicTypePluginMeta, + IPublicTypePluginRegisterOptions, } from '@alilc/lowcode-types'; +import PluginContext from './plugin-context'; export type PluginPreference = Map>; @@ -72,7 +73,7 @@ export interface ILowCodePluginManagerCore { register( pluginModel: IPublicTypePlugin, pluginOptions?: any, - options?: IPublicTypeCompositeObject, + options?: IPublicTypePluginRegisterOptions, ): Promise; init(pluginPreference?: Map>): Promise; get(pluginName: string): ILowCodePluginRuntime | undefined; @@ -81,6 +82,7 @@ export interface ILowCodePluginManagerCore { delete(pluginName: string): any; setDisabled(pluginName: string, flag: boolean): void; dispose(): void; + _getLowCodePluginContext (options: IPluginContextOptions): PluginContext; } export type ILowCodePluginManager = ILowCodePluginManagerCore & ILowCodePluginManagerPluginAccessor; diff --git a/packages/designer/src/project/project.ts b/packages/designer/src/project/project.ts index 51db678ad..3204e5c8b 100644 --- a/packages/designer/src/project/project.ts +++ b/packages/designer/src/project/project.ts @@ -41,6 +41,14 @@ export interface IProject extends Omit< IBaseApiProject< get documents(): IDocumentModel[]; + get i18n(): { + [local: string]: { + [key: string]: any; + }; + }; + + mountSimulator(simulator: ISimulatorHost): void; + open(doc?: string | IDocumentModel | IPublicTypeRootSchema): IDocumentModel | null; getDocumentByFileName(fileName: string): IDocumentModel | null; diff --git a/packages/designer/src/simulator.ts b/packages/designer/src/simulator.ts index 99586fb81..3a63a685b 100644 --- a/packages/designer/src/simulator.ts +++ b/packages/designer/src/simulator.ts @@ -1,8 +1,9 @@ import { ComponentType } from 'react'; import { IPublicTypeComponentMetadata, IPublicTypeNodeSchema, IPublicTypeScrollable, IPublicTypeComponentInstance, IPublicModelSensor, IPublicTypeNodeInstance, IPublicTypePackage } from '@alilc/lowcode-types'; -import { Point, ScrollTarget, ILocateEvent } from './designer'; +import { Point, ScrollTarget, ILocateEvent, IDesigner } from './designer'; import { BuiltinSimulatorRenderer } from './builtin-simulator/renderer'; import { INode } from './document'; +import { IProject } from './project'; export type AutoFit = '100%'; // eslint-disable-next-line no-redeclare @@ -89,6 +90,10 @@ export interface ISimulatorHost

extends IPublicModelSensor { readonly contentDocument?: Document; readonly renderer?: BuiltinSimulatorRenderer; + readonly project: IProject; + + readonly designer: IDesigner; + // dependsAsset // like react jQuery lodash // themesAsset // componentsAsset diff --git a/packages/editor-core/src/editor.ts b/packages/editor-core/src/editor.ts index 737a9fa26..e1d25bdff 100644 --- a/packages/editor-core/src/editor.ts +++ b/packages/editor-core/src/editor.ts @@ -2,7 +2,7 @@ /* eslint-disable max-len */ import { StrictEventEmitter } from 'strict-event-emitter-types'; import { EventEmitter } from 'events'; -import { EventBus } from './event-bus'; +import { EventBus, IEventBus } from './event-bus'; import { IPublicModelEditor, EditorConfig, @@ -52,15 +52,18 @@ export declare interface Editor extends StrictEventEmitter; } +export interface IEditor extends IPublicModelEditor { + config?: EditorConfig; + + components?: PluginClassSet; + + eventBus: IEventBus; + + init(config?: EditorConfig, components?: PluginClassSet): Promise; +} + // eslint-disable-next-line no-redeclare -export class Editor extends (EventEmitter as any) implements IPublicModelEditor { - constructor(readonly viewName: string = 'global', readonly workspaceMode: boolean = false) { - // eslint-disable-next-line constructor-super - super(); - // set global emitter maxListeners - this.setMaxListeners(200); - this.eventBus = new EventBus(this); - } +export class Editor extends EventEmitter implements IEditor { /** * Ioc Container @@ -71,10 +74,32 @@ export class Editor extends (EventEmitter as any) implements IPublicModelEditor return globalLocale.getLocale(); } + config?: EditorConfig; + + eventBus: EventBus; + + components?: PluginClassSet; + // readonly utils = utils; private hooks: HookConfig[] = []; + private waits = new Map< + IPublicTypeEditorValueKey, + Array<{ + once?: boolean; + resolve: (data: any) => void; + }> + >(); + + constructor(readonly viewName: string = 'global', readonly workspaceMode: boolean = false) { + // eslint-disable-next-line constructor-super + super(); + // set global emitter maxListeners + this.setMaxListeners(200); + this.eventBus = new EventBus(this); + } + get( keyOrType: KeyOrType, ): IPublicTypeEditorGetResult | undefined { @@ -202,12 +227,6 @@ export class Editor extends (EventEmitter as any) implements IPublicModelEditor this.notifyGot(key || data); } - config?: EditorConfig; - - eventBus: EventBus; - - components?: PluginClassSet; - async init(config?: EditorConfig, components?: PluginClassSet): Promise { this.config = config || {}; this.components = components || {}; @@ -270,16 +289,6 @@ export class Editor extends (EventEmitter as any) implements IPublicModelEditor }); }; - /* eslint-disable */ - private waits = new Map< - IPublicTypeEditorValueKey, - Array<{ - once?: boolean; - resolve: (data: any) => void; - }> - >(); - /* eslint-enable */ - private notifyGot(key: IPublicTypeEditorValueKey) { let waits = this.waits.get(key); if (!waits) { diff --git a/packages/editor-core/src/hotkey.ts b/packages/editor-core/src/hotkey.ts index 30390daca..adc74262a 100644 --- a/packages/editor-core/src/hotkey.ts +++ b/packages/editor-core/src/hotkey.ts @@ -339,8 +339,8 @@ function fireCallback(callback: IPublicTypeHotkeyCallback, e: KeyboardEvent, com } } -export interface IHotKey extends IPublicApiHotkey { - +export interface IHotKey extends Omit { + activate(activate: boolean): void; } export class Hotkey implements IHotKey { diff --git a/packages/editor-core/src/widgets/tip/tip-container.tsx b/packages/editor-core/src/widgets/tip/tip-container.tsx index ae494d540..ed3af589a 100644 --- a/packages/editor-core/src/widgets/tip/tip-container.tsx +++ b/packages/editor-core/src/widgets/tip/tip-container.tsx @@ -1,4 +1,5 @@ import { Component } from 'react'; +import ReactDOM from 'react-dom'; import { TipItem } from './tip-item'; import { tipHandler } from './tip-handler'; @@ -25,7 +26,7 @@ export class TipContainer extends Component { } render() { - return window.ReactDOM.createPortal( + return ReactDOM.createPortal(

, diff --git a/packages/editor-core/src/widgets/title/index.tsx b/packages/editor-core/src/widgets/title/index.tsx index b616ce69d..88a15ab29 100644 --- a/packages/editor-core/src/widgets/title/index.tsx +++ b/packages/editor-core/src/widgets/title/index.tsx @@ -1,7 +1,7 @@ import { Component, isValidElement, ReactNode } from 'react'; import classNames from 'classnames'; -import { createIcon, isI18nData } from '@alilc/lowcode-utils'; -import { IPublicTypeTitleContent, IPublicTypeI18nData } from '@alilc/lowcode-types'; +import { createIcon, isI18nData, isTitleConfig } from '@alilc/lowcode-utils'; +import { IPublicTypeTitleContent, IPublicTypeI18nData, IPublicTypeTitleConfig } from '@alilc/lowcode-types'; import { intl } from '../../intl'; import { Tip } from '../tip'; import './title.less'; @@ -88,7 +88,8 @@ export class Title extends Component<{ render() { // eslint-disable-next-line prefer-const - let { title, className } = this.props; + const { title, className } = this.props; + let _title: IPublicTypeTitleConfig; if (title == null) { return null; } @@ -96,34 +97,40 @@ export class Title extends Component<{ return title; } if (typeof title === 'string' || isI18nData(title)) { - title = { label: title }; + _title = { label: title }; + } else if (isTitleConfig(title)) { + _title = title; + } else { + _title = { + label: title, + }; } - const icon = title.icon ? createIcon(title.icon, { size: 20 }) : null; + const icon = _title.icon ? createIcon(_title.icon, { size: 20 }) : null; let tip: any = null; - if (title.tip) { - if (isValidElement(title.tip) && title.tip.type === Tip) { - tip = title.tip; + if (_title.tip) { + if (isValidElement(_title.tip) && _title.tip.type === Tip) { + tip = _title.tip; } else { const tipProps = - typeof title.tip === 'object' && !(isValidElement(title.tip) || isI18nData(title.tip)) - ? title.tip - : { children: title.tip }; + typeof _title.tip === 'object' && !(isValidElement(_title.tip) || isI18nData(_title.tip)) + ? _title.tip + : { children: _title.tip }; tip = ; } } return ( {icon ? {icon} : null} - {this.renderLabel(title.label)} + {this.renderLabel(_title.label)} {tip} ); diff --git a/packages/editor-skeleton/src/area.ts b/packages/editor-skeleton/src/area.ts index e96103ad6..8dc711084 100644 --- a/packages/editor-skeleton/src/area.ts +++ b/packages/editor-skeleton/src/area.ts @@ -3,7 +3,7 @@ import { obx, computed, makeObservable } from '@alilc/lowcode-editor-core'; import { Logger } from '@alilc/lowcode-utils'; import { IPublicTypeWidgetBaseConfig } from '@alilc/lowcode-types'; import { WidgetContainer } from './widget/widget-container'; -import { Skeleton } from './skeleton'; +import { ISkeleton } from './skeleton'; import { IWidget } from './widget/widget'; const logger = new Logger({ level: 'warn', bizName: 'skeleton:area' }); @@ -35,7 +35,9 @@ export class Area; - constructor(readonly skeleton: Skeleton, readonly name: string, handle: (item: T | C) => T, private exclusive?: boolean, defaultSetCurrent = false) { + private lastCurrent: T | null = null; + + constructor(readonly skeleton: ISkeleton, readonly name: string, handle: (item: T | C) => T, private exclusive?: boolean, defaultSetCurrent = false) { makeObservable(this); this.container = skeleton.createContainer(name, handle, exclusive, () => this.visible, defaultSetCurrent); } @@ -57,8 +59,6 @@ export class Area void; diff --git a/packages/editor-skeleton/src/components/widget-views/index.tsx b/packages/editor-skeleton/src/components/widget-views/index.tsx index ba7a3756b..87f11664c 100644 --- a/packages/editor-skeleton/src/components/widget-views/index.tsx +++ b/packages/editor-skeleton/src/components/widget-views/index.tsx @@ -47,6 +47,8 @@ function HelpTip({ tip }: any) { @observer export class PanelDockView extends Component { + private lastActived = false; + componentDidMount() { this.checkActived(); } @@ -55,8 +57,6 @@ export class PanelDockView extends Component { this.checkActived(); } - private lastActived = false; - checkActived() { const { dock } = this.props; if (dock.actived !== this.lastActived) { @@ -134,7 +134,7 @@ export class DraggableLineView extends Component<{ panel: Panel }> { // 默认 关闭,通过配置开启 const enableDrag = this.props.panel.config.props?.enableDrag; const isRightArea = this.props.panel.config?.area === 'rightArea'; - if (isRightArea || !enableDrag || this.props.panel?.parent.name === 'leftFixedArea') { + if (isRightArea || !enableDrag || this.props.panel?.parent?.name === 'leftFixedArea') { return null; } return ( @@ -159,6 +159,8 @@ export class DraggableLineView extends Component<{ panel: Panel }> { @observer export class TitledPanelView extends Component<{ panel: Panel; area?: string }> { + private lastVisible = false; + componentDidMount() { this.checkVisible(); } @@ -167,8 +169,6 @@ export class TitledPanelView extends Component<{ panel: Panel; area?: string }> this.checkVisible(); } - private lastVisible = false; - checkVisible() { const { panel } = this.props; const currentVisible = panel.inited && panel.visible; @@ -218,6 +218,8 @@ export class PanelView extends Component<{ hideOperationRow?: boolean; hideDragLine?: boolean; }> { + private lastVisible = false; + componentDidMount() { this.checkVisible(); } @@ -226,8 +228,6 @@ export class PanelView extends Component<{ this.checkVisible(); } - private lastVisible = false; - checkVisible() { const { panel } = this.props; const currentVisible = panel.inited && panel.visible; @@ -331,6 +331,9 @@ class PanelTitle extends Component<{ panel: Panel; className?: string }> { @observer export class WidgetView extends Component<{ widget: IWidget }> { + private lastVisible = false; + private lastDisabled: boolean | undefined = false; + componentDidMount() { this.checkVisible(); this.checkDisabled(); @@ -341,9 +344,6 @@ export class WidgetView extends Component<{ widget: IWidget }> { this.checkDisabled(); } - private lastVisible = false; - private lastDisabled = false; - checkVisible() { const { widget } = this.props; const currentVisible = widget.visible; diff --git a/packages/editor-skeleton/src/context.ts b/packages/editor-skeleton/src/context.ts index ee213e886..58eb48ac6 100644 --- a/packages/editor-skeleton/src/context.ts +++ b/packages/editor-skeleton/src/context.ts @@ -1,4 +1,4 @@ import { createContext } from 'react'; -import { Skeleton } from './skeleton'; +import { ISkeleton } from './skeleton'; -export const SkeletonContext = createContext({} as any); +export const SkeletonContext = createContext({} as any); diff --git a/packages/editor-skeleton/src/layouts/left-float-pane.tsx b/packages/editor-skeleton/src/layouts/left-float-pane.tsx index f44f60240..0be5ea6c3 100644 --- a/packages/editor-skeleton/src/layouts/left-float-pane.tsx +++ b/packages/editor-skeleton/src/layouts/left-float-pane.tsx @@ -3,9 +3,10 @@ import classNames from 'classnames'; import { observer, Focusable, focusTracker } from '@alilc/lowcode-editor-core'; import { Area } from '../area'; import { Panel } from '../widget/panel'; +import { PanelConfig } from '../types'; @observer -export default class LeftFloatPane extends Component<{ area: Area }> { +export default class LeftFloatPane extends Component<{ area: Area }> { private dispose?: () => void; private focusing?: Focusable; diff --git a/packages/editor-skeleton/src/layouts/workbench.less b/packages/editor-skeleton/src/layouts/workbench.less index 34018aa86..f97e1f46f 100644 --- a/packages/editor-skeleton/src/layouts/workbench.less +++ b/packages/editor-skeleton/src/layouts/workbench.less @@ -323,10 +323,8 @@ body { display: flex; align-items: center; justify-content: center; + cursor: pointer; - &.has-tip { - cursor: pointer; - } &.actived { color: #0079f2; } diff --git a/packages/editor-skeleton/src/layouts/workbench.tsx b/packages/editor-skeleton/src/layouts/workbench.tsx index e50bec4ec..1e412ed67 100644 --- a/packages/editor-skeleton/src/layouts/workbench.tsx +++ b/packages/editor-skeleton/src/layouts/workbench.tsx @@ -1,7 +1,7 @@ import { Component } from 'react'; import { TipContainer, observer } from '@alilc/lowcode-editor-core'; import classNames from 'classnames'; -import { Skeleton } from '../skeleton'; +import { ISkeleton } from '../skeleton'; import TopArea from './top-area'; import LeftArea from './left-area'; import LeftFixedPane from './left-fixed-pane'; @@ -16,7 +16,7 @@ import { EditorConfig, PluginClassSet } from '@alilc/lowcode-types'; @observer export class Workbench extends Component<{ - skeleton: Skeleton; + skeleton: ISkeleton; config?: EditorConfig; components?: PluginClassSet; className?: string; diff --git a/packages/editor-skeleton/src/skeleton.ts b/packages/editor-skeleton/src/skeleton.ts index 22f165b1d..180859f1d 100644 --- a/packages/editor-skeleton/src/skeleton.ts +++ b/packages/editor-skeleton/src/skeleton.ts @@ -1,4 +1,4 @@ -import { Editor, action, makeObservable, obx, engineConfig } from '@alilc/lowcode-editor-core'; +import { action, makeObservable, obx, engineConfig, IEditor } from '@alilc/lowcode-editor-core'; import { DockConfig, PanelConfig, @@ -27,6 +27,7 @@ import { IPublicTypeWidgetBaseConfig, IPublicTypeWidgetConfigArea, IPublicTypeSkeletonConfig, + IPublicApiSkeleton, } from '@alilc/lowcode-types'; const logger = new Logger({ level: 'warn', bizName: 'skeleton' }); @@ -42,6 +43,66 @@ export enum SkeletonEvents { WIDGET_ENABLE = 'skeleton.widget.enable', } +export interface ISkeleton extends Omit { + editor: IEditor; + + readonly leftArea: Area; + + readonly topArea: Area; + + readonly subTopArea: Area; + + readonly toolbar: Area; + + readonly leftFixedArea: Area; + + readonly leftFloatArea: Area; + + readonly rightArea: Area; + + readonly mainArea: Area; + + readonly bottomArea: Area; + + readonly stages: Area; + + readonly widgets: IWidget[]; + + getPanel(name: string): Panel | undefined; + + getWidget(name: string): IWidget | undefined; + + buildFromConfig(config?: EditorConfig, components?: PluginClassSet): void; + + createStage(config: any): string | undefined; + + getStage(name: string): Stage | null; + + createContainer( + name: string, + handle: (item: any) => any, + exclusive?: boolean, + checkVisible?: () => boolean, + defaultSetCurrent?: boolean, + ): WidgetContainer; + + createPanel(config: PanelConfig): Panel; +} + export class Skeleton { private panels = new Map(); @@ -69,7 +130,7 @@ export class Skeleton { readonly widgets: IWidget[] = []; - constructor(readonly editor: Editor, readonly viewName: string = 'global') { + constructor(readonly editor: IEditor, readonly viewName: string = 'global') { makeObservable(this); this.leftArea = new Area( this, @@ -244,7 +305,7 @@ export class Skeleton { Object.keys(plugins).forEach((area) => { plugins[area].forEach((item) => { const { pluginKey, type, props = {}, pluginProps } = item; - const config: Partial = { + const config: IPublicTypeWidgetBaseConfig = { area: area as IPublicTypeWidgetConfigArea, type: 'Widget', name: pluginKey, @@ -272,7 +333,7 @@ export class Skeleton { if (pluginKey in components) { config.content = components[pluginKey]; } - this.add(config as IPublicTypeWidgetBaseConfig); + this.add(config); }); }); } diff --git a/packages/editor-skeleton/src/transducers/parse-func.ts b/packages/editor-skeleton/src/transducers/parse-func.ts index d6e83667a..b25310350 100644 --- a/packages/editor-skeleton/src/transducers/parse-func.ts +++ b/packages/editor-skeleton/src/transducers/parse-func.ts @@ -4,6 +4,7 @@ import { isPlainObject, isJSFunction, getLogger } from '@alilc/lowcode-utils'; const leadingFnRe = /^function/; const leadingFnNameRe = /^\w+\s*\(/; const logger = getLogger({ level: 'warn', bizName: 'skeleton:transducers' }); + /** * 将函数字符串转成函数,支持几种类型 * 类型一:() => {} / val => {} diff --git a/packages/editor-skeleton/src/types.ts b/packages/editor-skeleton/src/types.ts index a51369f15..b73dc4adc 100644 --- a/packages/editor-skeleton/src/types.ts +++ b/packages/editor-skeleton/src/types.ts @@ -1,12 +1,11 @@ import { ReactElement, ComponentType } from 'react'; import { IPublicTypeTitleContent, - IPublicTypeIconType, IPublicTypeI18nData, - TipContent, IPublicTypeWidgetConfigArea, IPublicTypeWidgetBaseConfig, IPublicTypePanelDockPanelProps, + IPublicTypePanelDockProps, } from '@alilc/lowcode-types'; import { IWidget } from './widget/widget'; @@ -24,13 +23,7 @@ export function isWidgetConfig(obj: any): obj is WidgetConfig { return obj && obj.type === 'Widget'; } -export interface DockProps { - title?: IPublicTypeTitleContent; - icon?: IPublicTypeIconType; - size?: 'small' | 'medium' | 'large'; - className?: string; - description?: TipContent; - onClick?: () => void; +export interface DockProps extends IPublicTypePanelDockProps { } export interface DividerConfig extends IPublicTypeWidgetBaseConfig { diff --git a/packages/editor-skeleton/src/widget/dock.ts b/packages/editor-skeleton/src/widget/dock.ts index 819d5c616..20cdd425d 100644 --- a/packages/editor-skeleton/src/widget/dock.ts +++ b/packages/editor-skeleton/src/widget/dock.ts @@ -3,7 +3,7 @@ import { makeObservable, obx } from '@alilc/lowcode-editor-core'; import { uniqueId, createContent } from '@alilc/lowcode-utils'; import { getEvent } from '@alilc/lowcode-shell'; import { DockConfig } from '../types'; -import { Skeleton } from '../skeleton'; +import { ISkeleton } from '../skeleton'; import { DockView, WidgetView } from '../components/widget-views'; import { IWidget } from './widget'; @@ -59,7 +59,7 @@ export class Dock implements IWidget { return this._body; } - constructor(readonly skeleton: Skeleton, readonly config: DockConfig) { + constructor(readonly skeleton: ISkeleton, readonly config: DockConfig) { makeObservable(this); const { props = {}, name } = config; this.name = name; diff --git a/packages/editor-skeleton/src/widget/panel-dock.ts b/packages/editor-skeleton/src/widget/panel-dock.ts index f2a56e80c..896849706 100644 --- a/packages/editor-skeleton/src/widget/panel-dock.ts +++ b/packages/editor-skeleton/src/widget/panel-dock.ts @@ -1,7 +1,7 @@ import { obx, computed, makeObservable } from '@alilc/lowcode-editor-core'; import { uniqueId } from '@alilc/lowcode-utils'; import { createElement, ReactNode, ReactInstance } from 'react'; -import { Skeleton } from '../skeleton'; +import { ISkeleton } from '../skeleton'; import { PanelDockConfig } from '../types'; import { Panel } from './panel'; import { PanelDockView, WidgetView } from '../components/widget-views'; @@ -18,7 +18,7 @@ export class PanelDock implements IWidget { readonly name: string; - readonly align?: string; + readonly align?: 'left' | 'right' | 'bottom' | 'center' | 'top' | undefined; private inited = false; @@ -51,11 +51,6 @@ export class PanelDock implements IWidget { }); } - getDOMNode() { - // eslint-disable-next-line react/no-find-dom-node - return this._shell ? findDOMNode(this._shell) : null; - } - @obx.ref private _visible = true; get visible() { @@ -76,7 +71,7 @@ export class PanelDock implements IWidget { return this._panel || this.skeleton.getPanel(this.panelName); } - constructor(readonly skeleton: Skeleton, readonly config: PanelDockConfig) { + constructor(readonly skeleton: ISkeleton, readonly config: PanelDockConfig) { makeObservable(this); const { content, contentProps, panelProps, name, props } = config; this.name = name; @@ -84,7 +79,7 @@ export class PanelDock implements IWidget { this.panelName = config.panelName || name; this.align = props?.align; if (content) { - const _panelProps: any = { ...panelProps }; + const _panelProps = { ...panelProps }; if (_panelProps.title == null && props) { _panelProps.title = composeTitle(props.title, undefined, props.description, true, true); } @@ -102,6 +97,11 @@ export class PanelDock implements IWidget { } } + getDOMNode() { + // eslint-disable-next-line react/no-find-dom-node + return this._shell ? findDOMNode(this._shell) : null; + } + setVisible(flag: boolean) { if (flag === this._visible) { return; @@ -170,7 +170,6 @@ export class PanelDock implements IWidget { } } - export function isPanelDock(obj: any): obj is PanelDock { return obj && obj.isPanelDock; } diff --git a/packages/editor-skeleton/src/widget/panel.ts b/packages/editor-skeleton/src/widget/panel.ts index b74c87b94..feec08da7 100644 --- a/packages/editor-skeleton/src/widget/panel.ts +++ b/packages/editor-skeleton/src/widget/panel.ts @@ -6,7 +6,7 @@ import { WidgetContainer } from './widget-container'; import { getEvent } from '@alilc/lowcode-shell'; import { PanelConfig, HelpTipConfig } from '../types'; import { TitledPanelView, TabsPanelView, PanelView } from '../components/widget-views'; -import { Skeleton } from '../skeleton'; +import { ISkeleton } from '../skeleton'; import { composeTitle } from './utils'; import { IWidget } from './widget'; import { isPanelDock, PanelDock } from './panel-dock'; @@ -80,7 +80,7 @@ export class Panel implements IWidget { @obx.ref public parent?: WidgetContainer; - constructor(readonly skeleton: Skeleton, readonly config: PanelConfig) { + constructor(readonly skeleton: ISkeleton, readonly config: PanelConfig) { makeObservable(this); const { name, content, props = {} } = config; const { hideTitleBar, title, icon, description, help } = props; @@ -111,7 +111,7 @@ export class Panel implements IWidget { props.onInit.call(this, this); } - if (content.onInit) { + if (typeof content !== 'string' && content && content.onInit) { content.onInit.call(this, this); } // todo: process shortcut diff --git a/packages/editor-skeleton/src/widget/stage.ts b/packages/editor-skeleton/src/widget/stage.ts index bd233ad95..2b177af61 100644 --- a/packages/editor-skeleton/src/widget/stage.ts +++ b/packages/editor-skeleton/src/widget/stage.ts @@ -1,6 +1,6 @@ // import { uniqueId } from '@alilc/lowcode-utils'; import { Widget } from './widget'; -import { Skeleton } from '../skeleton'; +import { ISkeleton } from '../skeleton'; import { WidgetConfig } from '../types'; export interface StageConfig extends WidgetConfig { @@ -17,7 +17,7 @@ export class Stage extends Widget { direction?: 'right' | 'left'; }; - constructor(skeleton: Skeleton, config: StageConfig) { + constructor(skeleton: ISkeleton, config: StageConfig) { super(skeleton, config); this.isRoot = config.isRoot || false; } diff --git a/packages/editor-skeleton/src/widget/utils.ts b/packages/editor-skeleton/src/widget/utils.ts index a5d105969..c4096d2e2 100644 --- a/packages/editor-skeleton/src/widget/utils.ts +++ b/packages/editor-skeleton/src/widget/utils.ts @@ -3,45 +3,51 @@ import { isI18nData, isTitleConfig } from '@alilc/lowcode-utils'; import { isValidElement } from 'react'; export function composeTitle(title?: IPublicTypeTitleContent, icon?: IPublicTypeIconType, tip?: TipContent, tipAsTitle?: boolean, noIcon?: boolean) { + let _title: IPublicTypeTitleContent | undefined; if (!title) { - title = {}; + _title = {}; if (!icon || tipAsTitle) { - title.label = tip; + _title = { + label: tip, + }; tip = undefined; } + } else { + _title = title; } + if (icon || tip) { - if (typeof title !== 'object' || isValidElement(title) || isI18nData(title)) { - if (isValidElement(title)) { - if (title.type === 'svg' || (title.type as any).getIcon) { + if (typeof _title !== 'object' || isValidElement(_title) || isI18nData(_title)) { + if (isValidElement(_title)) { + if (_title.type === 'svg' || _title.type.getIcon) { if (!icon) { - icon = title as any; + icon = _title; } if (tipAsTitle) { - title = tip as any; + _title = tip; tip = null; } else { - title = undefined; + _title = undefined; } } } - title = { - label: title, + _title = { + label: _title, icon, tip, }; } else { - title = { - ...title, + _title = { + ..._title, icon, tip, }; } } - if (isTitleConfig(title) && noIcon) { + if (isTitleConfig(_title) && noIcon) { if (!isValidElement(title)) { - title.icon = undefined; + _title.icon = undefined; } } - return title; + return _title; } diff --git a/packages/editor-skeleton/src/widget/widget.ts b/packages/editor-skeleton/src/widget/widget.ts index d0df99a1e..c95673877 100644 --- a/packages/editor-skeleton/src/widget/widget.ts +++ b/packages/editor-skeleton/src/widget/widget.ts @@ -3,7 +3,7 @@ import { makeObservable, obx } from '@alilc/lowcode-editor-core'; import { createContent, uniqueId } from '@alilc/lowcode-utils'; import { getEvent } from '@alilc/lowcode-shell'; import { WidgetConfig } from '../types'; -import { Skeleton } from '../skeleton'; +import { ISkeleton } from '../skeleton'; import { WidgetView } from '../components/widget-views'; import { IPublicTypeTitleContent, IPublicTypeWidgetBaseConfig } from '@alilc/lowcode-types'; @@ -15,7 +15,7 @@ export interface IWidget { readonly visible: boolean; readonly disabled?: boolean; readonly body: ReactNode; - readonly skeleton: Skeleton; + readonly skeleton: ISkeleton; readonly config: IPublicTypeWidgetBaseConfig; getName(): string; @@ -71,7 +71,7 @@ export class Widget implements IWidget { readonly title: IPublicTypeTitleContent; - constructor(readonly skeleton: Skeleton, readonly config: WidgetConfig) { + constructor(readonly skeleton: ISkeleton, readonly config: WidgetConfig) { makeObservable(this); const { props = {}, name } = config; this.name = name; diff --git a/packages/react-simulator-renderer/src/renderer.ts b/packages/react-simulator-renderer/src/renderer.ts index dbb24a5bb..44fec0009 100644 --- a/packages/react-simulator-renderer/src/renderer.ts +++ b/packages/react-simulator-renderer/src/renderer.ts @@ -461,6 +461,7 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer { locale: renderer.locale, messages: _schema.i18n || {}, device: renderer.device, + locale: renderer.locale, appHelper: renderer.context, rendererName: 'LowCodeRenderer', thisRequiredInJSE: host.thisRequiredInJSE, @@ -632,4 +633,4 @@ function getLowCodeComponentProps(props: any) { return newProps; } -export default new SimulatorRendererContainer(); \ No newline at end of file +export default new SimulatorRendererContainer(); diff --git a/packages/shell/src/api/event.ts b/packages/shell/src/api/event.ts index 746d9ae6a..0fb41966e 100644 --- a/packages/shell/src/api/event.ts +++ b/packages/shell/src/api/event.ts @@ -1,4 +1,4 @@ -import { Editor as InnerEditor, EventBus } from '@alilc/lowcode-editor-core'; +import { IEditor, IEventBus } from '@alilc/lowcode-editor-core'; import { getLogger, isPluginEventName } from '@alilc/lowcode-utils'; import { IPublicApiEvent, IPublicTypeDisposable } from '@alilc/lowcode-types'; @@ -11,10 +11,10 @@ type EventOptions = { const eventBusSymbol = Symbol('eventBus'); export class Event implements IPublicApiEvent { - private readonly [eventBusSymbol]: EventBus; + private readonly [eventBusSymbol]: IEventBus; private readonly options: EventOptions; - constructor(eventBus: EventBus, options: EventOptions, public workspaceMode = false) { + constructor(eventBus: IEventBus, options: EventOptions, public workspaceMode = false) { this[eventBusSymbol] = eventBus; this.options = options; if (!this.options.prefix) { @@ -69,6 +69,6 @@ export class Event implements IPublicApiEvent { } } -export function getEvent(editor: InnerEditor, options: any = { prefix: 'common' }) { +export function getEvent(editor: IEditor, options: any = { prefix: 'common' }) { return new Event(editor.eventBus, options); } diff --git a/packages/shell/src/api/plugins.ts b/packages/shell/src/api/plugins.ts index 6e2b9c6b7..e5a79edbd 100644 --- a/packages/shell/src/api/plugins.ts +++ b/packages/shell/src/api/plugins.ts @@ -1,5 +1,5 @@ import { - LowCodePluginManager, + ILowCodePluginManager, } from '@alilc/lowcode-designer'; import { globalContext } from '@alilc/lowcode-editor-core'; import { @@ -14,8 +14,8 @@ import { pluginsSymbol } from '../symbols'; const innerPluginsSymbol = Symbol('plugin'); export class Plugins implements IPublicApiPlugins { - private readonly [innerPluginsSymbol]: LowCodePluginManager; - get [pluginsSymbol](): LowCodePluginManager { + private readonly [innerPluginsSymbol]: ILowCodePluginManager; + get [pluginsSymbol](): ILowCodePluginManager { if (this.workspaceMode) { return this[innerPluginsSymbol]; } @@ -27,7 +27,7 @@ export class Plugins implements IPublicApiPlugins { return this[innerPluginsSymbol]; } - constructor(plugins: LowCodePluginManager, public workspaceMode: boolean = false) { + constructor(plugins: ILowCodePluginManager, public workspaceMode: boolean = false) { this[innerPluginsSymbol] = plugins; } diff --git a/packages/shell/src/api/skeleton.ts b/packages/shell/src/api/skeleton.ts index e9bb28328..928c55a0d 100644 --- a/packages/shell/src/api/skeleton.ts +++ b/packages/shell/src/api/skeleton.ts @@ -1,17 +1,18 @@ import { globalContext } from '@alilc/lowcode-editor-core'; import { - Skeleton as InnerSkeleton, + ISkeleton, SkeletonEvents, } from '@alilc/lowcode-editor-skeleton'; import { skeletonSymbol } from '../symbols'; import { IPublicApiSkeleton, IPublicTypeDisposable, IPublicTypeSkeletonConfig, IPublicTypeWidgetConfigArea } from '@alilc/lowcode-types'; const innerSkeletonSymbol = Symbol('skeleton'); + export class Skeleton implements IPublicApiSkeleton { - private readonly [innerSkeletonSymbol]: InnerSkeleton; + private readonly [innerSkeletonSymbol]: ISkeleton; private readonly pluginName: string; - get [skeletonSymbol](): InnerSkeleton { + get [skeletonSymbol](): ISkeleton { if (this.workspaceMode) { return this[innerSkeletonSymbol]; } @@ -24,7 +25,7 @@ export class Skeleton implements IPublicApiSkeleton { } constructor( - skeleton: InnerSkeleton, + skeleton: ISkeleton, pluginName: string, readonly workspaceMode: boolean = false, ) { @@ -57,7 +58,7 @@ export class Skeleton implements IPublicApiSkeleton { if (!normalizeArea(area)) { return; } - skeleton[normalizeArea(area)!].container?.remove(name); + skeleton[normalizeArea(area)].container?.remove(name); } /** @@ -185,7 +186,7 @@ export class Skeleton implements IPublicApiSkeleton { } } -function normalizeArea(area: IPublicTypeWidgetConfigArea | undefined) { +function normalizeArea(area: IPublicTypeWidgetConfigArea | undefined): 'leftArea' | 'rightArea' | 'topArea' | 'toolbar' | 'mainArea' | 'bottomArea' | 'leftFixedArea' | 'leftFloatArea' | 'stages' { switch (area) { case 'leftArea': case 'left': diff --git a/packages/shell/src/api/workspace.ts b/packages/shell/src/api/workspace.ts index 54fccf426..ae4bc65aa 100644 --- a/packages/shell/src/api/workspace.ts +++ b/packages/shell/src/api/workspace.ts @@ -1,13 +1,13 @@ import { IPublicApiWorkspace, IPublicResourceList, IPublicTypeDisposable, IPublicTypeResourceType } from '@alilc/lowcode-types'; -import { Workspace as InnerWorkSpace } from '@alilc/lowcode-workspace'; +import { IWorkspace } from '@alilc/lowcode-workspace'; import { Plugins } from '@alilc/lowcode-shell'; import { workspaceSymbol } from '../symbols'; import { Resource as ShellResource, Window as ShellWindow } from '../model'; export class Workspace implements IPublicApiWorkspace { - readonly [workspaceSymbol]: InnerWorkSpace; + readonly [workspaceSymbol]: IWorkspace; - constructor(innerWorkspace: InnerWorkSpace) { + constructor(innerWorkspace: IWorkspace) { this[workspaceSymbol] = innerWorkspace; } diff --git a/packages/shell/src/model/dragon.ts b/packages/shell/src/model/dragon.ts index 392e3d158..7f2492e7e 100644 --- a/packages/shell/src/model/dragon.ts +++ b/packages/shell/src/model/dragon.ts @@ -1,5 +1,7 @@ import { + IDragon, ILocateEvent as InnerLocateEvent, + INode, } from '@alilc/lowcode-designer'; import { dragonSymbol, nodeSymbol } from '../symbols'; import LocateEvent from './locate-event'; @@ -11,18 +13,19 @@ import { IPublicModelDragObject, IPublicTypeDragNodeDataObject, IPublicModelNode, + IPublicTypeDragObject, } from '@alilc/lowcode-types'; export const innerDragonSymbol = Symbol('innerDragonSymbol'); export class Dragon implements IPublicModelDragon { - private readonly [innerDragonSymbol]: IPublicModelDragon; + private readonly [innerDragonSymbol]: IDragon; - constructor(innerDragon: IPublicModelDragon, readonly workspaceMode: boolean) { + constructor(innerDragon: IDragon, readonly workspaceMode: boolean) { this[innerDragonSymbol] = innerDragon; } - get [dragonSymbol](): any { + get [dragonSymbol](): IDragon { if (this.workspaceMode) { return this[innerDragonSymbol]; } @@ -38,7 +41,7 @@ export class Dragon implements IPublicModelDragon { } static create( - dragon: IPublicModelDragon | null, + dragon: IDragon | null, workspaceMode: boolean, ): IPublicModelDragon | null { if (!dragon) { @@ -102,11 +105,13 @@ export class Dragon implements IPublicModelDragon { * @param dragObject 拖拽对象 * @param boostEvent 拖拽初始时事件 */ - boost(dragObject: DragObject, boostEvent: MouseEvent | DragEvent, fromRglNode?: Node | IPublicModelNode): void { + boost(dragObject: IPublicTypeDragObject, boostEvent: MouseEvent | DragEvent, fromRglNode?: IPublicModelNode & { + [nodeSymbol]: INode; + }): void { return this[dragonSymbol].boost({ ...dragObject, nodes: dragObject.nodes.map((node: any) => node[nodeSymbol]), - }, boostEvent, fromRglNode); + }, boostEvent, fromRglNode?.[nodeSymbol]); } /** diff --git a/packages/shell/src/model/locate-event.ts b/packages/shell/src/model/locate-event.ts index 4c8f955b0..20451f946 100644 --- a/packages/shell/src/model/locate-event.ts +++ b/packages/shell/src/model/locate-event.ts @@ -1,16 +1,16 @@ -import { ILocateEvent as InnerLocateEvent } from '@alilc/lowcode-designer'; +import { ILocateEvent } from '@alilc/lowcode-designer'; import { locateEventSymbol } from '../symbols'; import { DragObject } from './drag-object'; import { IPublicModelLocateEvent, IPublicModelDragObject } from '@alilc/lowcode-types'; export default class LocateEvent implements IPublicModelLocateEvent { - private readonly [locateEventSymbol]: InnerLocateEvent; + private readonly [locateEventSymbol]: ILocateEvent; - constructor(locateEvent: InnerLocateEvent) { + constructor(locateEvent: ILocateEvent) { this[locateEventSymbol] = locateEvent; } - static create(locateEvent: InnerLocateEvent): IPublicModelLocateEvent | null { + static create(locateEvent: ILocateEvent): IPublicModelLocateEvent | null { if (!locateEvent) { return null; } diff --git a/packages/shell/src/model/resource.ts b/packages/shell/src/model/resource.ts index 63435cdea..b2b065398 100644 --- a/packages/shell/src/model/resource.ts +++ b/packages/shell/src/model/resource.ts @@ -1,11 +1,11 @@ import { IPublicModelResource } from '@alilc/lowcode-types'; -import { Resource as InnerResource } from '@alilc/lowcode-workspace'; +import { IResource } from '@alilc/lowcode-workspace'; import { resourceSymbol } from '../symbols'; export class Resource implements IPublicModelResource { - readonly [resourceSymbol]: InnerResource; + readonly [resourceSymbol]: IResource; - constructor(resource: InnerResource) { + constructor(resource: IResource) { this[resourceSymbol] = resource; } diff --git a/packages/shell/src/model/window.ts b/packages/shell/src/model/window.ts index e2f17b889..b1263d541 100644 --- a/packages/shell/src/model/window.ts +++ b/packages/shell/src/model/window.ts @@ -1,10 +1,10 @@ import { windowSymbol } from '../symbols'; import { IPublicModelResource, IPublicModelWindow, IPublicTypeDisposable } from '@alilc/lowcode-types'; -import { EditorWindow } from '@alilc/lowcode-workspace'; +import { IEditorWindow } from '@alilc/lowcode-workspace'; import { Resource as ShellResource } from './resource'; export class Window implements IPublicModelWindow { - private readonly [windowSymbol]: EditorWindow; + private readonly [windowSymbol]: IEditorWindow; get id() { return this[windowSymbol]?.id; @@ -22,7 +22,7 @@ export class Window implements IPublicModelWindow { return new ShellResource(this[windowSymbol].resource); } - constructor(editorWindow: EditorWindow) { + constructor(editorWindow: IEditorWindow) { this[windowSymbol] = editorWindow; } diff --git a/packages/types/src/shell/api/workspace.ts b/packages/types/src/shell/api/workspace.ts index c1be4cb7e..8c19846f7 100644 --- a/packages/types/src/shell/api/workspace.ts +++ b/packages/types/src/shell/api/workspace.ts @@ -2,19 +2,20 @@ import { IPublicModelWindow } from '../model'; import { IPublicApiPlugins, IPublicModelResource, IPublicResourceList, IPublicTypeDisposable, IPublicTypeResourceType } from '@alilc/lowcode-types'; export interface IPublicApiWorkspace< - Plugins = IPublicApiPlugins + Plugins = IPublicApiPlugins, + ModelWindow = IPublicModelWindow > { /** 是否启用 workspace 模式 */ isActive: boolean; /** 当前设计器窗口 */ - window: IPublicModelWindow; + window: ModelWindow; plugins: Plugins; /** 当前设计器的编辑窗口 */ - windows: IPublicModelWindow[]; + windows: ModelWindow[]; /** 获取资源树列表 */ get resourceList(): IPublicModelResource[]; diff --git a/packages/types/src/shell/model/drag-object.ts b/packages/types/src/shell/model/drag-object.ts index 9169ea853..af404a2f0 100644 --- a/packages/types/src/shell/model/drag-object.ts +++ b/packages/types/src/shell/model/drag-object.ts @@ -1,8 +1,3 @@ -export interface IPublicModelDragObject { +import { IPublicTypeDragNodeDataObject, IPublicTypeDragNodeObject } from '../type'; - get type(): any; - - get nodes(): any; - - get data(): any; -} +export type IPublicModelDragObject = Readonly | Readonly; diff --git a/packages/types/src/shell/model/dragon.ts b/packages/types/src/shell/model/dragon.ts index 67ddb82c7..662eb6a00 100644 --- a/packages/types/src/shell/model/dragon.ts +++ b/packages/types/src/shell/model/dragon.ts @@ -3,7 +3,8 @@ import { IPublicTypeDragNodeDataObject, IPublicTypeDragObject } from '../type'; import { IPublicModelDragObject, IPublicModelLocateEvent, IPublicModelNode } from './'; export interface IPublicModelDragon< - Node = IPublicModelNode + Node = IPublicModelNode, + LocateEvent = IPublicModelLocateEvent > { /** @@ -18,7 +19,7 @@ export interface IPublicModelDragon< * @param func * @returns */ - onDragstart(func: (e: IPublicModelLocateEvent) => any): () => void; + onDragstart(func: (e: LocateEvent) => any): () => void; /** * 绑定 drag 事件 @@ -26,7 +27,7 @@ export interface IPublicModelDragon< * @param func * @returns */ - onDrag(func: (e: IPublicModelLocateEvent) => any): () => void; + onDrag(func: (e: LocateEvent) => any): () => void; /** * 绑定 dragend 事件 diff --git a/packages/types/src/shell/model/resource.ts b/packages/types/src/shell/model/resource.ts index c81776659..e18f3d503 100644 --- a/packages/types/src/shell/model/resource.ts +++ b/packages/types/src/shell/model/resource.ts @@ -1,6 +1,8 @@ import { ReactElement } from 'react'; -export interface IPublicModelResource { +export interface IBaseModelResource< + Resource +> { get title(): string | undefined; get icon(): ReactElement | undefined; @@ -13,7 +15,9 @@ export interface IPublicModelResource { get category(): string | undefined; - get children(): IPublicModelResource[]; + get children(): Resource[]; get viewName(): string | undefined; -} \ No newline at end of file +} + +export type IPublicModelResource = IBaseModelResource; diff --git a/packages/types/src/shell/model/window.ts b/packages/types/src/shell/model/window.ts index f772dc9f4..bb27ce317 100644 --- a/packages/types/src/shell/model/window.ts +++ b/packages/types/src/shell/model/window.ts @@ -2,7 +2,9 @@ import { ReactElement } from 'react'; import { IPublicTypeDisposable, IPublicTypeNodeSchema } from '../type'; import { IPublicModelResource } from './resource'; -export interface IPublicModelWindow { +export interface IPublicModelWindow< + Resource = IPublicModelResource +> { /** 窗口 id */ id: string; @@ -14,7 +16,7 @@ export interface IPublicModelWindow { icon?: ReactElement; /** 窗口资源类型 */ - resource?: IPublicModelResource; + resource?: Resource; /** 当前窗口导入 schema */ importSchema(schema: IPublicTypeNodeSchema): void; diff --git a/packages/types/src/shell/type/action-content-object.ts b/packages/types/src/shell/type/action-content-object.ts index 25e913f02..cf3e0c048 100644 --- a/packages/types/src/shell/type/action-content-object.ts +++ b/packages/types/src/shell/type/action-content-object.ts @@ -1,19 +1,23 @@ +import { IPublicModelNode } from '../model'; import { IPublicTypeIconType, TipContent } from './'; /** * 动作描述 */ export interface IPublicTypeActionContentObject { + /** * 图标 */ icon?: IPublicTypeIconType; + /** * 描述 */ title?: TipContent; + /** * 执行动作 */ - action?: (currentNode: any) => void; + action?: (currentNode: IPublicModelNode) => void; } diff --git a/packages/types/src/shell/type/location.ts b/packages/types/src/shell/type/location.ts index c9e2df67f..4f8b59a7c 100644 --- a/packages/types/src/shell/type/location.ts +++ b/packages/types/src/shell/type/location.ts @@ -15,13 +15,14 @@ export enum LocationDetailType { } export type IPublicTypeRect = DOMRect & { - elements: Array; + elements?: Array; computed?: boolean; }; export interface IPublicTypeLocationChildrenDetail { type: IPublicTypeLocationDetailType.Children; index?: number | null; + /** * 是否有效位置 */ @@ -43,8 +44,7 @@ export interface IPublicTypeLocationPropDetail { domNode?: HTMLElement; } -// eslint-disable-next-line max-len -export type IPublicTypeLocationDetail = IPublicTypeLocationChildrenDetail | IPublicTypeLocationPropDetail | { type: string; [key: string]: any }; +export type IPublicTypeLocationDetail = IPublicTypeLocationChildrenDetail | IPublicTypeLocationPropDetail | { [key: string]: any; type: string }; export interface IPublicTypeLocationData< Node = IPublicModelNode diff --git a/packages/types/src/shell/type/metadata.ts b/packages/types/src/shell/type/metadata.ts index 7f972622b..7ed9dc6be 100644 --- a/packages/types/src/shell/type/metadata.ts +++ b/packages/types/src/shell/type/metadata.ts @@ -1,3 +1,4 @@ +import { MouseEvent } from 'react'; import { IPublicTypePropType, IPublicTypeComponentAction } from './'; import { IPublicModelNode, IPublicModelProp, IPublicModelSettingField } from '../model'; diff --git a/packages/types/src/shell/type/resource-list.ts b/packages/types/src/shell/type/resource-list.ts index db5e33dc8..5831d7b50 100644 --- a/packages/types/src/shell/type/resource-list.ts +++ b/packages/types/src/shell/type/resource-list.ts @@ -1,20 +1,27 @@ import { ReactElement } from 'react'; export interface IPublicResourceData { + /** 资源名字 */ resourceName: string; + /** 资源标题 */ - title: string; + title?: string; + /** 分类 */ category?: string; + /** 资源视图 */ viewName?: string; + /** 资源 icon */ icon?: ReactElement; + /** 资源其他配置 */ options: { [key: string]: any; }; + /** 资源子元素 */ children?: IPublicResourceData[]; } diff --git a/packages/types/src/shell/type/widget-base-config.ts b/packages/types/src/shell/type/widget-base-config.ts index 08c14c8db..8a8cda24f 100644 --- a/packages/types/src/shell/type/widget-base-config.ts +++ b/packages/types/src/shell/type/widget-base-config.ts @@ -1,4 +1,4 @@ -import { IPublicTypeWidgetConfigArea } from './'; +import { IPublicTypeIconType, IPublicTypeTitleContent, IPublicTypeWidgetConfigArea, TipContent } from './'; export interface IPublicTypeWidgetBaseConfig { [extra: string]: any; @@ -21,6 +21,24 @@ export interface IPublicTypePanelDockConfig extends IPublicTypeWidgetBaseConfig type: 'PanelDock'; panelProps?: IPublicTypePanelDockPanelProps; + + props?: IPublicTypePanelDockProps; +} + +export interface IPublicTypePanelDockProps { + [key: string]: any; + + size?: 'small' | 'medium' | 'large'; + + className?: string; + + description?: TipContent; + + onClick?: () => void; + + icon?: IPublicTypeIconType; + + title?: IPublicTypeTitleContent; } export interface IPublicTypePanelDockPanelProps { diff --git a/packages/utils/src/check-types/is-action-content-object.ts b/packages/utils/src/check-types/is-action-content-object.ts index 20c817177..4e9a6545a 100644 --- a/packages/utils/src/check-types/is-action-content-object.ts +++ b/packages/utils/src/check-types/is-action-content-object.ts @@ -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'; } diff --git a/packages/utils/src/check-types/is-location-data.ts b/packages/utils/src/check-types/is-location-data.ts index 3fa3a4204..8bb310346 100644 --- a/packages/utils/src/check-types/is-location-data.ts +++ b/packages/utils/src/check-types/is-location-data.ts @@ -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; } \ No newline at end of file diff --git a/packages/utils/src/css-helper.ts b/packages/utils/src/css-helper.ts index 9858d0d54..98bf1bbf0 100644 --- a/packages/utils/src/css-helper.ts +++ b/packages/utils/src/css-helper.ts @@ -10,14 +10,13 @@ const pseudoMap = ['hover', 'focus', 'active', 'visited']; const RE_CAMEL = /[A-Z]/g; const RE_HYPHEN = /[-\s]+(.)?/g; -const CSS_REG = /:root(.*)\{.*/i; const PROPS_REG = /([^:]*):\s?(.*)/i; // 给 css 分组 -function groupingCss(css) { +function groupingCss(css: string) { let stackLength = 0; let startIndex = 0; - const group = []; + const group: string[] = []; css.split('').forEach((char, index) => { if (char === '{') { stackLength++; @@ -33,38 +32,38 @@ function groupingCss(css) { return group; } - -function isString(str) { +function isString(str: any): str is string { return {}.toString.call(str) === '[object String]'; } -function hyphenate(str) { +function hyphenate(str: string): string { return str.replace(RE_CAMEL, w => `-${w}`).toLowerCase(); } -function camelize(str) { +function camelize(str: string): string { return str.replace(RE_HYPHEN, (m, w) => (w ? w.toUpperCase() : '')); } + /** * convert * {background-color: "red"} * to * background-color: red; */ -function runtimeToCss(runtime) { - const css = []; +function runtimeToCss(runtime: Record) { + const css: string[] = []; Object.keys(runtime).forEach((key) => { css.push(` ${key}: ${runtime[key]};`); }); return css.join('\n'); } -function toNativeStyle(runtime) { +function toNativeStyle(runtime: Record | undefined) { if (!runtime) { return {}; } if (runtime.default) { - const normalized = {}; + const normalized: Record = {}; Object.keys(runtime).forEach((pseudo) => { if (pseudo === 'extra') { normalized[pseudo] = runtime[pseudo]; @@ -98,14 +97,13 @@ function normalizeStyle(style) { return normalized; } - const normalized = {}; + const normalized: Record> = {}; Object.keys(style).forEach((key) => { normalized[hyphenate(key)] = style[key]; }); return normalized; } - function toCss(runtime) { if (!runtime) { return ( @@ -115,7 +113,7 @@ function toCss(runtime) { } if (runtime.default) { - const css = []; + const css: string[] = []; Object.keys(runtime).forEach((pseudo) => { if (pseudo === 'extra') { Array.isArray(runtime.extra) && css.push(runtime.extra.join('\n')); @@ -140,11 +138,14 @@ ${runtimeToCss(normalizeStyle(runtime))} ); } -function cssToRuntime(css) { +function cssToRuntime(css: string) { if (!css) { return {}; } - const runtime = {}; + const runtime: { + extra?: string[]; + default?: Record; + } = {}; const groups = groupingCss(css); groups.forEach((cssItem) => { if (!cssItem.startsWith(':root')) { @@ -153,7 +154,7 @@ function cssToRuntime(css) { } else { const res = /:root:?(.*)?{(.*)/ig.exec(cssItem.replace(/[\r\n]+/ig, '').trim()); if (res) { - let pseudo; + let pseudo: string | undefined; if (res[1] && res[1].trim() && some(pseudoMap, pse => res[1].indexOf(pse) === 0)) { pseudo = res[1].trim(); @@ -161,8 +162,8 @@ function cssToRuntime(css) { pseudo = res[1]; } - const s = {}; - res[2].split(';').reduce((prev, next) => { + const s: Record = {}; + res[2].split(';').reduce((prev, next) => { if (next.indexOf('base64') > -1) { prev[prev.length - 1] += `;${next}`; } else { @@ -173,8 +174,8 @@ function cssToRuntime(css) { if (item) { if (PROPS_REG.test(item)) { const props = item.match(PROPS_REG); - const key = props[1]; - const value = props[2]; + const key = props?.[1]; + const value = props?.[2]; if (key && value) { s[key.trim()] = value.trim(); } @@ -182,10 +183,7 @@ function cssToRuntime(css) { } }); - if (!pseudo) { - pseudo = 'default'; - } - runtime[pseudo] = s; + runtime[pseudo || 'default'] = s; } } }); diff --git a/packages/utils/src/is-react.ts b/packages/utils/src/is-react.ts index 02ef50fa6..1f17f9afc 100644 --- a/packages/utils/src/is-react.ts +++ b/packages/utils/src/is-react.ts @@ -23,7 +23,8 @@ export function isReactComponent(obj: any): obj is ComponentType { export function wrapReactClass(view: FunctionComponent) { let ViewComponentClass = class extends Component { render() { - return createElement(view, this.props); + const { children, ...other } = this.props; + return createElement(view, other, children); } } as any; ViewComponentClass = cloneEnumerableProperty(ViewComponentClass, view); diff --git a/packages/utils/src/node-helper.ts b/packages/utils/src/node-helper.ts index 55d42be4e..60102d679 100644 --- a/packages/utils/src/node-helper.ts +++ b/packages/utils/src/node-helper.ts @@ -1,5 +1,6 @@ // 仅使用类型 import { IPublicModelNode } from '@alilc/lowcode-types'; +import { MouseEvent } from 'react'; export const getClosestNode = ( node: Node, @@ -12,7 +13,7 @@ export const getClosestNode = return node; } else { // @ts-ignore - return getClosestNode(node.getParent(), until); + return getClosestNode(node.parent, until); } }; @@ -22,8 +23,8 @@ export const getClosestNode = * @param {unknown} e 点击事件 * @returns {boolean} 是否可点击,true表示可点击 */ -export function canClickNode(node: Node, e: unknown): boolean { +export function canClickNode(node: Node, e: MouseEvent): boolean { const onClickHook = node.componentMeta?.advanced?.callbacks?.onClickHook; - const canClick = typeof onClickHook === 'function' ? onClickHook(e as MouseEvent, node) : true; + const canClick = typeof onClickHook === 'function' ? onClickHook(e, node) : true; return canClick; -}; +} diff --git a/packages/workspace/src/context/base-context.ts b/packages/workspace/src/context/base-context.ts index b67842fe8..b82e25872 100644 --- a/packages/workspace/src/context/base-context.ts +++ b/packages/workspace/src/context/base-context.ts @@ -3,13 +3,17 @@ import { engineConfig, Setters as InnerSetters, Hotkey as InnerHotkey, commonEvent, + IEngineConfig, + IHotKey, } from '@alilc/lowcode-editor-core'; import { Designer, ILowCodePluginContextApiAssembler, LowCodePluginManager, ILowCodePluginContextPrivate, - Project as InnerProject, + IProject, + IDesigner, + ILowCodePluginManager, } from '@alilc/lowcode-designer'; import { Skeleton as InnerSkeleton, @@ -29,40 +33,72 @@ import { } from '@alilc/lowcode-shell'; import { IPluginPreferenceMananger, + IPublicApiCanvas, + IPublicApiCommon, IPublicApiEvent, - IPublicApiWorkspace, + IPublicApiHotkey, + IPublicApiMaterial, + IPublicApiPlugins, + IPublicApiProject, + IPublicApiSetters, + IPublicApiSkeleton, IPublicModelPluginContext, IPublicTypePluginMeta, } from '@alilc/lowcode-types'; -import { getLogger } from '@alilc/lowcode-utils'; -import { Workspace as InnerWorkspace } from '../workspace'; -import { EditorWindow } from '../window'; +import { getLogger, Logger as InnerLogger } from '@alilc/lowcode-utils'; +import { IWorkspace } from '../workspace'; +import { IEditorWindow } from '../window'; -export class BasicContext implements IPublicModelPluginContext { - skeleton: Skeleton; - plugins: Plugins; - project: Project; - setters: Setters; - material: Material; - common: Common; - config; - event; - logger; - hotkey: Hotkey; - innerProject: InnerProject; +export interface IBasicContext extends Omit { + skeleton: IPublicApiSkeleton; + plugins: IPublicApiPlugins; + project: IPublicApiProject; + setters: IPublicApiSetters; + material: IPublicApiMaterial; + common: IPublicApiCommon; + config: IEngineConfig; + event: IPublicApiEvent; + logger: InnerLogger; + hotkey: IPublicApiHotkey; + innerProject: IProject; editor: Editor; - designer: Designer; + designer: IDesigner; registerInnerPlugins: () => Promise; innerSetters: InnerSetters; innerSkeleton: InnerSkeleton; - innerHotkey: InnerHotkey; - innerPlugins: LowCodePluginManager; - canvas: Canvas; + innerHotkey: IHotKey; + innerPlugins: ILowCodePluginManager; + canvas: IPublicApiCanvas; pluginEvent: IPublicApiEvent; preference: IPluginPreferenceMananger; - workspace: IPublicApiWorkspace; + workspace: IWorkspace; +} - constructor(innerWorkspace: InnerWorkspace, viewName: string, public editorWindow?: EditorWindow) { +export class BasicContext implements IBasicContext { + skeleton: IPublicApiSkeleton; + plugins: IPublicApiPlugins; + project: IPublicApiProject; + setters: IPublicApiSetters; + material: IPublicApiMaterial; + common: IPublicApiCommon; + config: IEngineConfig; + event: IPublicApiEvent; + logger: InnerLogger; + hotkey: IPublicApiHotkey; + innerProject: IProject; + editor: Editor; + designer: IDesigner; + registerInnerPlugins: () => Promise; + innerSetters: InnerSetters; + innerSkeleton: InnerSkeleton; + innerHotkey: IHotKey; + innerPlugins: ILowCodePluginManager; + canvas: IPublicApiCanvas; + pluginEvent: IPublicApiEvent; + preference: IPluginPreferenceMananger; + workspace: IWorkspace; + + constructor(innerWorkspace: IWorkspace, viewName: string, public editorWindow?: IEditorWindow) { const editor = new Editor(viewName, true); const innerSkeleton = new InnerSkeleton(editor, viewName); @@ -110,7 +146,7 @@ export class BasicContext implements IPublicModelPluginContext { this.canvas = canvas; const common = new Common(editor, innerSkeleton); this.common = common; - let plugins: any; + let plugins: IPublicApiPlugins; const pluginContextApiAssembler: ILowCodePluginContextApiAssembler = { assembleApis: (context: ILowCodePluginContextPrivate, pluginName: string, meta: IPublicTypePluginMeta) => { diff --git a/packages/workspace/src/context/view-context.ts b/packages/workspace/src/context/view-context.ts index d14549667..38a9e570f 100644 --- a/packages/workspace/src/context/view-context.ts +++ b/packages/workspace/src/context/view-context.ts @@ -1,9 +1,9 @@ import { computed, makeObservable, obx } from '@alilc/lowcode-editor-core'; import { IPublicEditorViewConfig, IPublicTypeEditorView } from '@alilc/lowcode-types'; import { flow } from 'mobx'; -import { Workspace as InnerWorkspace } from '../workspace'; +import { IWorkspace } from '../workspace'; import { BasicContext } from './base-context'; -import { EditorWindow } from '../window'; +import { IEditorWindow } from '../window'; import { getWebviewPlugin } from '../inner-plugins/webview'; export class Context extends BasicContext { @@ -21,7 +21,7 @@ export class Context extends BasicContext { return this._activate; } - init = flow(function* (this: any) { + init = flow(function* (this: Context) { if (this.viewType === 'webview') { const url = yield this.instance?.url?.(); yield this.plugins.register(getWebviewPlugin(url, this.viewName)); @@ -33,7 +33,7 @@ export class Context extends BasicContext { this.isInit = true; }); - constructor(public workspace: InnerWorkspace, public editorWindow: EditorWindow, public editorView: IPublicTypeEditorView, options: Object | undefined) { + constructor(public workspace: IWorkspace, public editorWindow: IEditorWindow, public editorView: IPublicTypeEditorView, options: Object | undefined) { super(workspace, editorView.viewName, editorWindow); this.viewType = editorView.viewType || 'editor'; this.viewName = editorView.viewName; diff --git a/packages/workspace/src/index.ts b/packages/workspace/src/index.ts index 9442266bb..157219e9f 100644 --- a/packages/workspace/src/index.ts +++ b/packages/workspace/src/index.ts @@ -1,4 +1,4 @@ -export { Workspace } from './workspace'; +export { Workspace, IWorkspace } from './workspace'; export * from './window'; export * from './layouts/workbench'; -export { Resource } from './resource'; +export { Resource, IResource } from './resource'; diff --git a/packages/workspace/src/resource-type.ts b/packages/workspace/src/resource-type.ts index b52183068..28d54e56b 100644 --- a/packages/workspace/src/resource-type.ts +++ b/packages/workspace/src/resource-type.ts @@ -1,6 +1,14 @@ import { IPublicTypeResourceType } from '@alilc/lowcode-types'; -export class ResourceType { +export interface IResourceType extends Omit { + name: string; + + type: 'editor' | 'webview'; + + resourceTypeModel: IPublicTypeResourceType; +} + +export class ResourceType implements IResourceType { constructor(readonly resourceTypeModel: IPublicTypeResourceType) { } diff --git a/packages/workspace/src/resource.ts b/packages/workspace/src/resource.ts index ffb60ff6a..27b1fdcd1 100644 --- a/packages/workspace/src/resource.ts +++ b/packages/workspace/src/resource.ts @@ -1,13 +1,31 @@ -import { IPublicTypeEditorView, IPublicModelResource, IPublicResourceData, IPublicResourceTypeConfig } from '@alilc/lowcode-types'; +import { IPublicTypeEditorView, IPublicResourceData, IPublicResourceTypeConfig, IBaseModelResource } from '@alilc/lowcode-types'; import { Logger } from '@alilc/lowcode-utils'; -import { BasicContext } from './context/base-context'; -import { ResourceType } from './resource-type'; -import { Workspace as InnerWorkSpace } from './workspace'; +import { BasicContext, IBasicContext } from './context/base-context'; +import { ResourceType, IResourceType } from './resource-type'; +import { IWorkspace } from './workspace'; const logger = new Logger({ level: 'warn', bizName: 'workspace:resource' }); -export class Resource implements IPublicModelResource { - private context: BasicContext; +export interface IBaseResource extends IBaseModelResource { + readonly resourceType: ResourceType; + + get editorViews(): IPublicTypeEditorView[]; + + get defaultViewType(): string; + + getEditorView(name: string): IPublicTypeEditorView | undefined; + + import(schema: any): Promise; + + save(value: any): Promise; + + url(): Promise; +} + +export type IResource = IBaseResource; + +export class Resource implements IResource { + private context: IBasicContext; resourceTypeInstance: IPublicResourceTypeConfig; @@ -49,13 +67,15 @@ export class Resource implements IPublicModelResource { return this.context.innerSkeleton; } - get children(): Resource[] { + get children(): IResource[] { return this.resourceData?.children?.map(d => new Resource(d, this.resourceType, this.workspace)) || []; } - constructor(readonly resourceData: IPublicResourceData, readonly resourceType: ResourceType, readonly workspace: InnerWorkSpace) { + constructor(readonly resourceData: IPublicResourceData, readonly resourceType: IResourceType, readonly workspace: IWorkspace) { this.context = new BasicContext(workspace, `resource-${resourceData.resourceName || resourceType.name}`); - this.resourceTypeInstance = resourceType.resourceTypeModel(this.context, this.options); + this.resourceTypeInstance = resourceType.resourceTypeModel(this.context.innerPlugins._getLowCodePluginContext({ + pluginName: '', + }), this.options); this.init(); if (this.resourceTypeInstance.editorViews) { this.resourceTypeInstance.editorViews.forEach((d: any) => { diff --git a/packages/workspace/src/window.ts b/packages/workspace/src/window.ts index e7e08757f..1fa426524 100644 --- a/packages/workspace/src/window.ts +++ b/packages/workspace/src/window.ts @@ -1,9 +1,10 @@ import { uniqueId } from '@alilc/lowcode-utils'; import { createModuleEventBus, IEventBus, makeObservable, obx } from '@alilc/lowcode-editor-core'; import { Context } from './context/view-context'; -import { Workspace } from './workspace'; -import { Resource } from './resource'; +import { IWorkspace } from './workspace'; +import { IResource } from './resource'; import { IPublicTypeDisposable } from '../../types/es/shell/type/disposable'; +import { IPublicModelWindow } from '@alilc/lowcode-types'; interface IWindowCOnfig { title: string | undefined; @@ -11,7 +12,13 @@ interface IWindowCOnfig { viewType?: string | undefined; } -export class EditorWindow { +export interface IEditorWindow extends Omit, 'changeViewType'> { + readonly resource: IResource; + + changeViewType: (name: string, ignoreEmit?: boolean) => void; +} + +export class EditorWindow implements IEditorWindow { id: string = uniqueId('window'); icon: React.ReactElement | undefined; @@ -27,7 +34,7 @@ export class EditorWindow { @obx initReady = false; - constructor(readonly resource: Resource, readonly workspace: Workspace, private config: IWindowCOnfig) { + constructor(readonly resource: IResource, readonly workspace: IWorkspace, private config: IWindowCOnfig) { makeObservable(this); this.init(); this.title = config.title; diff --git a/packages/workspace/src/workspace.ts b/packages/workspace/src/workspace.ts index f7d49ed49..526e1f2ca 100644 --- a/packages/workspace/src/workspace.ts +++ b/packages/workspace/src/workspace.ts @@ -1,23 +1,33 @@ -import { Designer, LowCodePluginManager } from '@alilc/lowcode-designer'; +import { IDesigner, ILowCodePluginManager, LowCodePluginManager } from '@alilc/lowcode-designer'; import { createModuleEventBus, Editor, IEventBus, makeObservable, obx } from '@alilc/lowcode-editor-core'; -import { Plugins } from '@alilc/lowcode-shell'; -import { IPublicApiWorkspace, IPublicResourceList, IPublicTypeResourceType } from '@alilc/lowcode-types'; +import { IPublicApiPlugins, IPublicApiWorkspace, IPublicResourceList, IPublicTypeResourceType, IShellModelFactory } from '@alilc/lowcode-types'; import { BasicContext } from './context/base-context'; -import { EditorWindow } from './window'; -import { Resource } from './resource'; -import { ResourceType } from './resource-type'; +import { EditorWindow, IEditorWindow } from './window'; +import { IResource, Resource } from './resource'; +import { IResourceType, ResourceType } from './resource-type'; -enum event { - ChangeWindow = 'change_window', +enum EVENT { + CHANGE_WINDOW = 'change_window', - ChangeActiveWindow = 'change_active_window', + CHANGE_ACTIVE_WINDOW = 'change_active_window', } const CHANGE_EVENT = 'resource.list.change'; -interface IWorkspace extends Omit, 'resourceList'> {} +export interface IWorkspace extends Omit, 'resourceList' | 'plugins'> { + readonly registryInnerPlugin: (designer: IDesigner, editor: Editor, plugins: IPublicApiPlugins) => Promise; + + readonly shellModelFactory: IShellModelFactory; + + window: IEditorWindow; + + plugins: ILowCodePluginManager; + + getResourceList(): IResource[]; +} export class Workspace implements IWorkspace { context: BasicContext; @@ -28,7 +38,7 @@ export class Workspace implements IWorkspace { private resourceTypeMap: Map = new Map(); - private resourceList: Resource[] = []; + private resourceList: IResource[] = []; get skeleton() { return this.context.innerSkeleton; @@ -50,14 +60,14 @@ export class Workspace implements IWorkspace { return null; } - @obx.ref windows: EditorWindow[] = []; + @obx.ref windows: IEditorWindow[] = []; - editorWindowMap: Map = new Map(); + editorWindowMap: Map = new Map(); - @obx.ref window: EditorWindow; + @obx.ref window: IEditorWindow; constructor( - readonly registryInnerPlugin: (designer: Designer, editor: Editor, plugins: Plugins) => Promise, + readonly registryInnerPlugin: (designer: IDesigner, editor: Editor, plugins: IPublicApiPlugins) => Promise, readonly shellModelFactory: any, ) { this.init(); @@ -74,7 +84,10 @@ export class Workspace implements IWorkspace { return; } const title = this.defaultResourceType.name; - const resource = new Resource({}, this.defaultResourceType, this); + const resource = new Resource({ + resourceName: title, + options: {}, + }, this.defaultResourceType, this); this.window = new EditorWindow(resource, this, { title, }); @@ -113,7 +126,7 @@ export class Workspace implements IWorkspace { }; } - getResourceType(resourceName: string): ResourceType { + getResourceType(resourceName: string): IResourceType { return this.resourceTypeMap.get(resourceName)!; } @@ -139,7 +152,7 @@ export class Workspace implements IWorkspace { } removeEditorWindow(resourceName: string) { - const index = this.windows.findIndex(d => (d.resource.name === resourceName && d.title)); + const index = this.windows.findIndex(d => (d.resource?.name === resourceName && d.title)); this.remove(index); } @@ -157,7 +170,7 @@ export class Workspace implements IWorkspace { console.error(`${name} resourceType is not available`); return; } - const filterWindows = this.windows.filter(d => (d.resource.name === name && d.resource.title == title)); + const filterWindows = this.windows.filter(d => (d.resource?.name === name && d.resource.title == title)); if (filterWindows && filterWindows.length) { this.window = filterWindows[0]; this.emitChangeActiveWindow(); @@ -180,24 +193,24 @@ export class Workspace implements IWorkspace { } onChangeWindows(fn: () => void) { - this.emitter.on(event.ChangeWindow, fn); + this.emitter.on(EVENT.CHANGE_WINDOW, fn); return () => { - this.emitter.removeListener(event.ChangeWindow, fn); + this.emitter.removeListener(EVENT.CHANGE_WINDOW, fn); }; } emitChangeWindow() { - this.emitter.emit(event.ChangeWindow); + this.emitter.emit(EVENT.CHANGE_WINDOW); } emitChangeActiveWindow() { - this.emitter.emit(event.ChangeActiveWindow); + this.emitter.emit(EVENT.CHANGE_ACTIVE_WINDOW); } onChangeActiveWindow(fn: () => void) { - this.emitter.on(event.ChangeActiveWindow, fn); + this.emitter.on(EVENT.CHANGE_ACTIVE_WINDOW, fn); return () => { - this.emitter.removeListener(event.ChangeActiveWindow, fn); + this.emitter.removeListener(EVENT.CHANGE_ACTIVE_WINDOW, fn); }; } }