diff --git a/packages/designer/src/builtin-simulator/host.ts b/packages/designer/src/builtin-simulator/host.ts index 1eb228f29..6415a1b4c 100644 --- a/packages/designer/src/builtin-simulator/host.ts +++ b/packages/designer/src/builtin-simulator/host.ts @@ -67,7 +67,7 @@ import { BuiltinSimulatorRenderer } from './renderer'; import { clipboard } from '../designer/clipboard'; import { LiveEditing } from './live-editing/live-editing'; import { Project } from '../project'; -import { Scroller } from '../designer/scroller'; +import { IScroller } from '../designer/scroller'; import { isElementNode, isDOMNodeVisible } from '../utils/misc'; import { debounce } from 'lodash'; @@ -170,7 +170,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost 0) { @@ -576,7 +576,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost detecting.leave(this.project.currentDocument); + const leave = () => { + this.project.currentDocument && detecting.leave(this.project.currentDocument) + }; doc.addEventListener('mouseover', hover, true); doc.addEventListener('mouseleave', leave, false); @@ -912,8 +916,11 @@ export class BuiltinSimulatorHost implements ISimulatorHost | null { + getNodeInstanceFromElement(target: Element | null): IPublicTypeNodeInstance | null { if (!target) { return null; } @@ -1215,7 +1222,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost node.isLocked); + const lockedNode = getClosestNode(dropContainer?.container, (node) => node.isLocked); if (lockedNode) return null; if ( !dropContainer @@ -1257,7 +1264,8 @@ export class BuiltinSimulatorHost implements ISimulatorHost | undefined; + let container: INode | null; + let nodeInstance: IPublicTypeNodeInstance | undefined; if (target) { const ref = this.getNodeInstanceFromElement(target); @@ -1391,8 +1399,8 @@ export class BuiltinSimulatorHost implements ISimulatorHost(); + const drillDownExcludes = new Set(); if (isDragNodeObject(dragObject)) { const { nodes } = dragObject; let i = nodes.length; @@ -1414,7 +1422,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost, + drillDownExcludes: Set, e: ILocateEvent, ) { const { children } = container; @@ -1519,7 +1527,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost; } export function isSimulatorRenderer(obj: any): obj is BuiltinSimulatorRenderer { diff --git a/packages/designer/src/builtin-simulator/utils/clickable.ts b/packages/designer/src/builtin-simulator/utils/clickable.ts index d1646254d..5413ad5c5 100644 --- a/packages/designer/src/builtin-simulator/utils/clickable.ts +++ b/packages/designer/src/builtin-simulator/utils/clickable.ts @@ -1,5 +1,5 @@ import { getClosestNode, canClickNode } from '@alilc/lowcode-utils'; -import { Node } from '../../document'; +import { INode } from '../../document'; /** * 获取离当前节点最近的可点击节点 @@ -7,7 +7,7 @@ import { Node } from '../../document'; * @param event */ export const getClosestClickableNode = ( - currentNode: Node | undefined | null, + currentNode: INode | undefined | null, event: MouseEvent, ) => { let node = currentNode; diff --git a/packages/designer/src/component-meta.ts b/packages/designer/src/component-meta.ts index 2691a8971..80f99c05b 100644 --- a/packages/designer/src/component-meta.ts +++ b/packages/designer/src/component-meta.ts @@ -58,6 +58,10 @@ export function buildFilter(rule?: string | string[] | RegExp | IPublicTypeNesti export interface IComponentMeta extends IPublicModelComponentMeta { prototype?: any; + + setMetadata(metadata: IPublicTypeComponentMetadata): void; + + get rootSelector(): string | undefined; } export class ComponentMeta implements IComponentMeta { @@ -332,7 +336,7 @@ export class ComponentMeta implements IComponentMeta { if (this.parentWhitelist) { return this.parentWhitelist( parent.internalToShellNode(), - isNode(my) ? my.internalToShellNode() : my, + isNode(my) ? my.internalToShellNode() : my, ); } return true; @@ -343,7 +347,7 @@ export class ComponentMeta implements IComponentMeta { if (this.childWhitelist) { const _target: any = !Array.isArray(target) ? [target] : target; return _target.every((item: Node | IPublicTypeNodeSchema) => { - const _item = !isNode(item) ? new Node(my.document, item) : item; + const _item = !isNode(item) ? new Node(my.document, item) : item; return ( this.childWhitelist && this.childWhitelist(_item.internalToShellNode(), my.internalToShellNode()) diff --git a/packages/designer/src/designer/designer.ts b/packages/designer/src/designer/designer.ts index 3e2ff6dd2..c26d9fb4b 100644 --- a/packages/designer/src/designer/designer.ts +++ b/packages/designer/src/designer/designer.ts @@ -18,6 +18,7 @@ import { IPublicEnumTransformStage, IPublicModelDragon, IPublicModelDropLocation, + IPublicModelLocateEvent, } from '@alilc/lowcode-types'; import { megreAssets, IPublicTypeAssetsJson, isNodeSchema, isDragNodeObject, isDragNodeDataObject, isLocationChildrenDetail, Logger } from '@alilc/lowcode-utils'; import { Project } from '../project'; @@ -45,15 +46,15 @@ export interface DesignerProps { defaultSchema?: IPublicTypeProjectSchema; hotkeys?: object; viewName?: string; - simulatorProps?: object | ((document: DocumentModel) => object); + simulatorProps?: Record | ((document: DocumentModel) => object); simulatorComponent?: ComponentType; dragGhostComponent?: ComponentType; suspensed?: boolean; componentMetadatas?: IPublicTypeComponentMetadata[]; globalComponentActions?: IPublicTypeComponentAction[]; onMount?: (designer: Designer) => void; - onDragstart?: (e: ILocateEvent) => void; - onDrag?: (e: ILocateEvent) => void; + onDragstart?: (e: IPublicModelLocateEvent) => void; + onDrag?: (e: IPublicModelLocateEvent) => void; onDragend?: ( e: { dragObject: IPublicModelDragObject; copy: boolean }, loc?: DropLocation, @@ -73,12 +74,14 @@ export interface IDesigner { get detecting(): Detecting; + get simulatorComponent(): ComponentType | undefined; + createScroller(scrollable: IPublicTypeScrollable): IPublicModelScroller; /** * 创建插入位置,考虑放到 dragon 中 */ - createLocation(locationData: IPublicTypeLocationData): IPublicModelDropLocation; + createLocation(locationData: IPublicTypeLocationData): DropLocation; get componentsMap(): { [key: string]: IPublicTypeNpmInfo | Component }; @@ -100,6 +103,8 @@ export interface IDesigner { transformProps(props: IPublicTypeCompositeObject | IPublicTypePropsList, node: Node, stage: IPublicEnumTransformStage): IPublicTypeCompositeObject | IPublicTypePropsList; createSettingEntry(nodes: INode[]): ISettingTopEntry; + + autorun(effect: (reaction: IReactionPublic) => void, options?: IReactionOptions): IReactionDisposer; } export class Designer implements IDesigner { @@ -196,7 +201,7 @@ export class Designer implements IDesigner { const loc = this._dropLocation; if (loc) { if (isLocationChildrenDetail(loc.detail) && loc.detail.valid !== false) { - let nodes: Node[] | undefined; + let nodes: INode[] | undefined; if (isDragNodeObject(dragObject)) { nodes = insertChildren(loc.target, [...dragObject.nodes], loc.detail.index, copy); } else if (isDragNodeDataObject(dragObject)) { @@ -209,7 +214,7 @@ export class Designer implements IDesigner { nodes = insertChildren(loc.target, nodeData, loc.detail.index); } if (nodes) { - loc.document.selection.selectAll(nodes.map((o) => o.id)); + loc.document?.selection.selectAll(nodes.map((o) => o.id)); setTimeout(() => this.activeTracker.track(nodes![0]), 10); } } @@ -222,7 +227,7 @@ export class Designer implements IDesigner { }); this.activeTracker.onChange(({ node, detail }) => { - node.document.simulator?.scrollToNode(node, detail); + node.document?.simulator?.scrollToNode(node, detail); }); let historyDispose: undefined | (() => void); @@ -264,8 +269,8 @@ export class Designer implements IDesigner { currentSelection.selected.length === 0 && this.simulatorProps?.designMode === 'live' ) { - const rootNodeChildrens = this.currentDocument.getRoot().getChildren().children; - if (rootNodeChildrens.length > 0) { + const rootNodeChildrens = this.currentDocument?.getRoot()?.getChildren()?.children; + if (rootNodeChildrens && rootNodeChildrens.length > 0) { currentSelection.select(rootNodeChildrens[0].id); } } @@ -288,14 +293,16 @@ export class Designer implements IDesigner { /** * 创建插入位置,考虑放到 dragon 中 */ - createLocation(locationData: IPublicTypeLocationData): DropLocation { + createLocation(locationData: IPublicTypeLocationData): DropLocation { const loc = new DropLocation(locationData); - if (this._dropLocation && this._dropLocation.document !== loc.document) { + if (this._dropLocation && this._dropLocation.document && this._dropLocation.document !== loc.document) { this._dropLocation.document.dropLocation = null; } this._dropLocation = loc; this.postEvent('dropLocation.change', loc); - loc.document.dropLocation = loc; + if (loc.document) { + loc.document.dropLocation = loc; + } this.activeTracker.track({ node: loc.target, detail: loc.detail }); return loc; } @@ -304,7 +311,7 @@ export class Designer implements IDesigner { * 清除插入位置 */ clearLocation() { - if (this._dropLocation) { + if (this._dropLocation && this._dropLocation.document) { this._dropLocation.document.dropLocation = null; } this.postEvent('dropLocation.change', undefined); @@ -376,7 +383,7 @@ export class Designer implements IDesigner { } else { // FIXME!!, parent maybe null target = refNode.parent!; - index = refNode.index + 1; + index = (refNode.index || 0) + 1; } if (target && insertNode && !target.componentMeta.checkNestingDown(target, insertNode)) { @@ -467,7 +474,7 @@ export class Designer implements IDesigner { return this._simulatorComponent; } - @computed get simulatorProps(): object { + @computed get simulatorProps(): Record { if (typeof this._simulatorProps === 'function') { return this._simulatorProps(this.project); } @@ -622,7 +629,7 @@ export class Designer implements IDesigner { } } - autorun(effect: (reaction: IReactionPublic) => void, options?: IReactionOptions): IReactionDisposer { + autorun(effect: (reaction: IReactionPublic) => void, options?: IReactionOptions): IReactionDisposer { return autorun(effect, options); } diff --git a/packages/designer/src/designer/dragon.ts b/packages/designer/src/designer/dragon.ts index 29a67a9ab..2fc0ca3e5 100644 --- a/packages/designer/src/designer/dragon.ts +++ b/packages/designer/src/designer/dragon.ts @@ -23,7 +23,6 @@ export interface ILocateEvent extends IPublicModelLocateEvent { * 激活的感应器 */ sensor?: IPublicModelSensor; - } /** @@ -97,7 +96,7 @@ function isDragEvent(e: any): e is DragEvent { } export interface IDragon extends IPublicModelDragon { - + emitter: IEventBus; } /** @@ -106,6 +105,8 @@ export interface IDragon extends IPublicModelDragon { export class Dragon implements IDragon { private sensors: IPublicModelSensor[] = []; + private nodeInstPointerEvents: boolean; + key = Math.random(); /** @@ -127,7 +128,7 @@ export class Dragon implements IDragon { viewName: string | undefined; - private emitter: IEventBus = createModuleEventBus('Dragon'); + emitter: IEventBus = createModuleEventBus('Dragon'); constructor(readonly designer: Designer) { makeObservable(this); @@ -356,8 +357,8 @@ export class Dragon implements IDragon { rglNode, node: tarNode, }); - const { selection } = designer.project.currentDocument; - selection.select(tarNode.id); + const selection = designer.project.currentDocument?.selection; + selection?.select(tarNode.id); } } } diff --git a/packages/designer/src/designer/location.ts b/packages/designer/src/designer/location.ts index ccf26e325..00ee4681c 100644 --- a/packages/designer/src/designer/location.ts +++ b/packages/designer/src/designer/location.ts @@ -122,7 +122,7 @@ export class DropLocation implements IDropLocation { return this.target.document; } - constructor({ target, detail, source, event }: IPublicTypeLocationData) { + constructor({ target, detail, source, event }: IPublicTypeLocationData) { this.target = target; this.detail = detail; this.source = source; diff --git a/packages/designer/src/designer/setting/setting-entry.ts b/packages/designer/src/designer/setting/setting-entry.ts index 39f978a70..9b0d4846a 100644 --- a/packages/designer/src/designer/setting/setting-entry.ts +++ b/packages/designer/src/designer/setting/setting-entry.ts @@ -1,17 +1,26 @@ -import { IPublicModelSettingTarget } from '@alilc/lowcode-types'; +import { IBaseModelSettingEntry, IPublicModelSettingPropEntry, IPublicTypeSetValueOptions } from '@alilc/lowcode-types'; import { IComponentMeta } from '../../component-meta'; -import { Designer } from '../designer'; +import { IDesigner } from '../designer'; import { INode } from '../../document'; -export interface ISettingEntry extends IPublicModelSettingTarget { - readonly nodes: INode[]; - readonly componentMeta: IComponentMeta | null; - readonly designer: Designer; +export interface ISettingEntry extends IBaseModelSettingEntry< + INode, + IComponentMeta, + ISettingEntry +> { + readonly designer: IDesigner; - // 顶端 - readonly top: ISettingEntry; - // 父级 - readonly parent: ISettingEntry; + readonly isGroup: boolean; - get: (propName: string | number) => ISettingEntry | null; + readonly id: string; + + get name(): string | number | undefined; + + internalToShellPropEntry(): IPublicModelSettingPropEntry; + + valueChange(options: IPublicTypeSetValueOptions): void; + + get valueState(): number; + + clearValue(): void; } diff --git a/packages/designer/src/designer/setting/setting-field.ts b/packages/designer/src/designer/setting/setting-field.ts index c073e2854..da374f9bb 100644 --- a/packages/designer/src/designer/setting/setting-field.ts +++ b/packages/designer/src/designer/setting/setting-field.ts @@ -1,3 +1,4 @@ +import { ReactNode } from 'react'; import { IPublicTypeTitleContent, IPublicTypeSetterType, @@ -25,8 +26,29 @@ function getSettingFieldCollectorKey(parent: ISettingEntry, config: IPublicTypeF return path.join('.'); } -export interface ISettingField extends ISettingEntry { +export interface ISettingField extends Omit { + get items(): Array; + get title(): string | ReactNode | undefined; + + purge(): void; + + extraProps: IPublicTypeFieldExtraProps; + + get setter(): IPublicTypeSetterType | null; + + get expanded(): boolean; + + readonly isRequired: boolean; + + setExpanded(value: boolean): void; + + setValue( + val: any, + isHotValue?: boolean, + force?: boolean, + extraOptions?: IPublicTypeSetValueOptions, + ): void; } export class SettingField extends SettingPropEntry implements ISettingField { @@ -57,12 +79,12 @@ export class SettingField extends SettingPropEntry implements ISettingField { @obx.ref private _expanded = true; - private _items: Array = []; + private _items: Array = []; constructor( parent: ISettingEntry, config: IPublicTypeFieldConfig, - private settingFieldCollector?: (name: string | number, field: SettingField) => void, + private settingFieldCollector?: (name: string | number, field: ISettingField) => void, ) { super(parent, config.name, config.type); makeObservable(this); @@ -97,7 +119,7 @@ export class SettingField extends SettingPropEntry implements ISettingField { if (isDynamicSetter(this._setter)) { return untracked(() => { const shellThis = this.internalToShellPropEntry(); - return this._setter.call(shellThis, shellThis); + return (this._setter as IPublicTypeDynamicSetter)?.call(shellThis, shellThis); }); } return this._setter; @@ -111,7 +133,7 @@ export class SettingField extends SettingPropEntry implements ISettingField { this._expanded = value; } - get items(): Array { + get items(): Array { return this._items; } @@ -122,8 +144,8 @@ export class SettingField extends SettingPropEntry implements ISettingField { private initItems( items: Array, settingFieldCollector?: { - (name: string | number, field: SettingField): void; - (name: string, field: SettingField): void; + (name: string | number, field: ISettingField): void; + (name: string, field: ISettingField): void; }, ) { this._items = items.map((item) => { @@ -140,7 +162,7 @@ export class SettingField extends SettingPropEntry implements ISettingField { } // 创建子配置项,通常用于 object/array 类型数据 - createField(config: IPublicTypeFieldConfig): SettingField { + createField(config: IPublicTypeFieldConfig): ISettingField { this.settingFieldCollector?.(getSettingFieldCollectorKey(this.parent, config), this); return new SettingField(this, config, this.settingFieldCollector); } @@ -161,8 +183,8 @@ export class SettingField extends SettingPropEntry implements ISettingField { } getItems( - filter?: (item: SettingField | IPublicTypeCustomView) => boolean, - ): Array { + filter?: (item: ISettingField | IPublicTypeCustomView) => boolean, + ): Array { return this._items.filter((item) => { if (filter) { return filter(item); @@ -252,6 +274,6 @@ export class SettingField extends SettingPropEntry implements ISettingField { /** * @deprecated use same function from '@alilc/lowcode-utils' instead */ -export function isSettingField(obj: any): obj is SettingField { +export function isSettingField(obj: any): obj is ISettingField { return obj && obj.isSettingField; } diff --git a/packages/designer/src/designer/setting/setting-prop-entry.ts b/packages/designer/src/designer/setting/setting-prop-entry.ts index ed20964ba..392301b7d 100644 --- a/packages/designer/src/designer/setting/setting-prop-entry.ts +++ b/packages/designer/src/designer/setting/setting-prop-entry.ts @@ -1,11 +1,10 @@ import { obx, computed, makeObservable, runInAction, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core'; -import { GlobalEvent, IPublicModelEditor, IPublicTypeSetValueOptions } from '@alilc/lowcode-types'; +import { GlobalEvent, IPublicApiSetters, IPublicModelEditor, IPublicTypeSetValueOptions } from '@alilc/lowcode-types'; import { uniqueId, isJSExpression, isSettingField } from '@alilc/lowcode-utils'; -import { Setters } from '@alilc/lowcode-shell'; import { ISettingEntry } from './setting-entry'; import { INode } from '../../document'; import { IComponentMeta } from '../../component-meta'; -import { Designer } from '../designer'; +import { IDesigner } from '../designer'; import { ISettingField } from './setting-field'; export class SettingPropEntry implements ISettingEntry { @@ -18,13 +17,13 @@ export class SettingPropEntry implements ISettingEntry { readonly isSingle: boolean; - readonly setters: Setters; + readonly setters: IPublicApiSetters; readonly nodes: INode[]; readonly componentMeta: IComponentMeta | null; - readonly designer: Designer; + readonly designer: IDesigner; readonly top: ISettingEntry; @@ -37,7 +36,7 @@ export class SettingPropEntry implements ISettingEntry { readonly emitter: IEventBus = createModuleEventBus('SettingPropEntry'); // ==== dynamic properties ==== - @obx.ref private _name: string | number; + @obx.ref private _name: string | number | undefined; get name() { return this._name; @@ -45,7 +44,7 @@ export class SettingPropEntry implements ISettingEntry { @computed get path() { const path = this.parent.path.slice(); - if (this.type === 'field') { + if (this.type === 'field' && this.name) { path.push(this.name); } return path; @@ -53,7 +52,7 @@ export class SettingPropEntry implements ISettingEntry { extraProps: any = {}; - constructor(readonly parent: ISettingEntry | ISettingField, name: string | number, type?: 'field' | 'group') { + constructor(readonly parent: ISettingEntry | ISettingField, name: string | number | undefined, type?: 'field' | 'group') { makeObservable(this); if (type == null) { const c = typeof name === 'string' ? name.slice(0, 1) : ''; @@ -161,7 +160,7 @@ export class SettingPropEntry implements ISettingEntry { */ getValue(): any { let val: any; - if (this.type === 'field') { + if (this.type === 'field' && this.name) { val = this.parent.getPropValue(this.name); } const { getValue } = this.extraProps; @@ -179,7 +178,7 @@ export class SettingPropEntry implements ISettingEntry { setValue(val: any, isHotValue?: boolean, force?: boolean, extraOptions?: IPublicTypeSetValueOptions) { const oldValue = this.getValue(); if (this.type === 'field') { - this.parent.setPropValue(this.name, val); + this.name && this.parent.setPropValue(this.name, val); } const { setValue } = this.extraProps; @@ -203,7 +202,7 @@ export class SettingPropEntry implements ISettingEntry { */ clearValue() { if (this.type === 'field') { - this.parent.clearPropValue(this.name); + this.name && this.parent.clearPropValue(this.name); } const { setValue } = this.extraProps; if (setValue) { diff --git a/packages/designer/src/document/document-model.ts b/packages/designer/src/document/document-model.ts index 89856d2eb..e44e21d35 100644 --- a/packages/designer/src/document/document-model.ts +++ b/packages/designer/src/document/document-model.ts @@ -39,7 +39,7 @@ import { IProject, Project } from '../project'; import { ISimulatorHost } from '../simulator'; import { IComponentMeta } from '../component-meta'; import { IDesigner, IHistory } from '../designer'; -import { insertChildren, insertChild, RootNode, INode } from './node/node'; +import { insertChildren, insertChild, IRootNode, INode } from './node/node'; import { Selection, ISelection } from './selection'; import { History } from './history'; import { IModalNodesManager, ModalNodesManager, Node } from './node'; @@ -56,7 +56,7 @@ export type GetDataType = T extends undefined export interface IDocumentModel extends Omit< IPublicModelDocumentModel< ISelection, IHistory, - INode | RootNode, + INode | IRootNode, IDropLocation, IModalNodesManager, IProject @@ -89,11 +89,26 @@ export interface IDocumentModel extends Omit< IPublicModelDocumentModel< get nodesMap(): Map; + /** + * 是否为非激活状态 + */ + get suspensed(): boolean; + + get fileName(): string; + + get currentRoot(): INode | null; + + selection: ISelection; + + isBlank(): boolean; + /** * 根据 id 获取节点 */ getNode(id: string): INode | null; + getRoot(): INode | null; + getHistory(): IHistory; checkNesting( @@ -122,13 +137,21 @@ export interface IDocumentModel extends Omit< IPublicModelDocumentModel< getComponentMeta(componentName: string): IComponentMeta; insertNodes(parent: INode, thing: INode[] | IPublicTypeNodeData[], at?: number | null, copy?: boolean): INode[]; + + open(): DocumentModel; + + remove(): void; + + suspense(): void; + + close(): void; } export class DocumentModel implements IDocumentModel { /** * 根节点 类型有:Page/Component/Block */ - rootNode: INode | null; + rootNode: IRootNode | null; /** * 文档编号 @@ -280,7 +303,7 @@ export class DocumentModel implements IDocumentModel { return this.rootNode; } - constructor(project: Project, schema?: IPublicTypeRootSchema) { + constructor(project: IProject, schema?: IPublicTypeRootSchema) { makeObservable(this); this.project = project; this.designer = this.project?.designer; @@ -346,7 +369,7 @@ export class DocumentModel implements IDocumentModel { } isBlank() { - return this._blank && !this.isModified(); + return !!(this._blank && !this.isModified()); } /** @@ -552,7 +575,7 @@ export class DocumentModel implements IDocumentModel { /** * 是否已修改 */ - isModified() { + isModified(): boolean { return this.history.isSavePoint(); } @@ -641,7 +664,7 @@ export class DocumentModel implements IDocumentModel { items = Array.isArray(dragObject.data) ? dragObject.data : [dragObject.data]; } else if (isDragNodeObject(dragObject)) { items = dragObject.nodes; - } else if (isNode(dragObject) || isNodeSchema(dragObject)) { + } else if (isNode(dragObject) || isNodeSchema(dragObject)) { items = [dragObject]; } else { console.warn('the dragObject is not in the correct type, dragObject:', dragObject); @@ -760,7 +783,7 @@ export class DocumentModel implements IDocumentModel { /* istanbul ignore next */ acceptRootNodeVisitor( visitorName = 'default', - visitorFn: (node: RootNode) => any, + visitorFn: (node: IRootNode) => any, ) { let visitorResult = {}; if (!visitorName) { @@ -768,8 +791,10 @@ export class DocumentModel implements IDocumentModel { console.warn('Invalid or empty RootNodeVisitor name.'); } try { - visitorResult = visitorFn.call(this, this.rootNode); - this.rootNodeVisitorMap[visitorName] = visitorResult; + if (this.rootNode) { + visitorResult = visitorFn.call(this, this.rootNode); + this.rootNodeVisitorMap[visitorName] = visitorResult; + } } catch (e) { console.error('RootNodeVisitor is not valid.'); console.error(e); @@ -864,7 +889,7 @@ export class DocumentModel implements IDocumentModel { console.warn('onRefresh method is deprecated'); } - onReady(fn: Function) { + onReady(fn: (...args: any[]) => void) { this.designer.editor.eventBus.on('document-open', fn); return () => { this.designer.editor.eventBus.off('document-open', fn); @@ -876,7 +901,7 @@ export class DocumentModel implements IDocumentModel { } } -export function isDocumentModel(obj: any): obj is DocumentModel { +export function isDocumentModel(obj: any): obj is IDocumentModel { return obj && obj.rootNode; } diff --git a/packages/designer/src/document/document-view.tsx b/packages/designer/src/document/document-view.tsx index a9641069a..c6dbe76a8 100644 --- a/packages/designer/src/document/document-view.tsx +++ b/packages/designer/src/document/document-view.tsx @@ -1,11 +1,11 @@ import { Component } from 'react'; import classNames from 'classnames'; import { observer } from '@alilc/lowcode-editor-core'; -import { DocumentModel } from './document-model'; +import { DocumentModel, IDocumentModel } from './document-model'; import { BuiltinSimulatorHostView } from '../builtin-simulator'; @observer -export class DocumentView extends Component<{ document: DocumentModel }> { +export class DocumentView extends Component<{ document: IDocumentModel }> { render() { const { document } = this.props; const { simulatorProps } = document; @@ -26,7 +26,7 @@ export class DocumentView extends Component<{ document: DocumentModel }> { } } -class DocumentInfoView extends Component<{ document: DocumentModel }> { +class DocumentInfoView extends Component<{ document: IDocumentModel }> { render() { return null; } diff --git a/packages/designer/src/document/history.ts b/packages/designer/src/document/history.ts index 5de6ca78a..d190a9a9c 100644 --- a/packages/designer/src/document/history.ts +++ b/packages/designer/src/document/history.ts @@ -1,5 +1,5 @@ import { reaction, untracked, globalContext, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core'; -import { IPublicTypeNodeSchema, IPublicModelHistory } from '@alilc/lowcode-types'; +import { IPublicTypeNodeSchema, IPublicModelHistory, IPublicTypeDisposable } from '@alilc/lowcode-types'; import { Logger } from '@alilc/lowcode-utils'; const logger = new Logger({ level: 'warn', bizName: 'history' }); @@ -10,7 +10,7 @@ export interface Serialization { } export interface IHistory extends IPublicModelHistory { - + onStateChange(func: () => any): IPublicTypeDisposable; } export class History implements IHistory { @@ -189,11 +189,11 @@ export class History implements IHistory { * @param func * @returns */ - onChangeState(func: () => any): () => void { + onChangeState(func: () => any): IPublicTypeDisposable { return this.onStateChange(func); } - onStateChange(func: () => any): () => void { + onStateChange(func: () => any): IPublicTypeDisposable { this.emitter.on('statechange', func); return () => { this.emitter.removeListener('statechange', func); @@ -205,7 +205,7 @@ export class History implements IHistory { * @param func * @returns */ - onChangeCursor(func: () => any): () => void { + onChangeCursor(func: () => any): IPublicTypeDisposable { return this.onCursor(func); } diff --git a/packages/designer/src/document/node/exclusive-group.ts b/packages/designer/src/document/node/exclusive-group.ts index 8cf993095..d8c14cedb 100644 --- a/packages/designer/src/document/node/exclusive-group.ts +++ b/packages/designer/src/document/node/exclusive-group.ts @@ -7,11 +7,17 @@ import { intl } from '../../locale'; export interface IExclusiveGroup extends IPublicModelExclusiveGroup { readonly name: string; + get index(): number | undefined; + remove(node: INode): void; add(node: INode): void; isVisible(node: INode): boolean; + + get length(): number; + + get visibleNode(): INode; } // modals assoc x-hide value, initial: check is Modal, yes will put it in modals, cross levels diff --git a/packages/designer/src/document/node/node-children.ts b/packages/designer/src/document/node/node-children.ts index 51e921a93..1b6df5866 100644 --- a/packages/designer/src/document/node/node-children.ts +++ b/packages/designer/src/document/node/node-children.ts @@ -20,6 +20,8 @@ export interface INodeChildren extends Omit, get length(): number; + children: INode[]; + unlinkChild(node: INode): void; /** @@ -65,7 +67,7 @@ export interface INodeChildren extends Omit, /** overriding methods end */ } export class NodeChildren implements INodeChildren { - @obx.shallow private children: INode[]; + @obx.shallow children: INode[]; private emitter: IEventBus = createModuleEventBus('NodeChildren'); diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts index 77f5bddd4..691c22844 100644 --- a/packages/designer/src/document/node/node.ts +++ b/packages/designer/src/document/node/node.ts @@ -37,9 +37,9 @@ export interface NodeStatus { inPlaceEditing: boolean; } -export interface INode extends Omit extends Omit; -export type SlotNode = Node; -export type PageNode = Node; -export type ComponentNode = Node; -export type RootNode = PageNode | ComponentNode; +export type ISlotNode = IBaseNode; +export type IPageNode = IBaseNode; +export type IComponentNode = IBaseNode; +export type IRootNode = IPageNode | IComponentNode; +export type INode = IPageNode | ISlotNode | IComponentNode | IRootNode; -export function isRootNode(node: INode): node is INode { +export function isRootNode(node: INode): node is IRootNode { return node && node.isRootNode; } -export function isLowCodeComponent(node: INode): node is INode { +export function isLowCodeComponent(node: INode): node is IComponentNode { return node.componentMeta?.getMetadata().devMode === 'lowCode'; } @@ -1446,7 +1453,7 @@ export function insertChild( at?: number | null, copy?: boolean, ): INode | null { - let node: INode | null | RootNode | undefined; + let node: INode | null | IRootNode | undefined; let nodeSchema: IPublicTypeNodeSchema; if (isNode(thing) && (copy || thing.isSlot())) { nodeSchema = thing.export(IPublicEnumTransformStage.Clone); diff --git a/packages/designer/src/document/node/props/prop.ts b/packages/designer/src/document/node/props/prop.ts index bb6797d45..a679c28c8 100644 --- a/packages/designer/src/document/node/props/prop.ts +++ b/packages/designer/src/document/node/props/prop.ts @@ -1,9 +1,9 @@ import { untracked, computed, obx, engineConfig, action, makeObservable, mobx, runInAction } from '@alilc/lowcode-editor-core'; import { IPublicTypeCompositeValue, GlobalEvent, IPublicTypeJSSlot, IPublicTypeSlotSchema, IPublicEnumTransformStage, IPublicModelProp } from '@alilc/lowcode-types'; -import { uniqueId, isPlainObject, hasOwnProperty, compatStage, isJSExpression, isJSSlot } from '@alilc/lowcode-utils'; +import { uniqueId, isPlainObject, hasOwnProperty, compatStage, isJSExpression, isJSSlot, isNodeSchema } from '@alilc/lowcode-utils'; import { valueToSource } from './value-to-source'; import { IProps, IPropParent } from './props'; -import { SlotNode, INode } from '../node'; +import { ISlotNode, INode } from '../node'; // import { TransformStage } from '../transform-stage'; const { set: mobxSet, isObservableArray } = mobx; @@ -30,6 +30,12 @@ export interface IProp extends Omit(slotSchema); + this._slotNode = owner.document.createNode(slotSchema); if (this._slotNode) { owner.addSlot(this._slotNode); this._slotNode.internalSetSlotFor(this); diff --git a/packages/designer/src/document/selection.ts b/packages/designer/src/document/selection.ts index 2456de759..93ec04ffe 100644 --- a/packages/designer/src/document/selection.ts +++ b/packages/designer/src/document/selection.ts @@ -4,7 +4,7 @@ import { DocumentModel } from './document-model'; import { IPublicModelSelection } from '@alilc/lowcode-types'; export interface ISelection extends Omit, 'node'> { - + containsNode(node: INode, excludeRoot: boolean): boolean; } export class Selection implements ISelection { diff --git a/packages/designer/src/project/project.ts b/packages/designer/src/project/project.ts index 6516d67aa..55ac584fb 100644 --- a/packages/designer/src/project/project.ts +++ b/packages/designer/src/project/project.ts @@ -12,7 +12,9 @@ import { import { isLowCodeComponentType, isProCodeComponentType } from '@alilc/lowcode-utils'; import { ISimulatorHost } from '../simulator'; -export interface IProject extends Omit< IPublicApiProject, +export interface IProject extends Omit< IPublicApiProject< + IDocumentModel +>, 'simulatorHost' | 'importSchema' | 'exportSchema' | @@ -49,7 +51,7 @@ export interface IProject extends Omit< IPublicApiProject, load(schema?: IPublicTypeProjectSchema, autoOpen?: boolean | string): void; getSchema( - stage: IPublicEnumTransformStage, + stage?: IPublicEnumTransformStage, ): IPublicTypeProjectSchema; getDocument(id: string): IDocumentModel | null; @@ -134,10 +136,10 @@ export class Project implements IProject { } private getComponentsMap(): IPublicTypeComponentsMap { - return this.documents.reduce(( + return this.documents.reduce(( componentsMap: IPublicTypeComponentsMap, - curDoc: DocumentModel, - ) => { + curDoc: IDocumentModel, + ): IPublicTypeComponentsMap => { const curComponentsMap = curDoc.getComponentsMap(); if (Array.isArray(curComponentsMap)) { curComponentsMap.forEach((item) => { @@ -176,7 +178,7 @@ export class Project implements IProject { componentsMap: this.getComponentsMap(), componentsTree: this.documents .filter((doc) => !doc.isBlank()) - .map((doc) => doc.export(stage)), + .map((doc) => doc.export(stage) || {} as IPublicTypeRootSchema), i18n: this.i18n, }; } @@ -188,7 +190,7 @@ export class Project implements IProject { setSchema(schema?: IPublicTypeProjectSchema) { // FIXME: 这里的行为和 getSchema 并不对等,感觉不太对 const doc = this.documents.find((doc) => doc.active); - doc && doc.import(schema?.componentsTree[0]); + doc && schema?.componentsTree[0] && doc.import(schema?.componentsTree[0]); this.simulator?.rerender(); } @@ -244,7 +246,7 @@ export class Project implements IProject { } } - removeDocument(doc: IPublicModelDocumentModel) { + removeDocument(doc: IDocumentModel) { const index = this.documents.indexOf(doc); if (index < 0) { return; diff --git a/packages/designer/src/simulator.ts b/packages/designer/src/simulator.ts index 32b9233c9..99586fb81 100644 --- a/packages/designer/src/simulator.ts +++ b/packages/designer/src/simulator.ts @@ -1,5 +1,5 @@ import { ComponentType } from 'react'; -import { IPublicTypeComponentMetadata, IPublicTypeNodeSchema, IPublicTypeScrollable, IPublicTypeComponentInstance, IPublicModelSensor, IPublicTypeNodeInstance } from '@alilc/lowcode-types'; +import { IPublicTypeComponentMetadata, IPublicTypeNodeSchema, IPublicTypeScrollable, IPublicTypeComponentInstance, IPublicModelSensor, IPublicTypeNodeInstance, IPublicTypePackage } from '@alilc/lowcode-types'; import { Point, ScrollTarget, ILocateEvent } from './designer'; import { BuiltinSimulatorRenderer } from './builtin-simulator/renderer'; import { INode } from './document'; @@ -78,7 +78,7 @@ export interface DropContainer { /** * 模拟器控制进程协议 */ -export interface ISimulatorHost

extends IPublicModelSensor { +export interface ISimulatorHost

extends IPublicModelSensor { readonly isSimulator: true; /** @@ -177,6 +177,8 @@ export interface ISimulatorHost

extends IPublicModelSensor { * 销毁 */ purge(): void; + + setupComponents(library: IPublicTypePackage[]): Promise; } export function isSimulatorHost(obj: any): obj is ISimulatorHost { diff --git a/packages/editor-skeleton/src/components/settings/settings-pane.tsx b/packages/editor-skeleton/src/components/settings/settings-pane.tsx index 0b470557b..89557e5e8 100644 --- a/packages/editor-skeleton/src/components/settings/settings-pane.tsx +++ b/packages/editor-skeleton/src/components/settings/settings-pane.tsx @@ -1,16 +1,16 @@ import { Component, MouseEvent, Fragment } from 'react'; import { shallowIntl, observer, obx, engineConfig, runInAction, globalContext } from '@alilc/lowcode-editor-core'; -import { createContent, isJSSlot, isSetterConfig, isSettingField } from '@alilc/lowcode-utils'; -import { Skeleton } from '@alilc/lowcode-editor-skeleton'; +import { createContent, isJSSlot, isSetterConfig } from '@alilc/lowcode-utils'; +import { Skeleton, Stage } from '@alilc/lowcode-editor-skeleton'; import { IPublicTypeCustomView } from '@alilc/lowcode-types'; -import { SettingField, SettingTopEntry, ISettingEntry, ComponentMeta } from '@alilc/lowcode-designer'; +import { SettingField, SettingTopEntry, ISettingEntry, IComponentMeta, ISettingField, isSettingField } from '@alilc/lowcode-designer'; import { createField } from '../field'; import PopupService, { PopupPipe } from '../popup'; import { SkeletonContext } from '../../context'; import { intl } from '../../locale'; import { Setters } from '@alilc/lowcode-shell'; -function isStandardComponent(componentMeta: ComponentMeta | null) { +function isStandardComponent(componentMeta: IComponentMeta | null) { if (!componentMeta) return false; const { prototype } = componentMeta; return prototype == null; @@ -31,8 +31,9 @@ function isInitialValueNotEmpty(initialValue: any) { return (initialValue !== undefined && initialValue !== null); } -type SettingFieldViewProps = { field: SettingField }; +type SettingFieldViewProps = { field: ISettingField }; type SettingFieldViewState = { fromOnChange: boolean; value: any }; + @observer class SettingFieldView extends Component { static contextType = SkeletonContext; @@ -55,7 +56,7 @@ class SettingFieldView extends Component { - stageName = `${field.getNode().id}_${field.name.toString()}`; + stageName = `${field.getNode().id}_${field.name?.toString()}`; // 清除原 stage,不然 content 引用的一直是老的 field,导致数据无法得到更新 stages.container.remove(stageName); stages.add({ @@ -252,7 +253,9 @@ class SettingFieldView extends Component { - field.parent.clearPropValue(field.name); + if (field.name) { + field.parent.clearPropValue(field.name); + } }, }), extraProps.forceInline ? 'plain' : extraProps.display, @@ -280,7 +283,7 @@ class SettingGroupView extends Component { let stageName; if (display === 'entry') { runInAction(() => { - stageName = `${field.getNode().id}_${field.name.toString()}`; + stageName = `${field.getNode().id}_${field.name?.toString()}`; // 清除原 stage,不然 content 引用的一直是老的 field,导致数据无法得到更新 stages.container.remove(stageName); stages.add({ @@ -324,7 +327,7 @@ class SettingGroupView extends Component { } } -export function createSettingFieldView(item: SettingField | IPublicTypeCustomView, field: ISettingEntry, index?: number) { +export function createSettingFieldView(item: ISettingField | IPublicTypeCustomView, field: ISettingEntry, index?: number) { if (isSettingField(item)) { if (item.isGroup) { return ; diff --git a/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx b/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx index c12d966be..0bbef4bf2 100644 --- a/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx +++ b/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx @@ -1,17 +1,22 @@ import React, { Component } from 'react'; import { Tab, Breadcrumb } from '@alifd/next'; import { Title, observer, Editor, obx, globalContext, engineConfig, makeObservable } from '@alilc/lowcode-editor-core'; -import { Node, SettingField } from '@alilc/lowcode-designer'; +import { Node, SettingField, isSettingField, INode } from '@alilc/lowcode-designer'; import classNames from 'classnames'; import { SettingsMain } from './main'; import { SettingsPane } from './settings-pane'; import { StageBox } from '../stage-box'; import { SkeletonContext } from '../../context'; import { intl } from '../../locale'; -import { createIcon, isSettingField } from '@alilc/lowcode-utils'; +import { createIcon } from '@alilc/lowcode-utils'; + +interface ISettingsPrimaryPaneProps { + engineEditor: Editor; + config: any; +} @observer -export class SettingsPrimaryPane extends Component<{ engineEditor: Editor; config: any }, { shouldIgnoreRoot: boolean }> { +export class SettingsPrimaryPane extends Component { state = { shouldIgnoreRoot: false, }; @@ -19,7 +24,7 @@ export class SettingsPrimaryPane extends Component<{ engineEditor: Editor; confi @obx.ref private _activeKey?: any; - constructor(props) { + constructor(props: ISettingsPrimaryPaneProps) { super(props); makeObservable(this); } @@ -72,8 +77,8 @@ export class SettingsPrimaryPane extends Component<{ engineEditor: Editor; confi const editor = this.props.engineEditor; const designer = editor.get('designer'); const current = designer?.currentSelection?.getNodes()?.[0]; - let node: Node | null = settings.first; - const { focusNode } = node.document; + let node: INode | null = settings.first; + const focusNode = node.document?.focusNode; const items = []; let l = 3; @@ -83,7 +88,7 @@ export class SettingsPrimaryPane extends Component<{ engineEditor: Editor; confi if (shouldIgnoreRoot && node.isRoot()) { break; } - if (node.contains(focusNode)) { + if (focusNode && node.contains(focusNode)) { l = 0; } const props = diff --git a/packages/editor-skeleton/src/types.ts b/packages/editor-skeleton/src/types.ts index b3e5a0408..a51369f15 100644 --- a/packages/editor-skeleton/src/types.ts +++ b/packages/editor-skeleton/src/types.ts @@ -15,7 +15,7 @@ export interface WidgetConfig extends IPublicTypeWidgetBaseConfig { props?: { align?: 'left' | 'right' | 'bottom' | 'center' | 'top'; onInit?: (widget: IWidget) => void; - title?: IPublicTypeTitleContent; + title?: IPublicTypeTitleContent | null; }; content?: string | ReactElement | ComponentType; // children } diff --git a/packages/types/src/shell/api/project.ts b/packages/types/src/shell/api/project.ts index edafabb48..ead415e54 100644 --- a/packages/types/src/shell/api/project.ts +++ b/packages/types/src/shell/api/project.ts @@ -3,20 +3,22 @@ import { IPublicEnumTransformStage } from '../enum'; import { IPublicApiSimulatorHost } from './'; import { IPublicModelDocumentModel } from '../model'; -export interface IPublicApiProject { +export interface IPublicApiProject< + DocumentModel = IPublicModelDocumentModel +> { /** * 获取当前的 document * get current document */ - get currentDocument(): IPublicModelDocumentModel | null; + get currentDocument(): DocumentModel | null; /** * 获取当前 project 下所有 documents * get all documents of this project * @returns */ - get documents(): IPublicModelDocumentModel[]; + get documents(): DocumentModel[]; /** * 获取模拟器的 host @@ -30,7 +32,7 @@ export interface IPublicApiProject { * @param doc * @returns */ - openDocument(doc?: string | IPublicTypeRootSchema | undefined): IPublicModelDocumentModel | null; + openDocument(doc?: string | IPublicTypeRootSchema | undefined): DocumentModel | null; /** * 创建一个 document @@ -38,14 +40,14 @@ export interface IPublicApiProject { * @param data * @returns */ - createDocument(data?: IPublicTypeRootSchema): IPublicModelDocumentModel | null; + createDocument(data?: IPublicTypeRootSchema): DocumentModel | null; /** * 删除一个 document * remove a document * @param doc */ - removeDocument(doc: IPublicModelDocumentModel): void; + removeDocument(doc: DocumentModel): void; /** * 根据 fileName 获取 document @@ -53,7 +55,7 @@ export interface IPublicApiProject { * @param fileName * @returns */ - getDocumentByFileName(fileName: string): IPublicModelDocumentModel | null; + getDocumentByFileName(fileName: string): DocumentModel | null; /** * 根据 id 获取 document @@ -61,7 +63,7 @@ export interface IPublicApiProject { * @param id * @returns */ - getDocumentById(id: string): IPublicModelDocumentModel | null; + getDocumentById(id: string): DocumentModel | null; /** * 导出 project @@ -82,7 +84,7 @@ export interface IPublicApiProject { * get current document * @returns */ - getCurrentDocument(): IPublicModelDocumentModel | null; + getCurrentDocument(): DocumentModel | null; /** * 增加一个属性的管道处理函数 @@ -107,7 +109,7 @@ export interface IPublicApiProject { * 当前 project 内的 document 变更事件 * set callback for event onDocumentChanged */ - onChangeDocument(fn: (doc: IPublicModelDocumentModel) => void): IPublicTypeDisposable; + onChangeDocument(fn: (doc: DocumentModel) => void): IPublicTypeDisposable; /** * 当前 project 的模拟器 ready 事件 diff --git a/packages/types/src/shell/model/dragon.ts b/packages/types/src/shell/model/dragon.ts index 602284e63..67ddb82c7 100644 --- a/packages/types/src/shell/model/dragon.ts +++ b/packages/types/src/shell/model/dragon.ts @@ -2,7 +2,9 @@ import { IPublicTypeDragNodeDataObject, IPublicTypeDragObject } from '../type'; import { IPublicModelDragObject, IPublicModelLocateEvent, IPublicModelNode } from './'; -export interface IPublicModelDragon { +export interface IPublicModelDragon< + Node = IPublicModelNode +> { /** * 是否正在拖动 @@ -51,7 +53,7 @@ export interface IPublicModelDragon { * @param dragObject 拖拽对象 * @param boostEvent 拖拽初始时事件 */ - boost(dragObject: IPublicTypeDragObject, boostEvent: MouseEvent | DragEvent, fromRglNode?: Node | IPublicModelNode): void; + boost(dragObject: IPublicTypeDragObject, boostEvent: MouseEvent | DragEvent, fromRglNode?: Node): void; /** * 添加投放感应区 diff --git a/packages/types/src/shell/model/index.ts b/packages/types/src/shell/model/index.ts index 23b6a6431..097e18065 100644 --- a/packages/types/src/shell/model/index.ts +++ b/packages/types/src/shell/model/index.ts @@ -29,3 +29,5 @@ export * from './plugin-instance'; export * from './sensor'; export * from './resource'; export * from './clipboard'; +export * from './setting-entry'; +export * from './setting-field'; diff --git a/packages/types/src/shell/model/node.ts b/packages/types/src/shell/model/node.ts index ba924d6d5..1cbf63e13 100644 --- a/packages/types/src/shell/model/node.ts +++ b/packages/types/src/shell/model/node.ts @@ -297,8 +297,9 @@ export interface IBaseModelNode< * 获取指定 path 的属性模型实例 * get prop by path * @param path 属性路径,支持 a / a.b / a.0 等格式 + * @param createIfNone 如果不存在,是否新建,默认为 true */ - getProp(path: string, createIfNone: boolean): Prop | null; + getProp(path: string, createIfNone?: boolean): Prop | null; /** * 获取指定 path 的属性模型实例值 diff --git a/packages/types/src/shell/model/sensor.ts b/packages/types/src/shell/model/sensor.ts index 405cd7866..b563cddb1 100644 --- a/packages/types/src/shell/model/sensor.ts +++ b/packages/types/src/shell/model/sensor.ts @@ -3,12 +3,15 @@ import { IPublicModelLocateEvent, IPublicModelDropLocation, IPublicTypeComponentInstance, + IPublicModelNode, } from '..'; /** * 拖拽敏感板 */ -export interface IPublicModelSensor { +export interface IPublicModelSensor< + Node = IPublicModelNode +> { /** * 是否可响应,比如面板被隐藏,可设置该值 false @@ -38,5 +41,5 @@ export interface IPublicModelSensor { /** * 获取节点实例 */ - getNodeInstanceFromElement?: (e: Element | null) => IPublicTypeNodeInstance | null; + getNodeInstanceFromElement?: (e: Element | null) => IPublicTypeNodeInstance | null; } diff --git a/packages/types/src/shell/model/setting-entry.ts b/packages/types/src/shell/model/setting-entry.ts new file mode 100644 index 000000000..ec5b42318 --- /dev/null +++ b/packages/types/src/shell/model/setting-entry.ts @@ -0,0 +1,20 @@ +import { IPublicModelComponentMeta } from "./component-meta"; +import { IPublicModelNode } from "./node"; +import { IBaseModelSettingTarget } from "./setting-target"; + +export interface IBaseModelSettingEntry< + Node, + ComponentMeta, + SettingEntry +> extends IBaseModelSettingTarget< + SettingEntry +> { + readonly nodes: Node[]; + readonly componentMeta: ComponentMeta | null; +} + +export interface IPublicModelSettingEntry extends IBaseModelSettingEntry< + IPublicModelNode, + IPublicModelComponentMeta, + IPublicModelSettingEntry +> {} \ No newline at end of file diff --git a/packages/types/src/shell/model/setting-field.ts b/packages/types/src/shell/model/setting-field.ts new file mode 100644 index 000000000..5efa4c646 --- /dev/null +++ b/packages/types/src/shell/model/setting-field.ts @@ -0,0 +1,5 @@ +import { IPublicModelSettingEntry } from "./setting-entry"; + +export interface IPublicModelSettingField extends IPublicModelSettingEntry { + +} \ No newline at end of file diff --git a/packages/types/src/shell/model/setting-target.ts b/packages/types/src/shell/model/setting-target.ts index e41cf6ea6..78bd924e1 100644 --- a/packages/types/src/shell/model/setting-target.ts +++ b/packages/types/src/shell/model/setting-target.ts @@ -1,7 +1,9 @@ import { IPublicApiSetters } from '../api'; import { IPublicModelEditor } from './'; -export interface IPublicModelSettingTarget { +export interface IBaseModelSettingTarget< + SettingTarget +> { /** * 同样类型的节点 @@ -33,12 +35,12 @@ export interface IPublicModelSettingTarget { /** * 顶端 */ - readonly top: IPublicModelSettingTarget; + readonly top: SettingTarget; /** * 父级 */ - readonly parent: IPublicModelSettingTarget; + readonly parent: SettingTarget; /** * 获取当前值 @@ -53,12 +55,12 @@ export interface IPublicModelSettingTarget { /** * 取得子项 */ - get: (propName: string | number) => IPublicModelSettingTarget | null; + get: (propName: string | number) => SettingTarget | null; /** * 取得子项 */ - getProps?: () => IPublicModelSettingTarget; + getProps?: () => SettingTarget; /** * 获取子项属性值 @@ -91,3 +93,9 @@ export interface IPublicModelSettingTarget { */ getNode: () => any; } + +export interface IPublicModelSettingTarget extends IBaseModelSettingTarget< + IPublicModelSettingTarget +> { + +} diff --git a/packages/types/src/shell/type/dynamic-setter.ts b/packages/types/src/shell/type/dynamic-setter.ts index c10d41c47..5883bb2bb 100644 --- a/packages/types/src/shell/type/dynamic-setter.ts +++ b/packages/types/src/shell/type/dynamic-setter.ts @@ -1,5 +1,4 @@ -import { IPublicModelSettingTarget } from '../model/setting-target'; -import { IPublicTypeCustomView } from '..'; +import { IPublicModelSettingPropEntry, IPublicTypeCustomView } from '..'; import { IPublicTypeSetterConfig } from './setter-config'; -export type IPublicTypeDynamicSetter = (target: IPublicModelSettingTarget) => string | IPublicTypeSetterConfig | IPublicTypeCustomView; +export type IPublicTypeDynamicSetter = (target: IPublicModelSettingPropEntry) => (string | IPublicTypeSetterConfig | IPublicTypeCustomView); diff --git a/packages/types/src/shell/type/location.ts b/packages/types/src/shell/type/location.ts index ac04687e0..c9e2df67f 100644 --- a/packages/types/src/shell/type/location.ts +++ b/packages/types/src/shell/type/location.ts @@ -46,8 +46,10 @@ export interface IPublicTypeLocationPropDetail { // eslint-disable-next-line max-len export type IPublicTypeLocationDetail = IPublicTypeLocationChildrenDetail | IPublicTypeLocationPropDetail | { type: string; [key: string]: any }; -export interface IPublicTypeLocationData { - target: IPublicModelNode; // shadowNode | ConditionFlow | ElementNode | RootNode +export interface IPublicTypeLocationData< + Node = IPublicModelNode +> { + target: Node; // shadowNode | ConditionFlow | ElementNode | RootNode detail: IPublicTypeLocationDetail; source: string; event: IPublicModelLocateEvent; diff --git a/packages/types/src/shell/type/metadata.ts b/packages/types/src/shell/type/metadata.ts index 39022d48f..5659916b8 100644 --- a/packages/types/src/shell/type/metadata.ts +++ b/packages/types/src/shell/type/metadata.ts @@ -184,9 +184,9 @@ export interface ConfigureSupport { */ export interface IPublicTypeCallbacks { // hooks - onMouseDownHook?: (e: MouseEvent, currentNode: IPublicModelNode) => any; - onDblClickHook?: (e: MouseEvent, currentNode: IPublicModelNode) => any; - onClickHook?: (e: MouseEvent, currentNode: IPublicModelNode) => any; + onMouseDownHook?: (e: MouseEvent, currentNode: IPublicModelNode | null) => any; + onDblClickHook?: (e: MouseEvent, currentNode: IPublicModelNode | null) => any; + onClickHook?: (e: MouseEvent, currentNode: IPublicModelNode | null) => any; // onLocateHook?: (e: any, currentNode: any) => any; // onAcceptHook?: (currentNode: any, locationData: any) => any; onMoveHook?: (currentNode: IPublicModelNode) => boolean; diff --git a/packages/types/src/shell/type/node-instance.ts b/packages/types/src/shell/type/node-instance.ts index e1d9789c8..fab8e672b 100644 --- a/packages/types/src/shell/type/node-instance.ts +++ b/packages/types/src/shell/type/node-instance.ts @@ -1,8 +1,11 @@ import { IPublicTypeComponentInstance, IPublicModelNode } from '..'; -export interface IPublicTypeNodeInstance { +export interface IPublicTypeNodeInstance< + T = IPublicTypeComponentInstance, + Node = IPublicModelNode +> { docId: string; nodeId: string; instance: T; - node?: IPublicModelNode | null; + node?: Node | null; } diff --git a/packages/types/src/shell/type/title-content.ts b/packages/types/src/shell/type/title-content.ts index b345ce854..b17a476a5 100644 --- a/packages/types/src/shell/type/title-content.ts +++ b/packages/types/src/shell/type/title-content.ts @@ -1,5 +1,5 @@ -import { ReactElement } from 'react'; +import { ReactElement, ReactNode } from 'react'; import { IPublicTypeI18nData, IPublicTypeTitleConfig } from './'; // eslint-disable-next-line max-len -export type IPublicTypeTitleContent = string | IPublicTypeI18nData | ReactElement | IPublicTypeTitleConfig; \ No newline at end of file +export type IPublicTypeTitleContent = string | IPublicTypeI18nData | ReactElement | ReactNode | IPublicTypeTitleConfig; \ No newline at end of file diff --git a/packages/utils/src/check-types/is-i18n-data.ts b/packages/utils/src/check-types/is-i18n-data.ts index d54ce8d91..f4a7b6f7a 100644 --- a/packages/utils/src/check-types/is-i18n-data.ts +++ b/packages/utils/src/check-types/is-i18n-data.ts @@ -1,6 +1,8 @@ // type checks -export function isI18nData(obj: any): boolean { +import { IPublicTypeI18nData } from "@alilc/lowcode-types"; + +export function isI18nData(obj: any): obj is IPublicTypeI18nData { return obj && obj.type === 'i18n'; } diff --git a/packages/utils/src/check-types/is-location-children-detail.ts b/packages/utils/src/check-types/is-location-children-detail.ts index d20ccc38c..c6d2819d3 100644 --- a/packages/utils/src/check-types/is-location-children-detail.ts +++ b/packages/utils/src/check-types/is-location-children-detail.ts @@ -1,5 +1,5 @@ -import { IPublicTypeLocationDetailType } from '@alilc/lowcode-types'; +import { IPublicTypeLocationChildrenDetail, IPublicTypeLocationDetailType } from '@alilc/lowcode-types'; -export function isLocationChildrenDetail(obj: any): boolean { +export function isLocationChildrenDetail(obj: any): obj is IPublicTypeLocationChildrenDetail { return obj && obj.type === IPublicTypeLocationDetailType.Children; } \ No newline at end of file diff --git a/packages/utils/src/check-types/is-procode-component-type.ts b/packages/utils/src/check-types/is-procode-component-type.ts index 5e58ed175..5c768dd94 100644 --- a/packages/utils/src/check-types/is-procode-component-type.ts +++ b/packages/utils/src/check-types/is-procode-component-type.ts @@ -1,6 +1,6 @@ -import { IPublicTypeComponentMap } from '@alilc/lowcode-types'; +import { IPublicTypeComponentMap, IPublicTypeProCodeComponent } from '@alilc/lowcode-types'; -export function isProCodeComponentType(desc: IPublicTypeComponentMap): boolean { +export function isProCodeComponentType(desc: IPublicTypeComponentMap): desc is IPublicTypeProCodeComponent { return 'package' in desc; } diff --git a/packages/utils/src/check-types/is-setting-field.ts b/packages/utils/src/check-types/is-setting-field.ts index 3db1d887f..67a183a95 100644 --- a/packages/utils/src/check-types/is-setting-field.ts +++ b/packages/utils/src/check-types/is-setting-field.ts @@ -1,3 +1,5 @@ -export function isSettingField(obj: any): boolean { +import { IPublicModelSettingField } from "@alilc/lowcode-types"; + +export function isSettingField(obj: any): obj is IPublicModelSettingField { return obj && obj.isSettingField; } diff --git a/packages/utils/src/check-types/is-title-config.ts b/packages/utils/src/check-types/is-title-config.ts index 23ec49833..460da9979 100644 --- a/packages/utils/src/check-types/is-title-config.ts +++ b/packages/utils/src/check-types/is-title-config.ts @@ -1,7 +1,7 @@ +import { IPublicTypeTitleConfig } from '@alilc/lowcode-types'; import { isI18nData } from './is-i18n-data'; import { isPlainObject } from '../is-plain-object'; - -export function isTitleConfig(obj: any): boolean { +export function isTitleConfig(obj: any): obj is IPublicTypeTitleConfig { return isPlainObject(obj) && !isI18nData(obj); } diff --git a/packages/utils/src/node-helper.ts b/packages/utils/src/node-helper.ts index 66a514364..55d42be4e 100644 --- a/packages/utils/src/node-helper.ts +++ b/packages/utils/src/node-helper.ts @@ -1,10 +1,10 @@ // 仅使用类型 import { IPublicModelNode } from '@alilc/lowcode-types'; -export const getClosestNode = ( - node: IPublicModelNode, - until: (n: IPublicModelNode) => boolean, - ): IPublicModelNode | undefined => { +export const getClosestNode = ( + node: Node, + until: (n: Node) => boolean, + ): Node | undefined => { if (!node) { return undefined; } @@ -22,7 +22,7 @@ export const getClosestNode = ( * @param {unknown} e 点击事件 * @returns {boolean} 是否可点击,true表示可点击 */ -export const canClickNode = (node: IPublicModelNode, e: unknown): boolean => { +export function canClickNode(node: Node, e: unknown): boolean { const onClickHook = node.componentMeta?.advanced?.callbacks?.onClickHook; const canClick = typeof onClickHook === 'function' ? onClickHook(e as MouseEvent, node) : true; return canClick;