diff --git a/docs/docs/api/model/detecting.md b/docs/docs/api/model/detecting.md index 7a4886ea4..15e1cfca7 100644 --- a/docs/docs/api/model/detecting.md +++ b/docs/docs/api/model/detecting.md @@ -67,6 +67,7 @@ release(id: string): void; leave(): void; ``` +## 事件 ### onDetectingChange hover 节点变化事件 @@ -81,6 +82,6 @@ onDetectingChange(fn: (node: IPublicModelNode) => void): IPublicTypeDisposable; 相关类型: - [IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts) -- [IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts) +- [IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts) **@since v1.1.0** \ No newline at end of file diff --git a/docs/docs/api/model/selection.md b/docs/docs/api/model/selection.md index 77b33fa60..529a3e5a2 100644 --- a/docs/docs/api/model/selection.md +++ b/docs/docs/api/model/selection.md @@ -14,49 +14,110 @@ sidebar_position: 6 返回选中的节点 id +`@type {string[]}` + +### node +返回选中的节点(如多个节点只返回第一个) + +`@type {IPublicModelNode | null}` + +相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts) + +**@since v1.1.0** + ## 方法签名 ### select -select(id: string) - 选中指定节点(覆盖方式) +```typescript +/** +* 选中指定节点(覆盖方式) +* select node with id, this will override current selection +* @param id +*/ +select(id: string): void; +``` + ### selectAll -selectAll(ids: string[]) - 批量选中指定节点们 +```typescript +/** +* 批量选中指定节点们 +* select node with ids, this will override current selection +* +* @param ids +*/ +selectAll(ids: string[]): void; +``` + ### remove -remove(id: string) - **取消选中**选中的指定节点,不会删除组件 +```typescript +/** +* 移除选中的指定节点 +* remove node from selection with node id +* @param id +*/ +remove(id: string): void; +``` + ### clear -clear() - **取消选中**所有选中节点,不会删除组件 +```typescript +/** +* 清除所有选中节点 +* clear current selection +*/ +clear(): void; +``` + ### has -has(id: string) - 判断是否选中了指定节点 +```typescript +/** +* 判断是否选中了指定节点 +* check if node with specific id is selected +* @param id +*/ +has(id: string): boolean; +``` + ### add -add(id: string) - 选中指定节点(增量方式) +```typescript +/** +* 选中指定节点(增量方式) +* add node with specific id to selection +* @param id +*/ +add(id: string): void; +``` + ### getNodes -getNodes() - 获取选中的节点实例 +```typescript +/** +* 获取选中的节点实例 +* get selected nodes +*/ +getNodes(): IPublicModelNode[]; +``` + +相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts) + ### getTopNodes 获取选区的顶层节点 例如选中的节点为: @@ -67,19 +128,34 @@ getNodes() getNodes 返回的是 [DivA、ChildrenA、DivB],getTopNodes 返回的是 [DivA、DivB],其中 ChildrenA 由于是二层节点,getTopNodes 不会返回 +```typescript +/** +* 获取选区的顶层节点 +* get seleted top nodes +* for example: +* getNodes() returns [A, subA, B], then +* getTopNodes() will return [A, B], subA will be removed +* @since v1.0.16 +*/ +getTopNodes(includeRoot?: boolean): IPublicModelNode[]; +``` + **@since v1.0.16** +## 事件 ### onSelectionChange 注册 selection 变化事件回调 ```typescript /** - * 注册 selection 变化事件回调 - * set callback which will be called when selection is changed - * @since v1.1.0 - */ -onSelectionChange(fn: (ids: string[]) => void): () => void; +* 注册 selection 变化事件回调 +* set callback which will be called when selection is changed +* @since v1.1.0 +*/ +onSelectionChange(fn: (ids: string[]) => void): IPublicTypeDisposable; ``` +相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts) + **@since v1.1.0** \ No newline at end of file diff --git a/packages/designer/src/document/document-model.ts b/packages/designer/src/document/document-model.ts index ffd0807ae..8bccde2ef 100644 --- a/packages/designer/src/document/document-model.ts +++ b/packages/designer/src/document/document-model.ts @@ -8,7 +8,6 @@ import { IPublicTypeDragNodeObject, IPublicTypeDragNodeDataObject, IPublicModelDocumentModel, - IPublicModelSelection, IPublicModelHistory, IPublicModelModalNodesManager, IPublicModelNode, @@ -22,7 +21,7 @@ import { ISimulatorHost } from '../simulator'; import { ComponentMeta } from '../component-meta'; import { IDropLocation, Designer } from '../designer'; import { Node, insertChildren, insertChild, isNode, RootNode, INode } from './node/node'; -import { Selection } from './selection'; +import { Selection, ISelection } from './selection'; import { History } from './history'; import { ModalNodesManager } from './node'; import { uniqueId, isPlainObject, compatStage, isJSExpression, isDOMText, isNodeSchema, isDragNodeObject, isDragNodeDataObject } from '@alilc/lowcode-utils'; @@ -35,10 +34,16 @@ export type GetDataType = T extends undefined ? R : any : T; -export interface IDocumentModel extends IPublicModelDocumentModel { + +export interface IDocumentModel extends Omit< IPublicModelDocumentModel, 'selection' > { readonly designer: Designer; + /** + * 选区控制 + */ + readonly selection: ISelection; + /** * 根据 id 获取节点 */ @@ -59,7 +64,7 @@ export class DocumentModel implements IDocumentModel { /** * 选区控制 */ - readonly selection: IPublicModelSelection = new Selection(this); + readonly selection: ISelection = new Selection(this); /** * 操作记录控制 @@ -489,7 +494,6 @@ export class DocumentModel implements IDocumentModel { ); } - /** * 切换激活,只有打开的才能激活 * 不激活,打开之后切换到另外一个时发生,比如 tab 视图,切换到另外一个标签页 diff --git a/packages/designer/src/document/selection.ts b/packages/designer/src/document/selection.ts index 22b8b4ecd..bcbf778ea 100644 --- a/packages/designer/src/document/selection.ts +++ b/packages/designer/src/document/selection.ts @@ -1,10 +1,20 @@ import { obx, makeObservable, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core'; -import { Node, comparePosition, PositionNO } from './node/node'; +import { Node, INode, comparePosition, PositionNO } from './node/node'; import { DocumentModel } from './document-model'; import { IPublicModelSelection } from '@alilc/lowcode-types'; -export interface ISelection extends IPublicModelSelection { +export interface ISelection extends Omit< IPublicModelSelection, 'getNodes' | 'getTopNodes' > { + /** + * 获取选中的节点实例 + * @returns + */ + getNodes(): INode[]; + + /** + * 获取顶层选区节点,场景:拖拽时,建立蒙层,只蒙在最上层 + */ + getTopNodes(includeRoot?: boolean): INode[]; } export class Selection implements ISelection { diff --git a/packages/shell/src/model/node.ts b/packages/shell/src/model/node.ts index eca07bb24..d9f86c8a8 100644 --- a/packages/shell/src/model/node.ts +++ b/packages/shell/src/model/node.ts @@ -19,12 +19,12 @@ import { IPublicModelSettingTopEntry, IPublicModelExclusiveGroup, } from '@alilc/lowcode-types'; -import { Prop } from './prop'; -import { Props } from './props'; -import { DocumentModel } from './document-model'; -import { NodeChildren } from './node-children'; -import { ComponentMeta } from './component-meta'; -import { SettingTopEntry } from './setting-top-entry'; +import { Prop as ShellProp } from './prop'; +import { Props as ShellProps } from './props'; +import { DocumentModel as ShellDocumentModel } from './document-model'; +import { NodeChildren as ShellNodeChildren } from './node-children'; +import { ComponentMeta as ShellComponentMeta } from './component-meta'; +import { SettingTopEntry as ShellSettingTopEntry } from './setting-top-entry'; import { documentSymbol, nodeSymbol } from '../symbols'; import { ReactElement } from 'react'; @@ -36,27 +36,6 @@ export class Node implements IPublicModelNode { private _id: string; - constructor(node: IPublicModelNode) { - this[nodeSymbol] = node; - this[documentSymbol] = node.document; - - this._id = this[nodeSymbol].id; - } - - static create(node: IPublicModelNode | null | undefined): IPublicModelNode | null { - if (!node) { - return null; - } - // @ts-ignore 直接返回已挂载的 shell node 实例 - if (node[shellNodeSymbol]) { - return (node as any)[shellNodeSymbol]; - } - const shellNode = new Node(node); - // @ts-ignore 挂载 shell node 实例 - node[shellNodeSymbol] = shellNode; - return shellNode; - } - /** * 节点 id */ @@ -257,7 +236,7 @@ export class Node implements IPublicModelNode { * 节点的物料元数据 */ get componentMeta(): IPublicModelComponentMeta | null { - return ComponentMeta.create(this[nodeSymbol].componentMeta); + return ShellComponentMeta.create(this[nodeSymbol].componentMeta); } /** @@ -265,7 +244,7 @@ export class Node implements IPublicModelNode { * @returns */ get document(): IPublicModelDocumentModel | null { - return DocumentModel.create(this[documentSymbol]); + return ShellDocumentModel.create(this[documentSymbol]); } /** @@ -297,7 +276,7 @@ export class Node implements IPublicModelNode { * @returns */ get children(): IPublicModelNodeChildren | null { - return NodeChildren.create(this[nodeSymbol].children); + return ShellNodeChildren.create(this[nodeSymbol].children); } /** @@ -311,14 +290,14 @@ export class Node implements IPublicModelNode { * 当前节点为插槽节点时,返回节点对应的属性实例 */ get slotFor(): IPublicModelProp | null { - return Prop.create(this[nodeSymbol].slotFor); + return ShellProp.create(this[nodeSymbol].slotFor); } /** * 返回节点的属性集 */ get props(): IPublicModelProps | null { - return Props.create(this[nodeSymbol].props); + return ShellProps.create(this[nodeSymbol].props); } /** @@ -336,7 +315,28 @@ export class Node implements IPublicModelNode { } get settingEntry(): IPublicModelSettingTopEntry { - return SettingTopEntry.create(this[nodeSymbol].settingEntry as any); + return ShellSettingTopEntry.create(this[nodeSymbol].settingEntry as any); + } + + constructor(node: IPublicModelNode) { + this[nodeSymbol] = node; + this[documentSymbol] = node.document; + + this._id = this[nodeSymbol].id; + } + + static create(node: InnerNode | null | undefined): IPublicModelNode | null { + if (!node) { + return null; + } + // @ts-ignore 直接返回已挂载的 shell node 实例 + if (node[shellNodeSymbol]) { + return (node as any)[shellNodeSymbol]; + } + const shellNode = new Node(node); + // @ts-ignore 挂载 shell node 实例 + node[shellNodeSymbol] = shellNode; + return shellNode; } /** @@ -445,7 +445,7 @@ export class Node implements IPublicModelNode { * @returns */ getProp(path: string, createIfNone = true): IPublicModelProp | null { - return Prop.create(this[nodeSymbol].getProp(path, createIfNone)); + return ShellProp.create(this[nodeSymbol].getProp(path, createIfNone)); } /** @@ -465,7 +465,7 @@ export class Node implements IPublicModelNode { * @returns */ getExtraProp(path: string, createIfNone?: boolean): IPublicModelProp | null { - return Prop.create(this[nodeSymbol].getExtraProp(path, createIfNone)); + return ShellProp.create(this[nodeSymbol].getExtraProp(path, createIfNone)); } /** @@ -591,12 +591,13 @@ export class Node implements IPublicModelNode { remove(): void { this[nodeSymbol].remove(); } + /** * @deprecated * 设置为磁贴布局节点 */ set isRGLContainer(flag: boolean) { - this[nodeSymbol].isRGLContainer = flag; + this[nodeSymbol].isRGLContainerNode = flag; } /** @@ -605,14 +606,14 @@ export class Node implements IPublicModelNode { * @returns Boolean */ get isRGLContainer() { - return this[nodeSymbol].isRGLContainer; + return this[nodeSymbol].isRGLContainerNode; } /** * 设置为磁贴布局节点 */ set isRGLContainerNode(flag: boolean) { - this[nodeSymbol].isRGLContainer = flag; + this[nodeSymbol].isRGLContainerNode = flag; } /** @@ -620,7 +621,7 @@ export class Node implements IPublicModelNode { * @returns Boolean */ get isRGLContainerNode() { - return this[nodeSymbol].isRGLContainer; + return this[nodeSymbol].isRGLContainerNode; } internalToShellNode() { diff --git a/packages/shell/src/model/selection.ts b/packages/shell/src/model/selection.ts index 92f0453ee..ff2124bec 100644 --- a/packages/shell/src/model/selection.ts +++ b/packages/shell/src/model/selection.ts @@ -1,19 +1,17 @@ import { - DocumentModel as InnerDocumentModel, - Node as InnerNode, - Selection as InnerSelection, + IDocumentModel as InnerDocumentModel, + INode as InnerNode, + ISelection as InnerSelection, } from '@alilc/lowcode-designer'; -import { Node } from './node'; -import { selectionSymbol, documentSymbol } from '../symbols'; -import { IPublicModelSelection, IPublicModelNode } from '@alilc/lowcode-types'; +import { Node as ShellNode } from './node'; +import { selectionSymbol } from '../symbols'; +import { IPublicModelSelection, IPublicModelNode, IPublicTypeDisposable } from '@alilc/lowcode-types'; export class Selection implements IPublicModelSelection { private readonly [selectionSymbol]: InnerSelection; - private readonly [documentSymbol]: InnerDocumentModel; constructor(document: InnerDocumentModel) { this[selectionSymbol] = document.selection; - this[documentSymbol] = document; } /** @@ -83,8 +81,16 @@ export class Selection implements IPublicModelSelection { * 获取选中的节点实例 * @returns */ - getNodes(): Array { - return this[selectionSymbol].getNodes().map((node: InnerNode) => Node.create(node)); + getNodes(): IPublicModelNode[] { + const innerNodes = this[selectionSymbol].getNodes(); + const nodes: IPublicModelNode[] = []; + innerNodes.forEach((node: InnerNode) => { + const shellNode = ShellNode.create(node); + if (shellNode) { + nodes.push(shellNode); + } + }); + return nodes; } /** @@ -94,12 +100,19 @@ export class Selection implements IPublicModelSelection { * getTopNodes() will return [A, B], subA will be removed * @returns */ - getTopNodes(includeRoot: boolean = false): Array { - return this[selectionSymbol].getTopNodes(includeRoot).map((node: InnerNode) => Node.create(node)); + getTopNodes(includeRoot: boolean = false): IPublicModelNode[] { + const innerNodes = this[selectionSymbol].getTopNodes(includeRoot); + const nodes: IPublicModelNode[] = []; + innerNodes.forEach((node: InnerNode) => { + const shellNode = ShellNode.create(node); + if (shellNode) { + nodes.push(shellNode); + } + }); + return nodes; } - - onSelectionChange(fn: (ids: string[]) => void): () => void { + onSelectionChange(fn: (ids: string[]) => void): IPublicTypeDisposable { return this[selectionSymbol].onSelectionChange(fn); } } diff --git a/packages/types/src/shell/model/history.ts b/packages/types/src/shell/model/history.ts index eb183ab77..9d75295ab 100644 --- a/packages/types/src/shell/model/history.ts +++ b/packages/types/src/shell/model/history.ts @@ -40,7 +40,7 @@ export interface IPublicModelHistory { * | 1 | 1 | 1 | * | -------- | -------- | -------- | * | modified | redoable | undoable | - * eg: + * eg. * 7 means : modified && redoable && undoable * 5 means : modified && undoable */ diff --git a/packages/types/src/shell/model/selection.ts b/packages/types/src/shell/model/selection.ts index bfc0b75ce..3b2fdb2f5 100644 --- a/packages/types/src/shell/model/selection.ts +++ b/packages/types/src/shell/model/selection.ts @@ -1,66 +1,76 @@ import { IPublicModelNode } from './'; +import { IPublicTypeDisposable } from '../type'; export interface IPublicModelSelection { /** * 返回选中的节点 id + * get ids of selected nodes */ get selected(): string[]; /** - * return selected Node instance + * 返回选中的节点(如多个节点只返回第一个) + * return selected Node instance,return the first one if multiple nodes are selected + * @since v1.1.0 */ get node(): IPublicModelNode | null; /** * 选中指定节点(覆盖方式) + * select node with id, this will override current selection * @param id */ select(id: string): void; /** * 批量选中指定节点们 + * select node with ids, this will override current selection + * * @param ids */ selectAll(ids: string[]): void; /** * 移除选中的指定节点 + * remove node from selection with node id * @param id */ remove(id: string): void; /** * 清除所有选中节点 + * clear current selection */ clear(): void; /** * 判断是否选中了指定节点 + * check if node with specific id is selected * @param id - * @returns */ has(id: string): boolean; /** * 选中指定节点(增量方式) + * add node with specific id to selection * @param id */ add(id: string): void; /** * 获取选中的节点实例 - * @returns + * get selected nodes */ getNodes(): IPublicModelNode[]; /** * 获取选区的顶层节点 + * get seleted top nodes * for example: * getNodes() returns [A, subA, B], then * getTopNodes() will return [A, B], subA will be removed * @since v1.0.16 - * @returns */ getTopNodes(includeRoot?: boolean): IPublicModelNode[]; @@ -69,5 +79,5 @@ export interface IPublicModelSelection { * set callback which will be called when selection is changed * @since v1.1.0 */ - onSelectionChange(fn: (ids: string[]) => void): () => void; + onSelectionChange(fn: (ids: string[]) => void): IPublicTypeDisposable; }