diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 000000000..a089167a7 --- /dev/null +++ b/babel.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: [ + ['@babel/plugin-proposal-decorators', { legacy: true }], + [require.resolve('@babel/plugin-proposal-class-properties'), { loose: true }], + ], +}; \ No newline at end of file diff --git a/docs/docs/api/model/document-model.md b/docs/docs/api/model/document-model.md index 0716588ce..c7b35c4d6 100644 --- a/docs/docs/api/model/document-model.md +++ b/docs/docs/api/model/document-model.md @@ -11,39 +11,86 @@ sidebar_position: 0 ## 变量 +### id + +唯一 ID + +`@type {string}` + ### selection -画布节点选中区模型实例,具体方法参见 [画布节点选中区模型](./selection) +画布节点选中区模型实例 + +`@type {IPublicModelSelection}` + +相关章节:[节点选中区模型](./selection) + +相关类型:[IPublicModelSelection](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/selection.ts) ### detecting -画布节点 hover 区模型实例,具体方法参见 [画布节点悬停模型](./detecting) +画布节点 hover 区模型实例 + +`@type {IPublicModelDetecting}` + +相关章节:[画布节点悬停模型](./detecting) + +相关类型:[IPublicModelDetecting](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/detecting.ts) ### history -操作历史模型实例,具体方法参见 [操作历史模型](./history) -### canvas +操作历史模型实例 -获取当前画布中的一些信息,比如拖拽时的 dropLocation +`@type {IPublicModelHistory}` + +相关章节:[操作历史模型](./history) + +相关类型:[IPublicModelHistory](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/history.ts) ### project 获取当前文档模型所属的 project +`@type {IPublicApiProject}` + +相关类型:[IPublicApiProject](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/project.ts) + ### root 获取文档的根节点 +`@type {IPublicModelNode | null}` + +相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts) + ### nodesMap -获取文档下所有节点 +获取文档下所有节点 Map, key 为 nodeId + +`@type {Map} ` + + +相关章节:[节点模型](./node) + +相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts) ### modalNodesManager -参见 [模态节点管理](./modal-nodes-manager) +模态节点管理器 + +`@type {IPublicModelModalNodesManager | null}` + +相关章节:[模态节点管理](./modal-nodes-manager) + +相关类型:[IPublicModelModalNodesManager](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/modal-nodes-manager.ts) ### dropLocation + 文档的 dropLocation + +`@type {IPublicModelDropLocation | null}` + + 相关类型:[IPublicModelDropLocation](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/drop-location.ts) **@since v1.1.0** @@ -51,51 +98,127 @@ sidebar_position: 0 ## 方法签名 ### getNodeById -getNodeById(nodeId: string) - 根据 nodeId 返回 [Node](./node) 实例 +```typescript +/** + * 根据 nodeId 返回 Node 实例 + * get node by nodeId + * @param nodeId + * @returns + */ +getNodeById(nodeId: string): IPublicModelNode | null; +``` + +相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts) + + ### importSchema -importSchema(schema: RootSchema) - 导入 schema + +```typescript +/** + * 导入 schema + * import schema data + * @param schema + */ +importSchema(schema: IPublicTypeRootSchema): void; +``` + +相关类型:[IPublicTypeRootSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/root-schema.ts) + + ### exportSchema - -exportSchema(stage: TransformStage = TransformStage.Render) - 导出 schema +```typescript +/** + * 导出 schema + * export schema + * @param stage + * @returns + */ +exportSchema(stage: IPublicEnumTransformStage): any; +``` + +相关类型:[IPublicEnumTransformStage](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/enum/transform-stage.ts) + ### insertNode -insertNode( - parent: Node, - thing: Node, - at?: number | null | undefined, - copy?: boolean | undefined, - ) - 插入节点 + +```typescript +/** + * 插入节点 + * insert a node + */ +insertNode( + parent: IPublicModelNode, + thing: IPublicModelNode, + at?: number | null | undefined, + copy?: boolean | undefined +): IPublicModelNode | null; +``` + +相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts) + ### createNode -createNode(data: any) - 创建一个节点 + +```typescript +/** + * 创建一个节点 + * create a node + * @param data + * @returns + */ +createNode(data: any): IPublicModelNode | null; +``` + +相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts) + ### removeNode -removeNode(idOrNode: string | Node) - 移除指定节点/节点id +```typescript +/** + * 移除指定节点/节点id + * remove a node by node instance or nodeId + * @param idOrNode + */ +removeNode(idOrNode: string | IPublicModelNode): void; +``` + +相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts) + ### checkNesting 检查拖拽放置的目标节点是否可以放置该拖拽对象 -**@since v1.0.16** - ```typescript -function checkNesting(dropTarget: Node, dragObject: DragNodeObject | DragNodeDataObject): boolean {} +/** + * 检查拖拽放置的目标节点是否可以放置该拖拽对象 + * check if dragOjbect can be put in this dragTarget + * @param dropTarget 拖拽放置的目标节点 + * @param dragObject 拖拽的对象 + * @returns boolean 是否可以放置 + * @since v1.0.16 + */ +checkNesting( + dropTarget: IPublicModelNode, + dragObject: IPublicTypeDragNodeObject | IPublicTypeDragNodeDataObject +): boolean; ``` +相关类型: +- [IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts) +- [IPublicTypeDragNodeObject](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/drag-node-object.ts) +- [IPublicTypeDragNodeDataObject](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/drag-node-object-data.ts) + +**@since v1.0.16** + ### isDetectingNode 检查拖拽放置的目标节点是否可以放置该拖拽对象 @@ -117,48 +240,107 @@ isDetectingNode(node: IPublicModelNode): boolean; ## 事件 ### onAddNode -onAddNode(fn: (node: Node) => void) - 当前 document 新增节点事件 ```typescript -import { project } from '@alilc/lowcode-engine'; - -project.currentDocument.onAddNode((node) => { - console.log('node', node); -}) +/** + * 当前 document 新增节点事件 + * set callback for event on node is created for a document + */ +onAddNode(fn: (node: IPublicModelNode) => void): IPublicTypeDisposable; ``` +相关类型: +- [IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts) +- [IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts) + +### onMountNode + +当前 document 新增节点事件,此时节点已经挂载到 document 上 + +```typescript +/** + * 当前 document 新增节点事件,此时节点已经挂载到 document 上 + * set callback for event on node is mounted to canvas + */ +onMountNode(fn: (payload: { node: IPublicModelNode }) => void): IPublicTypeDisposable; +``` + +相关类型: +- [IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts) +- [IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts) + ### onRemoveNode - -onRemoveNode(fn: (node: Node) => void) - 当前 document 删除节点事件 +```typescript +/** + * 当前 document 删除节点事件 + * set callback for event on node is removed + */ +onRemoveNode(fn: (node: IPublicModelNode) => void): IPublicTypeDisposable; +``` + +相关类型: +- [IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts) +- [IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts) + + ### onChangeDetecting -onChangeDetecting(fn: (node: Node) => void) - 当前 document 的 hover 变更事件 +```typescript +/** + * 当前 document 的 hover 变更事件 + * + * set callback for event on detecting changed + */ +onChangeDetecting(fn: (node: IPublicModelNode) => void): IPublicTypeDisposable; +``` + +相关类型: +- [IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts) +- [IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts) + ### onChangeSelection -onChangeSelection(fn: (ids: string[]) => void) - 当前 document 的选中变更事件 +```typescript +/** + * 当前 document 的选中变更事件 + * set callback for event on selection changed + */ +onChangeSelection(fn: (ids: string[]) => void): IPublicTypeDisposable; +``` + +相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts) + ### onChangeNodeVisible -onChangeNodeVisible(fn: (node: Node, visible: boolean) => void) - 当前 document 的节点显隐状态变更事件 +```typescript +/** + * 当前 document 的节点显隐状态变更事件 + * set callback for event on visibility changed for certain node + * @param fn + */ +onChangeNodeVisible(fn: (node: IPublicModelNode, visible: boolean) => void): void; +``` + +相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts) + ### onChangeNodeChildren onChangeNodeChildren(fn: (info?: IPublicOnChangeOptions) => void) 当前 document 的节点 children 变更事件 +```typescript +``` + ### onChangeNodeProp 当前 document 节点属性修改事件 diff --git a/docs/docs/api/model/drop-location.md b/docs/docs/api/model/drop-location.md new file mode 100644 index 000000000..37497741c --- /dev/null +++ b/docs/docs/api/model/drop-location.md @@ -0,0 +1,54 @@ +--- +title: DropLocation +sidebar_position: 13 +--- + +> **@types** [IPublicModelDropLocation](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/drop-location.ts)
+> **@since** v1.1.0 + + +## 基本介绍 + +拖拽放置位置模型 + +## 变量 + +### target + +拖拽放置位置目标 + +`@type {IPublicModelNode}` + +相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts) + +### detail + +拖拽放置位置详情 + +`@type {IPublicTypeLocationDetail}` + +相关类型:[IPublicTypeLocationDetail](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/location-detail.ts) + +### event + +拖拽放置位置对应的事件 + +`@type {IPublicTypeLocationDetail}` + +相关类型:[IPublicModelLocateEvent](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/location-event.ts) + +## 方法签名 + +### clone + +获取一份当前对象的克隆 + +```typescript +/** + * 获取一份当前对象的克隆 + * get a clone object of current dropLocation + */ +clone(event: IPublicModelLocateEvent): IPublicModelDropLocation; +``` + +相关类型:[IPublicModelLocateEvent](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/location-event.ts) \ No newline at end of file diff --git a/docs/docs/api/model/node.md b/docs/docs/api/model/node.md index cc031d040..60678ad34 100644 --- a/docs/docs/api/model/node.md +++ b/docs/docs/api/model/node.md @@ -14,237 +14,634 @@ sidebar_position: 1 节点 id +`@type {string}` + ### title 节点标题 -### isContainer +`@type {string | IPublicTypeI18nData | ReactElement}` + +相关类型:[IPublicTypeI18nData](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/i18n-data.ts) + +### isContainerNode 是否为「容器型」节点 -### isRoot +`@type {boolean}` + +**@since v1.1.0** +> v1.1.0 之前请使用 `isContainer` + +### isRootNode 是否为根节点 -### isEmpty +`@type {boolean}` + +**@since v1.1.0** + +> v1.1.0 之前请使用 `isRoot` + +### isEmptyNode 是否为空节点(无 children 或者 children 为空) -### isPage +`@type {boolean}` + +**@since v1.1.0** + +> v1.1.0 之前请使用 `isEmpty` + +### isPageNode 是否为 Page 节点 -### isComponent +`@type {boolean}` + +**@since v1.1.0** + +> v1.1.0 之前请使用 `isPage` + +### isComponentNode 是否为 Component 节点 -### isModal +`@type {boolean}` + +**@since v1.1.0** + +> v1.1.0 之前请使用 `isComponent` + +### isModalNode 是否为「模态框」节点 -### isSlot +`@type {boolean}` + +**@since v1.1.0** + +> v1.1.0 之前请使用 `isModal` + +### isSlotNode 是否为插槽节点 -### isParental +`@type {boolean}` + +**@since v1.1.0** + +> v1.1.0 之前请使用 `isSlot` + +### isParentalNode 是否为父类/分支节点 -### isLeaf +`@type {boolean}` + +**@since v1.1.0** + +> v1.1.0 之前请使用 `isParental` + +### isLeafNode + 是否为叶子节点 +`@type {boolean}` + +**@since v1.1.0** + +> v1.1.0 之前请使用 `isLeaf` + ### isLocked + 获取当前节点的锁定状态 **@since v1.0.16** -### isRGLContainer +### isRGLContainerNode 设置为磁贴布局节点,使用方式可参考:[磁贴布局在钉钉宜搭报表设计引擎中的实现](https://mp.weixin.qq.com/s/PSTut5ahAB8nlJ9kBpBaxw) -**@since v1.0.16** +`@type {boolean}` + +**@since v1.1.0** + +> v1.0.16 - v1.1.0 请使用 `isRGLContainer` ### index 下标 +`@type {number}` + ### icon 图标 +`@type {IPublicTypeIconType}` + +相关类型:[IPublicTypeIconType](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/icon-type.ts) + ### zLevel 节点所在树的层级深度,根节点深度为 0 +`@type {number}` + ### componentName 节点 componentName +`@type {string}` + ### componentMeta -节点的物料元数据,参见 物料元数据 +节点的物料元数据 + +`@type {IPublicModelComponentMeta | null}` + +相关类型:[IPublicTypeIconType](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/component-meta.ts) + ### document 获取节点所属的[文档模型](./document-model)对象 +`@type {IPublicModelDocumentModel | null}` + +相关类型:[IPublicModelDocumentModel](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/document-model.ts) + ### prevSibling 获取当前节点的前一个兄弟节点 +`@type {IPublicModelNode | null}` + ### nextSibling 获取当前节点的后一个兄弟节点 +`@type {IPublicModelNode | null}` + ### parent 获取当前节点的父亲节点 +`@type {IPublicModelNode | null}` + ### children 获取当前节点的孩子节点模型 +`@type {IPublicModelNodeChildren | null}` + +相关类型:[IPublicModelNodeChildren](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node-children.ts) + ### slots 节点上挂载的插槽节点们 +`@type {IPublicModelNode[]}` + ### slotFor 当前节点为插槽节点时,返回节点对应的属性实例 +`@type {IPublicModelProp | null}` + +相关类型:[IPublicModelProp](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/prop.ts) + ### props 返回节点的属性集 +`@type {IPublicModelProps | null}` + +相关类型:[IPublicModelProps](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/props.ts) + + ### propsData 返回节点的属性集值 +`@type {IPublicTypePropsMap | IPublicTypePropsList | null}` + +相关类型: +- [IPublicTypePropsMap](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/props-map.ts) +- [IPublicTypePropsList](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/props-list.ts) + +### conditionGroup + +获取条件组 + +`@type {IPublicModelExclusiveGroup | null}` + +相关类型:[IPublicModelExclusiveGroup](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/exclusive-group.ts) + +**@since v1.1.0** + +### schema + +获取符合搭建协议 - 节点 schema 结构 + +`@type {IPublicTypeNodeSchema | null}` + +相关类型:[IPublicTypeNodeSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/node-schema.ts) + +### settingEntry + +获取对应的 setting entry + +`@type {IPublicModelSettingTopEntry}` + +相关类型:[IPublicModelSettingTopEntry](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/setting-top-entry.ts) + +### visible +当前节点是否可见 + +`@type {boolean}` + +**@since v1.1.0** + ## 方法签名 -### getDOMNode - -getDOMNode() - -获取节点实例对应的 dom 节点 ### getRect -getRect() - 返回节点的尺寸、位置信息 +```typescript +/** + * 返回节点的尺寸、位置信息 + * get rect information for this node + */ +getRect(): DOMRect | null; +``` + ### hasSlots -hasSlots() - 是否有挂载插槽节点 +```typescript +/** + * 是否有挂载插槽节点 + * check if current node has slots + */ +hasSlots(): boolean; +``` + ### hasCondition -hasCondition() - 是否设定了渲染条件 +```typescript +/** + * 是否设定了渲染条件 + * check if current node has condition value set + */ +hasCondition(): boolean; +``` + ### hasLoop -hasLoop() - 是否设定了循环数据 +```typescript +/** + * 是否设定了循环数据 + * check if loop is set for this node + */ +hasLoop(): boolean; +``` + ### getProp -getProp(path: string): Prop | null - 获取指定 path 的属性模型实例 +```typescript +/** + * 获取指定 path 的属性模型实例 + * get prop by path + * @param path 属性路径,支持 a / a.b / a.0 等格式 + */ +getProp(path: string, createIfNone: boolean): IPublicModelProp | null; +``` + +相关类型:[IPublicModelProp](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/prop.ts) + ### getPropValue -getPropValue(path: string) - 获取指定 path 的属性模型实例值 +```typescript +/** + * 获取指定 path 的属性模型实例值 + * get prop value by path + * @param path 属性路径,支持 a / a.b / a.0 等格式 + */ +getPropValue(path: string): any; +``` + ### getExtraProp -getExtraProp(path: string): Prop | null - 获取指定 path 的属性模型实例,注:导出时,不同于普通属性,该属性并不挂载在 props 之下,而是与 props 同级 +```typescript +/** + * 获取指定 path 的属性模型实例, + * 注:导出时,不同于普通属性,该属性并不挂载在 props 之下,而是与 props 同级 + * + * get extra prop by path, an extra prop means a prop not exists in the `props` + * but as siblint of the `props` + * @param path 属性路径,支持 a / a.b / a.0 等格式 + * @param createIfNone 当没有属性的时候,是否创建一个属性 + */ +getExtraProp(path: string, createIfNone?: boolean): IPublicModelProp | null; +``` + +相关类型:[IPublicModelProp](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/prop.ts) + ### getExtraPropValue -getExtraPropValue(path: string) - 获取指定 path 的属性模型实例,注:导出时,不同于普通属性,该属性并不挂载在 props 之下,而是与 props 同级 +```typescript +/** + * 获取指定 path 的属性模型实例, + * 注:导出时,不同于普通属性,该属性并不挂载在 props 之下,而是与 props 同级 + * + * get extra prop value by path, an extra prop means a prop not exists in the `props` + * but as siblint of the `props` + * @param path 属性路径,支持 a / a.b / a.0 等格式 + * @returns + */ +getExtraPropValue(path: string): any; +``` + ### setPropValue setPropValue(path: string, value: CompositeValue) 设置指定 path 的属性模型实例值 -### setExtraPropValue +```typescript +/** + * 设置指定 path 的属性模型实例值 + * set value for prop with path + * @param path 属性路径,支持 a / a.b / a.0 等格式 + * @param value 值 + */ +setPropValue(path: string, value: IPublicTypeCompositeValue): void; +``` -setExtraPropValue(path: string, value: CompositeValue) +相关类型:[IPublicTypeCompositeValue](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/composite-value.ts) + + +### setExtraPropValue 设置指定 path 的属性模型实例值 -### importSchema +```typescript +/** + * 设置指定 path 的属性模型实例值 + * set value for extra prop with path + * @param path 属性路径,支持 a / a.b / a.0 等格式 + * @param value 值 + */ +setExtraPropValue(path: string, value: IPublicTypeCompositeValue): void; +``` -importSchema(data: NodeSchema) +相关类型:[IPublicTypeCompositeValue](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/composite-value.ts) + +### importSchema 导入节点数据 -### exportSchema +```typescript +/** + * 导入节点数据 + * import node schema + * @param data + */ +importSchema(data: IPublicTypeNodeSchema): void; +``` -exportSchema(stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Render, options?: any) +相关类型:[IPublicTypeNodeSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/node-schema.ts) + +### exportSchema 导出节点数据 -### insertBefore +```typescript +/** + * 导出节点数据 + * export schema from this node + * @param stage + * @param options + */ +exportSchema(stage: IPublicEnumTransformStage, options?: any): IPublicTypeNodeSchema; +``` -insertBefore(node: Node, ref?: Node | undefined, useMutator?: boolean) +相关类型: +- [IPublicEnumTransformStage](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/enum/transform-stage.ts) +- [IPublicTypeNodeSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/node-schema.ts) + +### insertBefore 在指定位置之前插入一个节点 -### insertAfter +```typescript +/** + * 在指定位置之前插入一个节点 + * insert a node befor current node + * @param node + * @param ref + * @param useMutator + */ +insertBefore( + node: IPublicModelNode, + ref?: IPublicModelNode | undefined, + useMutator?: boolean, + ): void; +``` -insertAfter(node: Node, ref?: Node | undefined, useMutator?: boolean) +### insertAfter 在指定位置之后插入一个节点 +```typescript +/** + * 在指定位置之后插入一个节点 + * insert a node after this node + * @param node + * @param ref + * @param useMutator + */ +insertAfter( + node: IPublicModelNode, + ref?: IPublicModelNode | undefined, + useMutator?: boolean, + ): void; +``` + ### replaceChild -replaceChild(node: Node, data: any) +替换指定子节点 -替换指定节点 +```typescript +/** + * 替换指定子节点 + * replace a child node with data provided + * @param node 待替换的子节点 + * @param data 用作替换的节点对象或者节点描述 + * @returns + */ +replaceChild(node: IPublicModelNode, data: any): IPublicModelNode | null; +``` ### replaceWith -replaceWith(schema: NodeSchema) - 将当前节点替换成指定节点描述 +```typescript +/** + * 将当前节点替换成指定节点描述 + * replace current node with a new node schema + * @param schema + */ +replaceWith(schema: IPublicTypeNodeSchema): any; +``` + +相关类型:[IPublicTypeNodeSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/node-schema.ts) + ### select -select() - 选中当前节点实例 +```typescript +/** + * 选中当前节点实例 + * select current node + */ +select(): void; +``` + ### hover -hover(flag = true) - 设置悬停态 +```typescript +/** + * 设置悬停态 + * set hover value for current node + * @param flag + */ +hover(flag: boolean): void; +``` + ### lock 设置节点锁定状态 ```typescript -function lock(flag?: boolean){} +/** + * 设置节点锁定状态 + * set lock value for current node + * @param flag + * @since v1.0.16 + */ +lock(flag?: boolean): void; ``` **@since v1.0.16** ### remove -remove() +删除当前节点实例 -删除当前节点实例 \ No newline at end of file +```typescript +/** + * 删除当前节点实例 + * remove current node + */ +remove(): void; +``` + +### mergeChildren + +执行新增、删除、排序等操作 + +```typescript +/** + * 执行新增、删除、排序等操作 + * excute remove/add/sort operations on node`s children + * + * @since v1.1.0 + */ +mergeChildren( + remover: (node: IPublicModelNode, idx: number) => boolean, + adder: (children: IPublicModelNode[]) => any, + sorter: (firstNode: IPublicModelNode, secondNode: IPublicModelNode) => number +): any; +``` + +**@since v1.1.0** + +### contains + +当前节点是否包含某子节点 + +```typescript +/** + * 当前节点是否包含某子节点 + * check if current node contains another node as a child + * @param node + * @since v1.1.0 + */ +contains(node: IPublicModelNode): boolean; +``` + +**@since v1.1.0** + +### canPerformAction + +是否可执行某 action + +```typescript +/** + * 是否可执行某 action + * check if current node can perform certain aciton with actionName + * @param actionName action 名字 + * @since v1.1.0 + */ +canPerformAction(actionName: string): boolean; +``` + +**@since v1.1.0** + +### isConditionalVisible + +获取该节点的 ConditionalVisible 值 + +```typescript +/** + * 获取该节点的 ConditionalVisible 值 + * check if current node ConditionalVisible + * @since v1.1.0 + */ +isConditionalVisible(): boolean | undefined; +``` + +**@since v1.1.0** + +### setConditionalVisible +设置该节点的 ConditionalVisible 为 true + +```typescript +/** + * 设置该节点的 ConditionalVisible 为 true + * make this node as conditionalVisible === true + * @since v1.1.0 + */ +setConditionalVisible(): void; +``` + +**@since v1.1.0** \ No newline at end of file diff --git a/docs/docs/guide/quickStart/start.md b/docs/docs/guide/quickStart/start.md index 870360537..6d4f829ec 100644 --- a/docs/docs/guide/quickStart/start.md +++ b/docs/docs/guide/quickStart/start.md @@ -2,68 +2,93 @@ sidebar_position: 2 title: 快速开始 --- + ## 前置知识 + 我们假定你已经对 HTML 和 JavaScript 都比较熟悉了。即便你之前使用其他编程语言,你也可以跟上这篇教程的。除此之外,我们假定你也已经熟悉了一些编程的概念,例如,函数、对象、数组,以及 class 的一些内容。 如果你想回顾一下 JavaScript,你可以阅读[这篇教程](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/A_re-introduction_to_JavaScript)。注意,我们也用到了一些 ES6(较新的 JavaScript 版本)的特性。在这篇教程里,我们主要使用了[箭头函数(arrow functions)](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/Arrow_functions)、[class](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Classes)、[let](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/let) 语句和 [const](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/const) 语句。你可以使用 [Babel REPL](https://babeljs.io/repl/#?presets=react&code_lz=MYewdgzgLgBApgGzgWzmWBeGAeAFgRgD4AJRBEAGhgHcQAnBAEwEJsB6AwgbgChRJY_KAEMAlmDh0YWRiGABXVOgB0AczhQAokiVQAQgE8AkowAUAcjogQUcwEpeAJTjDgUACIB5ALLK6aRklTRBQ0KCohMQk6Bx4gA) 在线预览 ES6 的编译结果。 ## 环境准备 + ### WSL(Window 电脑) + Window 环境需要使用 WSL 在 windows 下进行低代码引擎相关的开发。安装教程 ➡️ [WSL 安装教程](https://docs.microsoft.com/zh-cn/windows/wsl/install)。
**对于 Window 环境来说,之后所有需要执行命令的操作都是在 WSL 终端执行的。** + ### Node + node 版本推荐 16.18.0。 #### 查看 Node 版本 + ![image.png](https://img.alicdn.com/imgextra/i4/O1CN01oCZKNz290LIu8YUTk_!!6000000008005-2-tps-238-70.png) #### 通过 n 来管理 node 版本 + 可以安装 [n](https://www.npmjs.com/package/n) 来管理和变更 node 版本。 ##### 安装 n + ```bash npm install -g n ``` ##### 变更 node 版本 + ```bash n 14.17.0 ``` ### React + 低代码引擎的扩展能力都是基于 React 来研发的,在继续阅读之前最好有一定的 React 基础,React 学习教程 ➡️ [React 快速开始教程](https://zh-hans.reactjs.org/docs/getting-started.html)。 ### 下载 Demo -可以前往 github(https://github.com/alibaba/lowcode-demo)将 DEMO 下载到本地。 + +可以前往 github()将 DEMO 下载到本地。 #### git clone + ##### HTTPS + 需要使用到 git 工具 + ```bash git clone https://github.com/alibaba/lowcode-demo.git ``` + ##### SSH + 需要配置 SSH key,如果没有配置可以 + ```bash git clone git@github.com:alibaba/lowcode-demo.git ``` #### 下载 Zip 包 + ![image.png](https://img.alicdn.com/imgextra/i2/O1CN01iYC7E11phaNwLFUrN_!!6000000005392-2-tps-3584-1794.png) ### 选择一个 demo 项目 -在 以 `demo-general` 为例: + +在 以 `demo-general` 为例: + ```bash cd demo-general ``` ### 安装依赖 + 在 `lowcode-demo/demo-general` 目录下执行: + ```bash npm install ``` ### 启动 demo + 在 `lowcode-demo/demo-general` 目录下执行: + ```bash npm run start ``` @@ -71,6 +96,7 @@ npm run start 之后就可以通过 [http://localhost:5556/](http://localhost:5556/) 来访问我们的 DEMO 了。 ## 认识 Demo + 我们的 Demo 是一个**低代码平台的设计器**。它是一个低代码平台中最重要的一环,用户可以在这里通过拖拽、配置、写代码等等来完成一个页面的开发。由于用户的人群不同、场景不同、诉求不同等等,这个页面的功能就会有所差异。 这里记住**设计器**这个词,它描述的就是下面的这个页面,后面我们会经常看到它。 @@ -95,6 +121,7 @@ Demo 根据**不同的设计器所需要的物料不同**,分为了下面的 8 ![](https://img.alicdn.com/imgextra/i1/O1CN01EU2jRN1wUwlal17WK_!!6000000006312-2-tps-3110-1974.png) ### 目录介绍 + 仓库下每个 demo-xxx-xxx 目录都是一个可独立运行的 demo 工程,分别对应到刚刚介绍的场景。 ![image.png](https://img.alicdn.com/imgextra/i1/O1CN01ztxv5Y1mJozBsLdni_!!6000000004934-2-tps-696-958.png) @@ -104,11 +131,12 @@ Demo 根据**不同的设计器所需要的物料不同**,分为了下面的 8 ![image.png](https://img.alicdn.com/imgextra/i1/O1CN01A50oW522S5zg2eDUH_!!6000000007118-2-tps-732-1384.png) 介绍下其中主要的内容 + - 设计器入口文件 `source/index.ts` 这个文件做了下述几个事情: - 通过 plugins.register 注册各种插件,包括官方插件 (已发布 npm 包形式的插件) 和 `plugins` 目录下内置的示例插件 - 通过 init 初始化低代码设计器 - plugins 目录,存放的都是示例插件,方便用户从中看到一个插件是如何实现的 -- services 目录,模拟数据请求、提供默认 schema、默认资产包等,此目录下内容在真是项目中应替换成真是的与服务端交互的服务。 +- services 目录,模拟数据请求、提供默认 schema、默认资产包等,此目录下内容在真实项目中应替换成真实的与服务端交互的服务。 - 预览页面入口文件 `preview.tsx` 剩下的各位看官可以通过源码来进一步了解。 @@ -118,11 +146,15 @@ Demo 根据**不同的设计器所需要的物料不同**,分为了下面的 8 ![image.png](https://img.alicdn.com/imgextra/i4/O1CN01YJVcOd1PiL1am6bz2_!!6000000001874-2-tps-3248-1970.png) 接下来我们就根据我们自己的诉求通过对设计器进行扩展,改动成我们需要的设计器功能。 + ## 开发一个插件 + ### 方式 1:在 DEMO 中直接新增插件 + ![image.png](https://img.alicdn.com/imgextra/i4/O1CN01pXpSRs1QvRyut2EE3_!!6000000002038-2-tps-718-1144.png) 可以在 demo/sample-plugins 直接新增插件,这里我新增的插件目录是 plugin-demo。并且新增了 index.tsx 文件,将下面的代码粘贴到 index.tsx 中。 + ```javascript import * as React from 'react'; import { IPublicModelPluginContext } from '@alilc/lowcode-types'; @@ -136,7 +168,7 @@ const LowcodePluginPluginDemo = (ctx: IPublicModelPluginContext) => { func: () => { console.log('方法也是一样'); }, - } + }; }, // 插件的初始化函数,在引擎初始化之后会立刻调用 init() { @@ -170,7 +202,7 @@ LowcodePluginPluginDemo.meta = { engines: { lowcodeEngine: '^1.0.0', // 插件需要配合 ^1.0.0 的引擎才可运行 }, -} +}; export default LowcodePluginPluginDemo; ``` @@ -182,8 +214,11 @@ export default LowcodePluginPluginDemo; 这样在我们的设计器中就新增了一个 Demo 面板。 ![image.png](https://img.alicdn.com/imgextra/i2/O1CN01wtPIOV1TQiFLz5Vkf_!!6000000002377-2-tps-3584-1806.png) + ### 方式 2:在新的仓库下开发插件 + 初始化 + ```bash npm init @alilc/element your-plugin-name ``` @@ -201,11 +236,13 @@ npm init @alilc/element your-plugin-name ![image.png](https://img.alicdn.com/imgextra/i4/O1CN01iVIAXD1XVWsOdKttI_!!6000000002929-2-tps-3584-2020.png) 在插件项目下安装依赖 + ```bash npm install ``` 启动项目 + ```bash npm run start ``` @@ -220,9 +257,10 @@ npm run start ![image.png](https://img.alicdn.com/imgextra/i4/O1CN01uqSmrX1oqupxeGH1m_!!6000000005277-2-tps-3584-2020.png) - ## 开发一个自定义物料 + ### 初始化物料 + ```bash npm init @alilc/element your-material-demo ``` @@ -240,11 +278,15 @@ npm init @alilc/element your-material-demo ![image.png](https://img.alicdn.com/imgextra/i1/O1CN01SU2xn91TZPlzcARVI_!!6000000002396-2-tps-3584-2020.png) ### 启动并调试物料 + #### 安装依赖 + ```bash npm i ``` + #### 启动 + ```bash npm run lowcode:dev ``` @@ -252,7 +294,9 @@ npm run lowcode:dev 我们就可以通过 [http://localhost:3333/](http://localhost:3333/) 看到我们的研发的物料了。 ![image.png](https://img.alicdn.com/imgextra/i4/O1CN01JqoHqc1z7zlSWFYJD_!!6000000006668-2-tps-3584-1790.png) + #### 在 Demo 中调试 + ```bash npm i @alilc/build-plugin-alt ``` @@ -262,6 +306,7 @@ npm i @alilc/build-plugin-alt ![image.png](https://img.alicdn.com/imgextra/i2/O1CN01K7u7ci1KCfYlBj2yf_!!6000000001128-2-tps-1388-1046.png) 如图,新增如下代码 + ```javascript [ '@alilc/build-plugin-alt', @@ -281,12 +326,15 @@ npm i @alilc/build-plugin-alt ![image.png](https://img.alicdn.com/imgextra/i1/O1CN0166WywE26Lv7NuJMus_!!6000000007646-2-tps-3584-1812.png) ### 发布 + 首先进行构建 + ```bash npm run lowcode:build ``` 发布组件 + ```bash npm publish ``` @@ -344,6 +392,7 @@ npm publish ``` ### 使用 + 我们将刚刚发布的组件的 assets-prod.json 的内容放到 demo 的 src/universal/assets.json 中。 > 最好放到最后,防止因为资源加载顺序问题导致出现报错。 @@ -356,5 +405,7 @@ npm publish ![image.png](https://img.alicdn.com/imgextra/i2/O1CN01UNp89s1vQXKyfsFaL_!!6000000006167-2-tps-3584-2020.png) 这时候再启动 DEMO 项目,就会有新的低代码物料了。接下来就按照你们的需求,继续扩展物料吧。 + ## 总结 + 这里只是简单的介绍了一些低代码引擎的基础能力,带大家简单的对低代码 DEMO 进行扩展,定制一些新的功能。低代码引擎的能力还有很多很多,可以继续去探索更多的功能。 diff --git a/docs/docs/specs/assets-spec.md b/docs/docs/specs/assets-spec.md index dc55b12c1..5a91b8dde 100644 --- a/docs/docs/specs/assets-spec.md +++ b/docs/docs/specs/assets-spec.md @@ -2,8 +2,6 @@ title: 《低代码引擎资产包协议规范》 sidebar_position: 2 --- -# 《低代码引擎资产包协议规范》 - ## 1 介绍 ### 1.1 本协议规范涉及的问题域 diff --git a/docs/docs/specs/lowcode-spec.md b/docs/docs/specs/lowcode-spec.md index cbe204094..7deeedc2c 100644 --- a/docs/docs/specs/lowcode-spec.md +++ b/docs/docs/specs/lowcode-spec.md @@ -2,8 +2,6 @@ title: 《低代码引擎搭建协议规范》 sidebar_position: 0 --- -# 《低代码引擎搭建协议规范》 - ## 1 介绍 diff --git a/docs/docs/specs/material-spec.md b/docs/docs/specs/material-spec.md index c74d0c96a..234ec62f6 100644 --- a/docs/docs/specs/material-spec.md +++ b/docs/docs/specs/material-spec.md @@ -2,7 +2,6 @@ title: 《低代码引擎物料协议规范》 sidebar_position: 1 --- -# 《低代码引擎物料协议规范》 ## 1 介绍 diff --git a/modules/code-generator/babel.config.js b/modules/code-generator/babel.config.js new file mode 100644 index 000000000..c5986f2bc --- /dev/null +++ b/modules/code-generator/babel.config.js @@ -0,0 +1 @@ +module.exports = require('../../babel.config'); \ No newline at end of file diff --git a/modules/code-generator/babelTransform.js b/modules/code-generator/babelTransform.js deleted file mode 100644 index 6f5af94ff..000000000 --- a/modules/code-generator/babelTransform.js +++ /dev/null @@ -1,22 +0,0 @@ -const babelJest = require('babel-jest'); -const getBabelConfig = require('build-scripts-config/lib/config/babel/index.js'); -const formatWinPath = require('build-scripts-config/lib/config/jest/formatWinPath'); -const babelConfig = getBabelConfig(); - -babelConfig.plugins.push(['@babel/plugin-proposal-class-properties', { loose: true }]); - -const jestBabelConfig = { - ...babelConfig, - presets: babelConfig.presets.map((preset) => { - if (Array.isArray(preset) && formatWinPath(preset[0]).indexOf('@babel/preset-env') > -1) { - return [preset[0], { - targets: { - node: 'current', - }, - }]; - } - return preset; - }), -}; - -module.exports = babelJest.createTransformer(jestBabelConfig); \ No newline at end of file diff --git a/modules/code-generator/jest.config.js b/modules/code-generator/jest.config.js index 5c0fbe40a..0f908143d 100644 --- a/modules/code-generator/jest.config.js +++ b/modules/code-generator/jest.config.js @@ -1,8 +1,4 @@ module.exports = { - transform: { - '^.+\\.(js|jsx|ts|tsx)$': './babelTransform.js', - '^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': 'build-scripts-config/lib/config/jest/fileTransform.js', - }, preset: 'ts-jest', testEnvironment: 'node', transformIgnorePatterns: ['/node_modules/(?!core-js)/'], diff --git a/packages/designer/babel.config.js b/packages/designer/babel.config.js new file mode 100644 index 000000000..c5986f2bc --- /dev/null +++ b/packages/designer/babel.config.js @@ -0,0 +1 @@ +module.exports = require('../../babel.config'); \ No newline at end of file diff --git a/packages/designer/babelTransform.js b/packages/designer/babelTransform.js deleted file mode 100644 index 6f5af94ff..000000000 --- a/packages/designer/babelTransform.js +++ /dev/null @@ -1,22 +0,0 @@ -const babelJest = require('babel-jest'); -const getBabelConfig = require('build-scripts-config/lib/config/babel/index.js'); -const formatWinPath = require('build-scripts-config/lib/config/jest/formatWinPath'); -const babelConfig = getBabelConfig(); - -babelConfig.plugins.push(['@babel/plugin-proposal-class-properties', { loose: true }]); - -const jestBabelConfig = { - ...babelConfig, - presets: babelConfig.presets.map((preset) => { - if (Array.isArray(preset) && formatWinPath(preset[0]).indexOf('@babel/preset-env') > -1) { - return [preset[0], { - targets: { - node: 'current', - }, - }]; - } - return preset; - }), -}; - -module.exports = babelJest.createTransformer(jestBabelConfig); \ No newline at end of file diff --git a/packages/designer/jest.config.js b/packages/designer/jest.config.js index 4d6d29173..788c0ac79 100644 --- a/packages/designer/jest.config.js +++ b/packages/designer/jest.config.js @@ -4,10 +4,6 @@ const esModules = [].join('|'); const pkgNames = fs.readdirSync(join('..')).filter(pkgName => !pkgName.startsWith('.')); const jestConfig = { - transform: { - '^.+\\.(js|jsx|ts|tsx)$': './babelTransform.js', - '^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': 'build-scripts-config/lib/config/jest/fileTransform.js', - }, // transform: { // '^.+\\.[jt]sx?$': 'babel-jest', // // '^.+\\.(ts|tsx)$': 'ts-jest', diff --git a/packages/designer/src/designer/location.ts b/packages/designer/src/designer/location.ts index a690b28d5..59d32f048 100644 --- a/packages/designer/src/designer/location.ts +++ b/packages/designer/src/designer/location.ts @@ -101,10 +101,6 @@ export function getWindow(elem: Element | Document): Window { } export interface IDropLocation extends IPublicModelDropLocation { - readonly target: INode; - - readonly event: ILocateEvent; - readonly source: string; get document(): IPublicModelDocumentModel; diff --git a/packages/designer/src/document/document-model.ts b/packages/designer/src/document/document-model.ts index 5e0717e03..679931bc7 100644 --- a/packages/designer/src/document/document-model.ts +++ b/packages/designer/src/document/document-model.ts @@ -15,6 +15,8 @@ import { IPublicApiProject, IPublicModelDropLocation, IPublicEnumTransformStage, + IPublicOnChangeOptions, + EDITOR_EVENT, } from '@alilc/lowcode-types'; import { Project } from '../project'; import { ISimulatorHost } from '../simulator'; @@ -158,6 +160,22 @@ export class DocumentModel implements IDocumentModel { this.inited = true; } + onChangeNodeVisible(fn: (node: IPublicModelNode, visible: boolean) => void): () => void { + this.designer.editor?.eventBus.on(EDITOR_EVENT.NODE_CHILDREN_CHANGE, fn); + + return () => { + this.designer.editor?.eventBus.off(EDITOR_EVENT.NODE_CHILDREN_CHANGE, fn); + }; + } + + onChangeNodeChildren(fn: (info: IPublicOnChangeOptions) => void): () => void { + this.designer.editor?.eventBus.on(EDITOR_EVENT.NODE_VISIBLE_CHANGE, fn); + + return () => { + this.designer.editor?.eventBus.off(EDITOR_EVENT.NODE_VISIBLE_CHANGE, fn); + }; + } + @obx.shallow private willPurgeSpace: Node[] = []; get modalNode() { diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts index 90f8be9a2..169dc5cbf 100644 --- a/packages/designer/src/document/node/node.ts +++ b/packages/designer/src/document/node/node.ts @@ -16,6 +16,7 @@ import { IPublicModelNode, IPublicModelExclusiveGroup, IPublicEnumTransformStage, + EDITOR_EVENT, } from '@alilc/lowcode-types'; import { compatStage, isDOMText, isJSExpression } from '@alilc/lowcode-utils'; import { SettingTopEntry } from '@alilc/lowcode-designer'; @@ -32,6 +33,9 @@ import { NodeRemoveOptions } from '../../types'; export interface INode extends IPublicModelNode { + setVisible(flag: boolean): void; + + getVisible(): boolean; } /** @@ -190,6 +194,13 @@ export class Node this.isInited = true; this.emitter = createModuleEventBus('Node'); + const editor = this.document.designer.editor; + this.onVisibleChange((visible: boolean) => { + editor?.eventBus.emit(EDITOR_EVENT.NODE_VISIBLE_CHANGE, this, visible); + }); + this.onChildrenChange((info?: { type: string; node: Node }) => { + editor?.eventBus.emit(EDITOR_EVENT.NODE_VISIBLE_CHANGE, info); + }); } _settingEntry: SettingTopEntry; @@ -261,27 +272,59 @@ export class Node return !!this._isRGLContainer; } + set isRGLContainerNode(status: boolean) { + this._isRGLContainer = status; + } + + get isRGLContainerNode(): boolean { + return !!this._isRGLContainer; + } + isContainer(): boolean { - return this.isParental() && this.componentMeta.isContainer; + return this.isContainerNode; + } + + get isContainerNode(): boolean { + return this.isParentalNode && this.componentMeta.isContainer; } isModal(): boolean { + return this.isModalNode; + } + + get isModalNode(): boolean { return this.componentMeta.isModal; } isRoot(): boolean { + return this.isRootNode; + } + + get isRootNode(): boolean { return this.document.rootNode === (this as any); } isPage(): boolean { - return this.isRoot() && this.componentName === 'Page'; + return this.isPageNode; + } + + get isPageNode(): boolean { + return this.isRootNode && this.componentName === 'Page'; } isComponent(): boolean { - return this.isRoot() && this.componentName === 'Component'; + return this.isComponentNode; + } + + get isComponentNode(): boolean { + return this.isRootNode && this.componentName === 'Component'; } isSlot(): boolean { + return this.isSlotNode; + } + + get isSlotNode(): boolean { return this._slotFor != null && this.componentName === 'Slot'; } @@ -289,13 +332,20 @@ export class Node * 是否一个父亲类节点 */ isParental(): boolean { - return !this.isLeaf(); + return this.isParentalNode; + } + + get isParentalNode(): boolean { + return !this.isLeafNode; } /** * 终端节点,内容一般为 文字 或者 表达式 */ - isLeaf(): this is LeafNode { + isLeaf(): boolean { + return this.isLeafNode; + } + get isLeafNode(): boolean { return this.componentName === 'Leaf'; } diff --git a/packages/designer/tests/document/node/node.add.test.ts b/packages/designer/tests/document/node/node.add.test.ts index a9ca5247c..4f5655db9 100644 --- a/packages/designer/tests/document/node/node.add.test.ts +++ b/packages/designer/tests/document/node/node.add.test.ts @@ -6,7 +6,6 @@ import { Node } from '../../../src/document/node/node'; import { Designer } from '../../../src/designer/designer'; import formSchema from '../../fixtures/schema/form'; import { getIdsFromSchema, getNodeFromSchemaById } from '../../utils'; -import { EBADF } from 'constants'; const mockCreateSettingEntry = jest.fn(); jest.mock('../../../src/designer/designer', () => { diff --git a/packages/designer/tests/document/node/node.dragdrop.test.ts b/packages/designer/tests/document/node/node.dragdrop.test.ts index c15ced2b2..3fe909124 100644 --- a/packages/designer/tests/document/node/node.dragdrop.test.ts +++ b/packages/designer/tests/document/node/node.dragdrop.test.ts @@ -1,8 +1,5 @@ -import set from 'lodash/set'; -import cloneDeep from 'lodash/cloneDeep'; import '../../fixtures/window'; import { Project } from '../../../src/project/project'; -import { Node } from '../../../src/document/node/node'; import { Designer } from '../../../src/designer/designer'; import formSchema from '../../fixtures/schema/form'; import { getIdsFromSchema, getNodeFromSchemaById } from '../../utils'; diff --git a/packages/designer/tests/document/node/node.modify.test.ts b/packages/designer/tests/document/node/node.modify.test.ts index 34db3b238..7aa055ae1 100644 --- a/packages/designer/tests/document/node/node.modify.test.ts +++ b/packages/designer/tests/document/node/node.modify.test.ts @@ -1,8 +1,5 @@ -import set from 'lodash/set'; -import cloneDeep from 'lodash/cloneDeep'; import '../../fixtures/window'; import { Project } from '../../../src/project/project'; -import { Node } from '../../../src/document/node/node'; import { Designer } from '../../../src/designer/designer'; import formSchema from '../../fixtures/schema/form'; import { getIdsFromSchema, getNodeFromSchemaById } from '../../utils'; diff --git a/packages/designer/tests/document/node/node.remove.test.ts b/packages/designer/tests/document/node/node.remove.test.ts index 1adf7dd0b..28bdf914f 100644 --- a/packages/designer/tests/document/node/node.remove.test.ts +++ b/packages/designer/tests/document/node/node.remove.test.ts @@ -2,10 +2,9 @@ import set from 'lodash/set'; import cloneDeep from 'lodash/cloneDeep'; import '../../fixtures/window'; import { Project } from '../../../src/project/project'; -import { Node } from '../../../src/document/node/node'; import { Designer } from '../../../src/designer/designer'; import formSchema from '../../fixtures/schema/form'; -import { getIdsFromSchema, getNodeFromSchemaById } from '../../utils'; +import { getIdsFromSchema } from '../../utils'; const mockCreateSettingEntry = jest.fn(); jest.mock('../../../src/designer/designer', () => { diff --git a/packages/editor-skeleton/src/area.ts b/packages/editor-skeleton/src/area.ts index df0df412c..f0dac5757 100644 --- a/packages/editor-skeleton/src/area.ts +++ b/packages/editor-skeleton/src/area.ts @@ -1,9 +1,12 @@ /* eslint-disable max-len */ import { obx, computed, makeObservable } from '@alilc/lowcode-editor-core'; +import { Logger } from '@alilc/lowcode-utils'; +import { IPublicTypeWidgetBaseConfig, IArea } from '@alilc/lowcode-types'; import { WidgetContainer } from './widget/widget-container'; import { Skeleton } from './skeleton'; import { IWidget } from './widget/widget'; -import { IPublicTypeWidgetBaseConfig, IArea } from '@alilc/lowcode-types'; + +const logger = new Logger({ level: 'warn', bizName: 'skeleton:area' }); export class Area implements IArea { @obx private _visible = true; @@ -36,6 +39,7 @@ export class Area { onGetWebpackConfig((config) => { - ['jsx', 'tsx'].forEach((rule) => { - config.module - .rule(rule) - .exclude.clear() - .add(/node_modules(?!(.+_component_demo|.+build-plugin-component))/) - .end() - .use('babel-loader') - .tap((options) => { - const { plugins = [] } = options; - return { - ...options, - plugins: [ - ...plugins, - ['@babel/plugin-proposal-class-properties', { loose: true }], - ], - }; - }); - }); config.resolve .plugin('tsconfigpaths') .use(TsconfigPathsPlugin, [{ diff --git a/packages/ignitor/babel.config.js b/packages/ignitor/babel.config.js new file mode 100644 index 000000000..c5986f2bc --- /dev/null +++ b/packages/ignitor/babel.config.js @@ -0,0 +1 @@ +module.exports = require('../../babel.config'); \ No newline at end of file diff --git a/packages/ignitor/build.plugin.js b/packages/ignitor/build.plugin.js index 308432796..ffa1d4957 100644 --- a/packages/ignitor/build.plugin.js +++ b/packages/ignitor/build.plugin.js @@ -6,26 +6,6 @@ const { version } = lernaConfig; module.exports = ({ context, onGetWebpackConfig }) => { onGetWebpackConfig((config) => { - ['jsx', 'tsx'].forEach((rule) => { - config.module - .rule(rule) - .exclude.clear() - .add(/node_modules(?!(.+_component_demo|.+build-plugin-component))/) - .end() - .use('babel-loader') - .tap((options) => { - const { plugins = [] } = options; - console.log('plugins', plugins); - return { - ...options, - plugins: [ - ...plugins, - ['@babel/plugin-proposal-class-properties', { loose: true }], - ], - }; - }); - }); - config.resolve.plugin('tsconfigpaths').use(TsconfigPathsPlugin, [ { configFile: './tsconfig.json', diff --git a/packages/ignitor/jest.config.js b/packages/ignitor/jest.config.js new file mode 100644 index 000000000..788c0ac79 --- /dev/null +++ b/packages/ignitor/jest.config.js @@ -0,0 +1,47 @@ +const fs = require('fs'); +const { join } = require('path'); +const esModules = [].join('|'); +const pkgNames = fs.readdirSync(join('..')).filter(pkgName => !pkgName.startsWith('.')); + +const jestConfig = { + // transform: { + // '^.+\\.[jt]sx?$': 'babel-jest', + // // '^.+\\.(ts|tsx)$': 'ts-jest', + // // '^.+\\.(js|jsx)$': 'babel-jest', + // }, + // testMatch: ['**/node-children.test.ts'], + // testMatch: ['**/plugin-manager.test.ts'], + // testMatch: ['**/history/history.test.ts'], + // testMatch: ['**/document-model.test.ts'], + // testMatch: ['**/prop.test.ts'], + // testMatch: ['(/tests?/.*(test))\\.[jt]s$'], + transformIgnorePatterns: [ + `/node_modules/(?!${esModules})/`, + ], + setupFiles: ['./tests/fixtures/unhandled-rejection.ts'], + moduleFileExtensions: ['ts', 'tsx', 'js', 'json'], + collectCoverage: false, + collectCoverageFrom: [ + 'src/**/*.ts', + '!src/**/*.d.ts', + '!src/icons/**', + '!src/locale/**', + '!src/builtin-simulator/utils/**', + '!src/plugin/sequencify.ts', + '!src/document/node/exclusive-group.ts', + '!src/document/node/props/value-to-source.ts', + '!src/builtin-simulator/live-editing/live-editing.ts', + '!src/designer/offset-observer.ts', + '!src/designer/clipboard.ts', + '!src/designer/scroller.ts', + '!src/builtin-simulator/host.ts', + '!**/node_modules/**', + '!**/vendor/**', + ], +}; + +// 只对本仓库内的 pkg 做 mapping +jestConfig.moduleNameMapper = {}; +jestConfig.moduleNameMapper[`^@alilc/lowcode\\-(${pkgNames.join('|')})$`] = '/../$1/src'; + +module.exports = jestConfig; \ No newline at end of file diff --git a/packages/plugin-outline-pane/src/controllers/tree-node.ts b/packages/plugin-outline-pane/src/controllers/tree-node.ts index 32c21ede2..1babdbe61 100644 --- a/packages/plugin-outline-pane/src/controllers/tree-node.ts +++ b/packages/plugin-outline-pane/src/controllers/tree-node.ts @@ -110,7 +110,7 @@ export default class TreeNode { get hidden(): boolean { const cv = this.node.isConditionalVisible(); if (cv == null) { - return !this.node.getVisible(); + return !this.node.visible; } return !cv; } @@ -119,7 +119,7 @@ export default class TreeNode { if (this.node.conditionGroup) { return; } - this.node.setVisible(!flag); + this.node.visible = !flag; this.onHiddenChanged && this.onHiddenChanged(flag); } diff --git a/packages/plugin-outline-pane/src/views/tree-title.tsx b/packages/plugin-outline-pane/src/views/tree-title.tsx index 92fac1bba..7a3718366 100644 --- a/packages/plugin-outline-pane/src/views/tree-title.tsx +++ b/packages/plugin-outline-pane/src/views/tree-title.tsx @@ -122,7 +122,7 @@ export default class TreeTitle extends Component<{ data-id={treeNode.id} onClick={() => { if (isModal) { - if (node.getVisible()) { + if (node.visible) { node.document?.modalNodesManager?.setInvisible(node); } else { node.document?.modalNodesManager?.setVisible(node); @@ -134,7 +134,7 @@ export default class TreeTitle extends Component<{ } }} > - {isModal && node.getVisible() && ( + {isModal && node.visible && (
{ node.document?.modalNodesManager?.setInvisible(node); }} @@ -142,7 +142,7 @@ export default class TreeTitle extends Component<{
)} - {isModal && !node.getVisible() && ( + {isModal && !node.visible && (
{ node.document?.modalNodesManager?.setVisible(node); }} diff --git a/packages/rax-simulator-renderer/babel.config.js b/packages/rax-simulator-renderer/babel.config.js new file mode 100644 index 000000000..c5986f2bc --- /dev/null +++ b/packages/rax-simulator-renderer/babel.config.js @@ -0,0 +1 @@ +module.exports = require('../../babel.config'); \ No newline at end of file diff --git a/packages/rax-simulator-renderer/build.plugin.js b/packages/rax-simulator-renderer/build.plugin.js index 1c8604e63..d613f1f56 100644 --- a/packages/rax-simulator-renderer/build.plugin.js +++ b/packages/rax-simulator-renderer/build.plugin.js @@ -1,24 +1,5 @@ module.exports = ({ onGetWebpackConfig }) => { onGetWebpackConfig((config) => { - ['jsx', 'tsx'].forEach((rule) => { - config.module - .rule(rule) - .exclude.clear() - .add(/node_modules(?!(.+_component_demo|.+build-plugin-component))/) - .end() - .use('babel-loader') - .tap((options) => { - const { plugins = [] } = options; - console.log('plugins', plugins); - return { - ...options, - plugins: [ - ...plugins, - ['@babel/plugin-proposal-class-properties', { loose: true }], - ], - }; - }); - }); config.performance.hints(false); }); }; diff --git a/packages/react-simulator-renderer/babel.config.js b/packages/react-simulator-renderer/babel.config.js new file mode 100644 index 000000000..c5986f2bc --- /dev/null +++ b/packages/react-simulator-renderer/babel.config.js @@ -0,0 +1 @@ +module.exports = require('../../babel.config'); \ No newline at end of file diff --git a/packages/react-simulator-renderer/build.plugin.js b/packages/react-simulator-renderer/build.plugin.js index 1c8604e63..d613f1f56 100644 --- a/packages/react-simulator-renderer/build.plugin.js +++ b/packages/react-simulator-renderer/build.plugin.js @@ -1,24 +1,5 @@ module.exports = ({ onGetWebpackConfig }) => { onGetWebpackConfig((config) => { - ['jsx', 'tsx'].forEach((rule) => { - config.module - .rule(rule) - .exclude.clear() - .add(/node_modules(?!(.+_component_demo|.+build-plugin-component))/) - .end() - .use('babel-loader') - .tap((options) => { - const { plugins = [] } = options; - console.log('plugins', plugins); - return { - ...options, - plugins: [ - ...plugins, - ['@babel/plugin-proposal-class-properties', { loose: true }], - ], - }; - }); - }); config.performance.hints(false); }); }; diff --git a/packages/shell/src/api/project.ts b/packages/shell/src/api/project.ts index e97a18334..3ad977584 100644 --- a/packages/shell/src/api/project.ts +++ b/packages/shell/src/api/project.ts @@ -139,7 +139,6 @@ export class Project implements IPublicApiProject { */ importSchema(schema?: IPublicTypeProjectSchema): void { this[projectSymbol].load(schema, true); - // this[editorSymbol].emit(Events.IMPORT_SCHEMA, schema); } /** diff --git a/packages/shell/src/api/skeleton.ts b/packages/shell/src/api/skeleton.ts index b8930677b..51a30d018 100644 --- a/packages/shell/src/api/skeleton.ts +++ b/packages/shell/src/api/skeleton.ts @@ -11,7 +11,7 @@ export class Skeleton implements IPublicApiSkeleton { private readonly [innerSkeletonSymbol]: InnerSkeleton; private readonly pluginName: string; - get [skeletonSymbol]() { + get [skeletonSymbol](): InnerSkeleton { if (this.workspaceMode) { return this[innerSkeletonSymbol]; } diff --git a/packages/shell/src/model/document-model.ts b/packages/shell/src/model/document-model.ts index 1d31d8132..f771d62ec 100644 --- a/packages/shell/src/model/document-model.ts +++ b/packages/shell/src/model/document-model.ts @@ -29,6 +29,7 @@ import { Node } from './node'; import { Selection } from './selection'; import { Detecting } from './detecting'; import { History } from './history'; +import { DropLocation } from './drop-location'; import { Project } from '../api/project'; import { Prop } from './prop'; import { ModalNodesManager } from './modal-nodes-manager'; @@ -45,7 +46,7 @@ export class DocumentModel implements IPublicModelDocumentModel { detecting: IPublicModelDetecting; history: IPublicModelHistory; /** - * @deprecated + * @deprecated use canvas API instead */ canvas: IPublicApiCanvas; @@ -89,12 +90,13 @@ export class DocumentModel implements IPublicModelDocumentModel { * 获取当前文档所属的 project * @returns */ - get project(): IPublicApiProject | null { + get project(): IPublicApiProject { return Project.create(this[documentSymbol].project); } /** * 获取文档的根节点 + * root node of this documentModel * @returns */ get root(): IPublicModelNode | null { @@ -114,10 +116,10 @@ export class DocumentModel implements IPublicModelDocumentModel { } /** - * 获取文档下所有节点 - * @returns + * 获取文档下所有节点 Map, key 为 nodeId + * get map of all nodes , using node.id as key */ - get nodesMap(): any { + get nodesMap(): Map { const map = new Map(); for (let id of this[documentSymbol].nodesMap.keys()) { map.set(id, this.getNodeById(id)!); @@ -132,11 +134,8 @@ export class DocumentModel implements IPublicModelDocumentModel { return ModalNodesManager.create(this[documentSymbol].modalNodesManager); } - /** - * @TODO: 能不能直接暴露 - */ - get dropLocation(): IPublicModelDropLocation { - return this[documentSymbol].dropLocation; + get dropLocation(): IPublicModelDropLocation | null { + return DropLocation.create(this[documentSymbol].dropLocation); } set dropLocation(loc: IPublicModelDropLocation | null) { @@ -144,8 +143,8 @@ export class DocumentModel implements IPublicModelDocumentModel { } /** * 根据 nodeId 返回 Node 实例 - * @param nodeId - * @returns + * get node instance by nodeId + * @param {string} nodeId */ getNodeById(nodeId: string): IPublicModelNode | null { return Node.create(this[documentSymbol].getNode(nodeId)); @@ -289,11 +288,8 @@ export class DocumentModel implements IPublicModelDocumentModel { * @param fn */ onChangeNodeVisible(fn: (node: IPublicModelNode, visible: boolean) => void): void { - // TODO: history 变化时需要重新绑定 - this[documentSymbol].nodesMap?.forEach((node) => { - node.onVisibleChange((flag: boolean) => { - fn(Node.create(node)!, flag); - }); + this[documentSymbol].onChangeNodeVisible((node: IPublicModelNode, visible: boolean) => { + fn(Node.create(node)!, visible); }); } @@ -301,16 +297,14 @@ export class DocumentModel implements IPublicModelDocumentModel { * 当前 document 的节点 children 变更事件 * @param fn */ - onChangeNodeChildren(fn: (info?: IPublicOnChangeOptions) => void): void { - // TODO: history 变化时需要重新绑定 - this[documentSymbol].nodesMap?.forEach((node) => { - node.onChildrenChange((info?: InnerOnChangeOptions) => { - return info - ? fn({ - type: info.type, - node: Node.create(node)!, - }) - : fn(); + onChangeNodeChildren(fn: (info: IPublicOnChangeOptions) => void): void { + this[documentSymbol].onChangeNodeChildren((info?: IPublicOnChangeOptions) => { + if (!info) { + return; + } + fn({ + type: info.type, + node: Node.create(info.node)!, }); }); } diff --git a/packages/shell/src/model/drop-location.ts b/packages/shell/src/model/drop-location.ts index 0f5b8f2b4..e4b13a668 100644 --- a/packages/shell/src/model/drop-location.ts +++ b/packages/shell/src/model/drop-location.ts @@ -3,7 +3,7 @@ import { } from '@alilc/lowcode-designer'; import { dropLocationSymbol } from '../symbols'; import { Node } from './node'; -import { IPublicModelDropLocation } from '@alilc/lowcode-types'; +import { IPublicModelDropLocation, IPublicTypeLocationDetail, IPublicModelLocateEvent } from '@alilc/lowcode-types'; export class DropLocation implements IPublicModelDropLocation { private readonly [dropLocationSymbol]: InnerDropLocation; @@ -12,7 +12,7 @@ export class DropLocation implements IPublicModelDropLocation { this[dropLocationSymbol] = dropLocation; } - static create(dropLocation: InnerDropLocation | null): DropLocation | null { + static create(dropLocation: InnerDropLocation | null): IPublicModelDropLocation | null { if (!dropLocation) { return null; } @@ -22,4 +22,16 @@ export class DropLocation implements IPublicModelDropLocation { get target() { return Node.create(this[dropLocationSymbol].target); } + + get detail(): IPublicTypeLocationDetail { + return this[dropLocationSymbol].detail; + } + + get event(): IPublicModelLocateEvent { + return this[dropLocationSymbol].event; + } + + clone(event: IPublicModelLocateEvent): IPublicModelDropLocation { + return new DropLocation(this[dropLocationSymbol].clone(event)); + } } diff --git a/packages/shell/src/model/node.ts b/packages/shell/src/model/node.ts index 2179c4c18..eca07bb24 100644 --- a/packages/shell/src/model/node.ts +++ b/packages/shell/src/model/node.ts @@ -1,5 +1,6 @@ import { - DocumentModel as InnerDocumentModel, + IDocumentModel as InnerDocumentModel, + INode as InnerNode, } from '@alilc/lowcode-designer'; import { IPublicTypeCompositeValue, @@ -16,6 +17,7 @@ import { IPublicTypePropsMap, IPublicTypePropsList, IPublicModelSettingTopEntry, + IPublicModelExclusiveGroup, } from '@alilc/lowcode-types'; import { Prop } from './prop'; import { Props } from './props'; @@ -29,8 +31,8 @@ import { ReactElement } from 'react'; const shellNodeSymbol = Symbol('shellNodeSymbol'); export class Node implements IPublicModelNode { - private readonly [documentSymbol]: InnerDocumentModel; - private readonly [nodeSymbol]: IPublicModelNode; + private readonly [documentSymbol]: InnerDocumentModel | null; + private readonly [nodeSymbol]: InnerNode; private _id: string; @@ -81,14 +83,14 @@ export class Node implements IPublicModelNode { * 是否为「容器型」节点 */ get isContainer(): boolean { - return this[nodeSymbol].isContainer(); + return this[nodeSymbol].isContainerNode; } /** * 是否为「容器型」节点 */ get isContainerNode(): boolean { - return this[nodeSymbol].isContainer(); + return this[nodeSymbol].isContainerNode; } /** @@ -96,14 +98,14 @@ export class Node implements IPublicModelNode { * 是否为根节点 */ get isRoot(): boolean { - return this[nodeSymbol].isRoot(); + return this[nodeSymbol].isRootNode; } /** * 是否为根节点 */ get isRootNode(): boolean { - return this[nodeSymbol].isRoot(); + return this[nodeSymbol].isRootNode; } /** @@ -111,14 +113,14 @@ export class Node implements IPublicModelNode { * 是否为空节点(无 children 或者 children 为空) */ get isEmpty(): boolean { - return this[nodeSymbol].isEmpty(); + return this[nodeSymbol].isEmptyNode; } /** * 是否为空节点(无 children 或者 children 为空) */ get isEmptyNode(): boolean { - return this[nodeSymbol].isEmpty(); + return this[nodeSymbol].isEmptyNode; } /** @@ -126,14 +128,14 @@ export class Node implements IPublicModelNode { * 是否为 Page 节点 */ get isPage(): boolean { - return this[nodeSymbol].isPage(); + return this[nodeSymbol].isPageNode; } /** * 是否为 Page 节点 */ get isPageNode(): boolean { - return this[nodeSymbol].isPage(); + return this[nodeSymbol].isPageNode; } /** @@ -141,14 +143,14 @@ export class Node implements IPublicModelNode { * 是否为 Component 节点 */ get isComponent(): boolean { - return this[nodeSymbol].isComponent(); + return this[nodeSymbol].isComponentNode; } /** * 是否为 Component 节点 */ get isComponentNode(): boolean { - return this[nodeSymbol].isComponent(); + return this[nodeSymbol].isComponentNode; } /** @@ -156,14 +158,14 @@ export class Node implements IPublicModelNode { * 是否为「模态框」节点 */ get isModal(): boolean { - return this[nodeSymbol].isModal(); + return this[nodeSymbol].isModalNode; } /** * 是否为「模态框」节点 */ get isModalNode(): boolean { - return this[nodeSymbol].isModal(); + return this[nodeSymbol].isModalNode; } /** @@ -171,14 +173,14 @@ export class Node implements IPublicModelNode { * 是否为插槽节点 */ get isSlot(): boolean { - return this[nodeSymbol].isSlot(); + return this[nodeSymbol].isSlotNode; } /** * 是否为插槽节点 */ get isSlotNode(): boolean { - return this[nodeSymbol].isSlot(); + return this[nodeSymbol].isSlotNode; } /** @@ -186,14 +188,14 @@ export class Node implements IPublicModelNode { * 是否为父类/分支节点 */ get isParental(): boolean { - return this[nodeSymbol].isParental(); + return this[nodeSymbol].isParentalNode; } /** * 是否为父类/分支节点 */ get isParentalNode(): boolean { - return this[nodeSymbol].isParental(); + return this[nodeSymbol].isParentalNode; } /** @@ -201,14 +203,14 @@ export class Node implements IPublicModelNode { * 是否为叶子节点 */ get isLeaf(): boolean { - return this[nodeSymbol].isLeaf(); + return this[nodeSymbol].isLeafNode; } /** * 是否为叶子节点 */ get isLeafNode(): boolean { - return this[nodeSymbol].isLeaf(); + return this[nodeSymbol].isLeafNode; } /** @@ -398,6 +400,14 @@ export class Node implements IPublicModelNode { return this[nodeSymbol].hasLoop(); } + get visible(): boolean { + return this[nodeSymbol].getVisible(); + } + + set visible(value: boolean) { + this[nodeSymbol].setVisible(value); + } + getVisible(): boolean { return this[nodeSymbol].getVisible(); } @@ -620,4 +630,20 @@ export class Node implements IPublicModelNode { canPerformAction(actionName: string): boolean { return this[nodeSymbol].canPerformAction(actionName); } + + /** + * get conditionGroup + * @since v1.1.0 + */ + get conditionGroup(): IPublicModelExclusiveGroup | null { + return this[nodeSymbol].conditionGroup; + } + + /** + * set value for conditionalVisible + * @since v1.1.0 + */ + setConditionalVisible(): void { + this[nodeSymbol].setConditionalVisible(); + } } diff --git a/packages/types/src/editor.ts b/packages/types/src/editor.ts index 72dcb9f31..1334f4439 100644 --- a/packages/types/src/editor.ts +++ b/packages/types/src/editor.ts @@ -173,3 +173,9 @@ export interface PluginStatus { export interface PluginStatusSet { [key: string]: PluginStatus; } + +export enum EDITOR_EVENT { + NODE_CHILDREN_CHANGE = 'node.children.change', + + NODE_VISIBLE_CHANGE = 'node.visible.change', +} \ No newline at end of file diff --git a/packages/types/src/shell/model/document-model.ts b/packages/types/src/shell/model/document-model.ts index 2ba3f8b67..48ad9cbd3 100644 --- a/packages/types/src/shell/model/document-model.ts +++ b/packages/types/src/shell/model/document-model.ts @@ -2,6 +2,7 @@ import { IPublicTypeRootSchema, IPublicTypeDragNodeDataObject, IPublicTypeDragNo import { IPublicEnumTransformStage } from '../enum'; import { IPublicApiProject } from '../api'; import { IPublicModelDropLocation, IPublicModelDetecting, IPublicModelNode, IPublicModelSelection, IPublicModelHistory, IPublicModelModalNodesManager } from './'; +import { IPublicOnChangeOptions } from '@alilc/lowcode-types'; export interface IPublicModelDocumentModel { @@ -12,20 +13,34 @@ export interface IPublicModelDocumentModel { set id(id); + /** + * 节点选中区模型实例 + * instance of selection + */ selection: IPublicModelSelection; + /** + * 画布节点 hover 区模型实例 + * instance of detecting + */ detecting: IPublicModelDetecting; + /** + * 操作历史模型实例 + * instance of history + */ history: IPublicModelHistory; /** * 获取当前文档所属的 project + * get project which this documentModel belongs to * @returns */ - get project(): IPublicApiProject | null; + get project(): IPublicApiProject; /** * 获取文档的根节点 + * root node of this documentModel * @returns */ get root(): IPublicModelNode | null; @@ -38,15 +53,17 @@ export interface IPublicModelDocumentModel { * 获取文档下所有节点 * @returns */ - get nodesMap(): any; + get nodesMap(): Map; /** * 模态节点管理 + * get instance of modalNodesManager */ get modalNodesManager(): IPublicModelModalNodesManager | null; /** * 根据 nodeId 返回 Node 实例 + * get node by nodeId * @param nodeId * @returns */ @@ -54,12 +71,14 @@ export interface IPublicModelDocumentModel { /** * 导入 schema + * import schema data * @param schema */ importSchema(schema: IPublicTypeRootSchema): void; /** * 导出 schema + * export schema * @param stage * @returns */ @@ -67,11 +86,7 @@ export interface IPublicModelDocumentModel { /** * 插入节点 - * @param parent - * @param thing - * @param at - * @param copy - * @returns + * insert a node */ insertNode( parent: IPublicModelNode, @@ -82,6 +97,7 @@ export interface IPublicModelDocumentModel { /** * 创建一个节点 + * create a node * @param data * @returns */ @@ -89,6 +105,7 @@ export interface IPublicModelDocumentModel { /** * 移除指定节点/节点id + * remove a node by node instance or nodeId * @param idOrNode */ removeNode(idOrNode: string | IPublicModelNode): void; @@ -102,9 +119,11 @@ export interface IPublicModelDocumentModel { /** * 检查拖拽放置的目标节点是否可以放置该拖拽对象 + * check if dragOjbect can be put in this dragTarget * @param dropTarget 拖拽放置的目标节点 * @param dragObject 拖拽的对象 * @returns boolean 是否可以放置 + * @since v1.0.16 */ checkNesting( dropTarget: IPublicModelNode, @@ -113,36 +132,49 @@ export interface IPublicModelDocumentModel { /** * 当前 document 新增节点事件 + * set callback for event on node is created for a document */ onAddNode(fn: (node: IPublicModelNode) => void): IPublicTypeDisposable; /** * 当前 document 新增节点事件,此时节点已经挂载到 document 上 + * set callback for event on node is mounted to canvas */ onMountNode(fn: (payload: { node: IPublicModelNode }) => void): IPublicTypeDisposable; /** * 当前 document 删除节点事件 + * set callback for event on node is removed */ onRemoveNode(fn: (node: IPublicModelNode) => void): IPublicTypeDisposable; /** * 当前 document 的 hover 变更事件 + * + * set callback for event on detecting changed */ onChangeDetecting(fn: (node: IPublicModelNode) => void): IPublicTypeDisposable; /** * 当前 document 的选中变更事件 + * set callback for event on selection changed */ onChangeSelection(fn: (ids: string[]) => void): IPublicTypeDisposable; /** * 当前 document 的节点显隐状态变更事件 + * set callback for event on visibility changed for certain node * @param fn */ onChangeNodeVisible(fn: (node: IPublicModelNode, visible: boolean) => void): void; + /** + * 当前 document 的节点 children 变更事件 + * @param fn + */ + onChangeNodeChildren(fn: (info: IPublicOnChangeOptions) => void): void; + /** * 当前 document 节点属性修改事件 * @param fn @@ -169,7 +201,7 @@ export interface IPublicModelDocumentModel { * get current drop location * @since v1.1.0 */ - get dropLocation(): IPublicModelDropLocation; + get dropLocation(): IPublicModelDropLocation | null; /** * 设置当前的 DropLocation 信息 diff --git a/packages/types/src/shell/model/drop-location.ts b/packages/types/src/shell/model/drop-location.ts index d1e57ccbf..11ae888ac 100644 --- a/packages/types/src/shell/model/drop-location.ts +++ b/packages/types/src/shell/model/drop-location.ts @@ -1,10 +1,29 @@ import { IPublicTypeLocationDetail } from '../type'; -import { IPublicModelLocateEvent } from './'; +import { IPublicModelLocateEvent, IPublicModelNode } from './'; export interface IPublicModelDropLocation { - get target(): any; - readonly detail: IPublicTypeLocationDetail; + /** + * 拖拽位置目标 + * get target of dropLocation + */ + get target(): IPublicModelNode; + /** + * 拖拽放置位置详情 + * get detail of dropLocation + */ + get detail(): IPublicTypeLocationDetail; + + /** + * 拖拽放置位置对应的事件 + * get event of dropLocation + */ + get event(): IPublicModelLocateEvent; + + /** + * 获取一份当前对象的克隆 + * get a clone object of current dropLocation + */ clone(event: IPublicModelLocateEvent): IPublicModelDropLocation; } diff --git a/packages/types/src/shell/model/node.ts b/packages/types/src/shell/model/node.ts index 536699c17..2350b5291 100644 --- a/packages/types/src/shell/model/node.ts +++ b/packages/types/src/shell/model/node.ts @@ -6,43 +6,49 @@ import { IPublicModelNodeChildren, IPublicModelComponentMeta, IPublicModelProp, export interface IPublicModelNode { /** * 节点 id + * node id */ id: string; + /** * 节点标题 + * title of node */ get title(): string | IPublicTypeI18nData | ReactElement; /** * @deprecated please use isContainerNode - * 是否为「容器型」节点 */ get isContainer(): boolean; /** * 是否为「容器型」节点 + * check if node is a container type node + * @since v1.1.0 */ get isContainerNode(): boolean; /** * @deprecated please use isRootNode - * 是否为根节点 */ get isRoot(): boolean; /** * 是否为根节点 + * check if node is root in the tree + * @since v1.1.0 */ get isRootNode(): boolean; /** * @deprecated please use isEmptyNode - * 是否为空节点(无 children 或者 children 为空) */ get isEmpty(): boolean; /** * 是否为空节点(无 children 或者 children 为空) + * check if current node is empty, which means no children or children is empty + * @since v1.1.0 */ get isEmptyNode(): boolean; @@ -54,220 +60,260 @@ export interface IPublicModelNode { /** * 是否为 Page 节点 + * check if node is Page + * @since v1.1.0 */ get isPageNode(): boolean; /** * @deprecated please use isComponentNode - * 是否为 Component 节点 */ get isComponent(): boolean; /** * 是否为 Component 节点 + * check if node is Component + * @since v1.1.0 */ get isComponentNode(): boolean; /** * @deprecated please use isModalNode - * 是否为「模态框」节点 */ get isModal(): boolean; /** * 是否为「模态框」节点 + * check if node is Modal + * @since v1.1.0 */ get isModalNode(): boolean; /** * @deprecated please use isSlotNode - * 是否为插槽节点 */ get isSlot(): boolean; /** * 是否为插槽节点 + * check if node is a Slot + * @since v1.1.0 */ get isSlotNode(): boolean; /** * @deprecated please use isParentalNode - * 是否为父类/分支节点 */ get isParental(): boolean; /** * 是否为父类/分支节点 + * check if node a parental node + * @since v1.1.0 */ get isParentalNode(): boolean; /** * @deprecated please use isLeafNode - * 是否为叶子节点 */ get isLeaf(): boolean; /** * 是否为叶子节点 + * check if node is a leaf node in tree + * @since v1.1.0 */ get isLeafNode(): boolean; /** * 获取当前节点的锁定状态 + * check if current node is locked + * @since v1.0.16 */ get isLocked(): boolean; + /** + * @deprecated please use isRGLContainerNode + */ + set isRGLContainer(flag: boolean); + + /** + * @deprecated please use isRGLContainerNode + * @returns Boolean + */ + get isRGLContainer(); + + /** + * 设置为磁贴布局节点 + * @since v1.1.0 + */ + set isRGLContainerNode(flag: boolean); + + /** + * 获取磁贴布局节点设置状态 + * @returns Boolean + * @since v1.1.0 + */ + get isRGLContainerNode(); + /** * 下标 + * index */ get index(): number; /** * 图标 + * get icon of this node */ get icon(): IPublicTypeIconType; /** * 节点所在树的层级深度,根节点深度为 0 + * depth level of this node, value of root node is 0 */ get zLevel(): number; /** * 节点 componentName + * componentName */ get componentName(): string; /** * 节点的物料元数据 + * get component meta of this node */ get componentMeta(): IPublicModelComponentMeta | null; /** * 获取节点所属的文档模型对象 - * @returns + * get documentModel of this node */ get document(): IPublicModelDocumentModel | null; /** * 获取当前节点的前一个兄弟节点 - * @returns + * get previous sibling of this node */ get prevSibling(): IPublicModelNode | null; /** * 获取当前节点的后一个兄弟节点 - * @returns + * get next sibling of this node */ get nextSibling(): IPublicModelNode | null; /** * 获取当前节点的父亲节点 - * @returns + * get parent of this node */ get parent(): IPublicModelNode | null; /** * 获取当前节点的孩子节点模型 - * @returns + * get children of this node */ get children(): IPublicModelNodeChildren | null; /** * 节点上挂载的插槽节点们 + * get slots of this node */ get slots(): IPublicModelNode[]; /** * 当前节点为插槽节点时,返回节点对应的属性实例 + * return coresponding prop when this node is a slot node */ get slotFor(): IPublicModelProp | null; /** * 返回节点的属性集 + * get props */ get props(): IPublicModelProps | null; /** * 返回节点的属性集 + * get props data */ get propsData(): IPublicTypePropsMap | IPublicTypePropsList | null; + /** + * get conditionGroup + */ + get conditionGroup(): IPublicModelExclusiveGroup | null; + /** * 获取符合搭建协议 - 节点 schema 结构 + * get schema of this node + * @since v1.1.0 */ get schema(): IPublicTypeNodeSchema; + /** + * 获取对应的 setting entry + * get setting entry of this node + * @since v1.1.0 + */ get settingEntry(): IPublicModelSettingTopEntry; - /** - * 执行新增、删除、排序等操作 - * @param remover - * @param adder - * @param sorter - */ - mergeChildren( - remover: (node: IPublicModelNode, idx: number) => boolean, - adder: (children: IPublicModelNode[]) => any, - sorter: (firstNode: IPublicModelNode, secondNode: IPublicModelNode) => number - ): any; - /** * 返回节点的尺寸、位置信息 - * @returns + * get rect information for this node */ getRect(): DOMRect | null; /** * 是否有挂载插槽节点 - * @returns + * check if current node has slots */ hasSlots(): boolean; /** * 是否设定了渲染条件 - * @returns + * check if current node has condition value set */ hasCondition(): boolean; /** * 是否设定了循环数据 - * @returns + * check if loop is set for this node */ hasLoop(): boolean; - getVisible(): boolean; - - setVisible(flag: boolean): void; - - isConditionalVisible(): boolean | undefined; - - /** - * 设置节点锁定状态 - * @param flag - */ - lock(flag?: boolean): void; - - contains(node: IPublicModelNode): boolean; - /** * 获取指定 path 的属性模型实例 + * get prop by path * @param path 属性路径,支持 a / a.b / a.0 等格式 - * @returns */ getProp(path: string, createIfNone: boolean): IPublicModelProp | null; + /** + * 获取指定 path 的属性模型实例值 + * get prop value by path + * @param path 属性路径,支持 a / a.b / a.0 等格式 + */ + getPropValue(path: string): any; + /** * 获取指定 path 的属性模型实例, * 注:导出时,不同于普通属性,该属性并不挂载在 props 之下,而是与 props 同级 + * + * get extra prop by path, an extra prop means a prop not exists in the `props` + * but as siblint of the `props` * @param path 属性路径,支持 a / a.b / a.0 等格式 * @param createIfNone 当没有属性的时候,是否创建一个属性 - * @returns */ getExtraProp(path: string, createIfNone?: boolean): IPublicModelProp | null; /** * 获取指定 path 的属性模型实例, * 注:导出时,不同于普通属性,该属性并不挂载在 props 之下,而是与 props 同级 + * + * get extra prop value by path, an extra prop means a prop not exists in the `props` + * but as siblint of the `props` * @param path 属性路径,支持 a / a.b / a.0 等格式 * @returns */ @@ -275,52 +321,64 @@ export interface IPublicModelNode { /** * 设置指定 path 的属性模型实例值 + * set value for prop with path * @param path 属性路径,支持 a / a.b / a.0 等格式 * @param value 值 - * @returns */ setPropValue(path: string, value: IPublicTypeCompositeValue): void; /** * 设置指定 path 的属性模型实例值 + * set value for extra prop with path * @param path 属性路径,支持 a / a.b / a.0 等格式 * @param value 值 - * @returns */ setExtraPropValue(path: string, value: IPublicTypeCompositeValue): void; /** * 导入节点数据 + * import node schema * @param data */ importSchema(data: IPublicTypeNodeSchema): void; /** * 导出节点数据 + * export schema from this node * @param stage * @param options - * @returns */ exportSchema(stage: IPublicEnumTransformStage, options?: any): IPublicTypeNodeSchema; /** * 在指定位置之前插入一个节点 + * insert a node befor current node * @param node * @param ref * @param useMutator */ - insertBefore(node: IPublicModelNode, ref?: IPublicModelNode | undefined, useMutator?: boolean): void; + insertBefore( + node: IPublicModelNode, + ref?: IPublicModelNode | undefined, + useMutator?: boolean, + ): void; /** * 在指定位置之后插入一个节点 + * insert a node after this node * @param node * @param ref * @param useMutator */ - insertAfter(node: IPublicModelNode, ref?: IPublicModelNode | undefined, useMutator?: boolean): void; + insertAfter( + node: IPublicModelNode, + ref?: IPublicModelNode | undefined, + useMutator?: boolean, + ): void; /** * 替换指定节点 + * replace a child node with data provided * @param node 待替换的子节点 * @param data 用作替换的节点对象或者节点描述 * @returns @@ -329,58 +387,91 @@ export interface IPublicModelNode { /** * 将当前节点替换成指定节点描述 + * replace current node with a new node schema * @param schema */ replaceWith(schema: IPublicTypeNodeSchema): any; /** * 选中当前节点实例 + * select current node */ select(): void; /** * 设置悬停态 + * set hover value for current node * @param flag */ hover(flag: boolean): void; + /** + * 设置节点锁定状态 + * set lock value for current node + * @param flag + * @since v1.0.16 + */ + lock(flag?: boolean): void; + /** * 删除当前节点实例 + * remove current node */ remove(): void; /** - * @deprecated please use isRGLContainerNode - * 设置为磁贴布局节点 + * 执行新增、删除、排序等操作 + * excute remove/add/sort operations on node`s children + * + * @since v1.1.0 */ - set isRGLContainer(flag: boolean); + mergeChildren( + remover: (node: IPublicModelNode, idx: number) => boolean, + adder: (children: IPublicModelNode[]) => any, + sorter: (firstNode: IPublicModelNode, secondNode: IPublicModelNode) => number + ): any; /** - * @deprecated please use isRGLContainerNode - * 获取磁贴布局节点设置状态 - * @returns Boolean + * 当前节点是否包含某子节点 + * check if current node contains another node as a child + * @param node + * @since v1.1.0 */ - get isRGLContainer(); - - /** - * 设置为磁贴布局节点 - */ - set isRGLContainerNode(flag: boolean); - - /** - * 获取磁贴布局节点设置状态 - * @returns Boolean - */ - get isRGLContainerNode(); + contains(node: IPublicModelNode): boolean; /** * 是否可执行某 action + * check if current node can perform certain aciton with actionName * @param actionName action 名字 - * @returns boolean + * @since v1.1.0 */ canPerformAction(actionName: string): boolean; - get conditionGroup(): IPublicModelExclusiveGroup | null; + /** + * 当前节点是否可见 + * check if current node is visible + * @since v1.1.0 + */ + get visible(): boolean; + /** + * 设置当前节点是否可见 + * set visible value for current node + * @since v1.1.0 + */ + set visible(value: boolean); + + /** + * 获取该节点的 ConditionalVisible 值 + * check if current node ConditionalVisible + * @since v1.1.0 + */ + isConditionalVisible(): boolean | undefined; + + /** + * 设置该节点的 ConditionalVisible 为 true + * make this node as conditionalVisible === true + * @since v1.1.0 + */ setConditionalVisible(): void; }