diff --git a/lerna.json b/lerna.json
index 92a6ed85d..87bc9fc56 100644
--- a/lerna.json
+++ b/lerna.json
@@ -1,6 +1,6 @@
{
"lerna": "2.11.0",
- "version": "1.0.55",
+ "version": "1.0.56",
"npmClient": "tnpm",
"registry": "http://registry.npm.alibaba-inc.com",
"useWorkspaces": true,
diff --git a/package.json b/package.json
index ad2023cce..d0e32422d 100644
--- a/package.json
+++ b/package.json
@@ -14,9 +14,9 @@
"clean": "rm -rf ./packages/*/lib ./packages/*/es ./packages/*/dist ./packages/*/build",
"lint": "eslint --ext .ts,.tsx,.js,.jsx ./ --quiet",
"lint:fix": "eslint --ext .ts,.tsx,.js,.jsx ./ --quiet --fix",
- "pub": "tnpm run watchdog:build && lerna publish patch --force-publish --exact",
- "pub:prepatch": "tnpm run watchdog:build && lerna publish prepatch --force-publish --exact --dist-tag beta --preid beta",
- "pub:prerelease": "tnpm run watchdog:build && lerna publish prerelease --force-publish --exact --dist-tag beta --preid beta",
+ "pub": "tnpm run watchdog:build && lerna publish patch --force-publish --exact --no-changelog",
+ "pub:prepatch": "tnpm run watchdog:build && lerna publish prepatch --force-publish --exact --dist-tag beta --preid beta --no-changelog",
+ "pub:prerelease": "tnpm run watchdog:build && lerna publish prerelease --force-publish --exact --dist-tag beta --preid beta --no-changelog",
"setup": "./scripts/setup.sh",
"setup:skip-build": "./scripts/setup-skip-build.sh",
"start": "./scripts/start.sh",
diff --git a/packages/designer/jest.config.js b/packages/designer/jest.config.js
index 1a6063f1a..0c79d473b 100644
--- a/packages/designer/jest.config.js
+++ b/packages/designer/jest.config.js
@@ -6,7 +6,7 @@ module.exports = {
// // '^.+\\.(ts|tsx)$': 'ts-jest',
// // '^.+\\.(js|jsx)$': 'babel-jest',
// },
- // testMatch: ['**/node.add.test.ts'],
+ // testMatch: ['**/setting-prop-entry.test.ts'],
// testMatch: ['(/tests?/.*(test))\\.[jt]s$'],
transformIgnorePatterns: [
`/node_modules/(?!${esModules})/`,
@@ -22,6 +22,7 @@ module.exports = {
'!src/builtin-simulator/utils/**',
'!src/plugin/sequencify.ts',
'!src/document/node/exclusive-group.ts',
+ '!src/document/node/props/value-to-source.ts',
'!**/node_modules/**',
'!**/vendor/**',
],
diff --git a/packages/designer/package.json b/packages/designer/package.json
index b80b5c458..87b357c24 100644
--- a/packages/designer/package.json
+++ b/packages/designer/package.json
@@ -1,6 +1,6 @@
{
"name": "@ali/lowcode-designer",
- "version": "1.0.55",
+ "version": "1.0.56",
"description": "Designer for Ali LowCode Engine",
"main": "lib/index.js",
"module": "es/index.js",
@@ -14,9 +14,9 @@
},
"license": "MIT",
"dependencies": {
- "@ali/lowcode-editor-core": "1.0.55",
- "@ali/lowcode-types": "1.0.55",
- "@ali/lowcode-utils": "1.0.55",
+ "@ali/lowcode-editor-core": "1.0.56",
+ "@ali/lowcode-types": "1.0.56",
+ "@ali/lowcode-utils": "1.0.56",
"classnames": "^2.2.6",
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.5",
diff --git a/packages/designer/src/builtin-simulator/bem-tools/index.tsx b/packages/designer/src/builtin-simulator/bem-tools/index.tsx
index 97ce673dc..6551633e8 100644
--- a/packages/designer/src/builtin-simulator/bem-tools/index.tsx
+++ b/packages/designer/src/builtin-simulator/bem-tools/index.tsx
@@ -24,7 +24,7 @@ export class BemTools extends Component<{ host: BuiltinSimulatorHost }> {
}
return (
-
+ { !engineConfig.get('disableDetecting') && }
{ engineConfig.get('enableReactiveContainer') && }
@@ -38,4 +38,4 @@ export class BemTools extends Component<{ host: BuiltinSimulatorHost }> {
);
}
-}
+}
\ No newline at end of file
diff --git a/packages/designer/src/builtin-simulator/host.ts b/packages/designer/src/builtin-simulator/host.ts
index 4cb8199df..efe00d474 100644
--- a/packages/designer/src/builtin-simulator/host.ts
+++ b/packages/designer/src/builtin-simulator/host.ts
@@ -1,9 +1,23 @@
-import { obx, autorun, computed, getPublicPath, hotkey, focusTracker, engineConfig } from '@ali/lowcode-editor-core';
+import {
+ obx,
+ autorun,
+ computed,
+ getPublicPath,
+ hotkey,
+ focusTracker,
+ engineConfig,
+} from '@ali/lowcode-editor-core';
import { EventEmitter } from 'events';
-import { ISimulatorHost, Component, NodeInstance, ComponentInstance, DropContainer } from '../simulator';
+import {
+ ISimulatorHost,
+ Component,
+ NodeInstance,
+ ComponentInstance,
+ DropContainer,
+} from '../simulator';
import Viewport from './viewport';
import { createSimulator } from './create-simulator';
-import { Node, ParentalNode, isNode, contains, isRootNode } from '../document';
+import { Node, ParentalNode, contains, isRootNode, isLowCodeComponent } from '../document';
import ResourceConsumer from './resource-consumer';
import {
AssetLevel,
@@ -23,7 +37,6 @@ import {
LocateEvent,
isDragAnyObject,
isDragNodeObject,
- LocationData,
isLocationData,
LocationChildrenDetail,
LocationDetailType,
@@ -36,7 +49,12 @@ import {
} from '../designer';
import { parseMetadata } from './utils/parse-metadata';
import { getClosestClickableNode } from './utils/clickable';
-import { ComponentMetadata, ComponentSchema, TransformStage, ActivityData } from '@ali/lowcode-types';
+import {
+ ComponentMetadata,
+ ComponentSchema,
+ TransformStage,
+ ActivityData,
+} from '@ali/lowcode-types';
import { BuiltinSimulatorRenderer } from './renderer';
import clipboard from '../designer/clipboard';
import { LiveEditing } from './live-editing/live-editing';
@@ -80,7 +98,10 @@ const defaultSimulatorUrl = (() => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [_, prefix = '', dev] = /^(.+?)(\/js)?\/?$/.exec(publicPath) || [];
if (dev) {
- urls = [`${prefix}/css/react-simulator-renderer.css`, `${prefix}/js/react-simulator-renderer.js`];
+ urls = [
+ `${prefix}/css/react-simulator-renderer.css`,
+ `${prefix}/js/react-simulator-renderer.js`,
+ ];
} else if (process.env.NODE_ENV === 'production') {
urls = [`${prefix}/react-simulator-renderer.css`, `${prefix}/react-simulator-renderer.js`];
} else {
@@ -106,12 +127,16 @@ const defaultRaxSimulatorUrl = (() => {
const defaultEnvironment = [
// https://g.alicdn.com/mylib/??react/16.11.0/umd/react.production.min.js,react-dom/16.8.6/umd/react-dom.production.min.js,prop-types/15.7.2/prop-types.min.js
- assetItem(AssetType.JSText, 'window.React=parent.React;window.ReactDOM=parent.ReactDOM;window.__is_simulator_env__=true;', undefined, 'react'),
+ assetItem(
+ AssetType.JSText,
+ 'window.React=parent.React;window.ReactDOM=parent.ReactDOM;window.__is_simulator_env__=true;',
+ undefined,
+ 'react',
+ ),
assetItem(
AssetType.JSText,
'window.PropTypes=parent.PropTypes;React.PropTypes=parent.PropTypes; window.__REACT_DEVTOOLS_GLOBAL_HOOK__ = window.parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;',
),
-
];
const defaultRaxEnvironment = [
@@ -217,7 +242,10 @@ export class BuiltinSimulatorHost implements ISimulatorHost void; firstRun: boolean }) => void) {
+ connect(
+ renderer: BuiltinSimulatorRenderer,
+ fn: (context: { dispose: () => void; firstRun: boolean }) => void,
+ ) {
this._renderer = renderer;
return autorun(fn as any, true);
}
@@ -294,7 +325,7 @@ export class BuiltinSimulatorHost implements ISimulatorHostwindow.${item.library}});`);
+ libraryExportList.push(
+ `Object.defineProperty(window,'${item.exportName}',{get:()=>window.${item.library}});`,
+ );
}
if (item.urls) {
libraryAsset.push(item.urls);
@@ -337,7 +370,8 @@ export class BuiltinSimulatorHost implements ISimulatorHost 0) {
// 加载异步Library
await renderer.loadAsyncLibrary(this.asyncLibraryMap);
@@ -384,7 +417,6 @@ export class BuiltinSimulatorHost implements ISimulatorHost {
// console.log('add node', node);
@@ -501,20 +537,82 @@ export class BuiltinSimulatorHost implements ISimulatorHost {
+ const _nodeInst = this.getNodeInstanceFromElement(e.target as Element);
+ const _node = _nodeInst?.node;
+ if (!_node) return { status: false };
+ const { isRGL: _isRGL, rglNode: _rglNode } = _node.getRGL();
+ const status = !!(
+ _isRGL &&
+ _rglNode?.id !== rglNode?.id &&
+ _rglNode?.getParent() !== node &&
+ _node !== nodeInst?.node
+ );
+ return { status, rglNode: _rglNode };
+ };
+ const move = (e: MouseEvent) => {
+ if (!isShaken(downEvent, e)) {
+ if (nodeInst.instance && nodeInst.instance.style) {
+ nodeInst.instance.style.pointerEvents = 'none';
+ }
+ }
+ const { status, rglNode: _rglNode } = judgeEnterOtherRGL(e);
+ if (status) {
+ designer.dragon.emitter.emit('rgl.add.placeholder', {
+ rglNode: _rglNode,
+ node,
+ event: e,
+ fromRglNode: rglNode,
+ });
+ } else {
+ designer.dragon.emitter.emit('rgl.remove.placeholder');
+ }
+ };
+ const over = (e: MouseEvent) => {
+ const { status, rglNode: _rglNode } = judgeEnterOtherRGL(e);
+ if (status) {
+ designer.dragon.emitter.emit('rgl.drop', {
+ rglNode: _rglNode,
+ node,
+ fromRglNode: rglNode,
+ });
+ }
+ designer.dragon.emitter.emit('rgl.remove.placeholder');
+ if (nodeInst.instance && nodeInst.instance.style) {
+ nodeInst.instance.style.pointerEvents = '';
+ }
+ designer.dragon.emitter.emit('rgl.switch', {
+ action: 'end',
+ rglNode,
+ });
+ doc.removeEventListener('mouseup', over, true);
+ doc.removeEventListener('mousemove', move, true);
+ };
+ doc.addEventListener('mouseup', over, true);
+ doc.addEventListener('mousemove', move, true);
+ } else {
+ // stop response document focus event
+ downEvent.stopPropagation();
+ downEvent.preventDefault();
+ }
// if (!node?.isValidComponent()) {
// // 对于未注册组件直接返回
// return;
@@ -522,8 +620,8 @@ export class BuiltinSimulatorHost implements ISimulatorHost {
doc.removeEventListener('mouseup', checkSelect, true);
- // 鼠标是否移动
- if (!isShaken(downEvent, e)) {
+ // 鼠标是否移动 ? - 鼠标抖动应该也需要支持选中事件,偶尔点击不能选中,磁帖块移除shaken检测
+ if (!isShaken(downEvent, e) || isRGLNode) {
let { id } = node;
designer.activeTracker.track({ node, instance: nodeInst?.instance });
if (isMulti && !isRootNode(node) && selection.has(id)) {
@@ -531,10 +629,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost void;
private disableDetecting?: () => void;
+
/**
* 设置悬停处理
*/
@@ -694,11 +795,14 @@ export class BuiltinSimulatorHost implements ISimulatorHost
// 可能是 [null];
item && item.contains(targetElement),
@@ -851,7 +955,10 @@ export class BuiltinSimulatorHost implements ISimulatorHost | null {
+ getClosestNodeInstance(
+ from: ComponentInstance,
+ specId?: string,
+ ): NodeInstance | null {
return this.renderer?.getClosestNodeInstance(from, specId) || null;
}
@@ -978,7 +1085,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost= rect.top && e.globalY <= rect.bottom && e.globalX >= rect.left && e.globalX <= rect.right;
+ return (
+ e.globalY >= rect.top &&
+ e.globalY <= rect.bottom &&
+ e.globalX >= rect.left &&
+ e.globalX <= rect.right
+ );
}
private sensing = false;
@@ -1157,7 +1269,10 @@ export class BuiltinSimulatorHost implements ISimulatorHost 1
- ? instances.find((_inst) => this.getClosestNodeInstance(_inst, container.id)?.instance === containerInstance)
+ ? instances.find(
+ (_inst) =>
+ this.getClosestNodeInstance(_inst, container.id)?.instance === containerInstance,
+ )
: instances[0]
: null;
- const rect = inst ? this.computeComponentInstanceRect(inst, node.componentMeta.rootSelector) : null;
+ const rect = inst
+ ? this.computeComponentInstanceRect(inst, node.componentMeta.rootSelector)
+ : null;
if (!rect) {
continue;
@@ -1344,7 +1464,10 @@ export class BuiltinSimulatorHost implements ISimulatorHost, e: LocateEvent) {
+ getNearByContainer(
+ { container, instance }: DropContainer,
+ drillDownExcludes: Set,
+ e: LocateEvent,
+ ) {
const { children } = container;
const document = this.project.currentDocument!;
if (!children || children.isEmpty()) {
diff --git a/packages/designer/src/component-meta.ts b/packages/designer/src/component-meta.ts
index 0fe273601..f8cc3a335 100644
--- a/packages/designer/src/component-meta.ts
+++ b/packages/designer/src/component-meta.ts
@@ -23,6 +23,7 @@ import { IconRemove } from './icons/remove';
import { IconClone } from './icons/clone';
import { ReactElement } from 'react';
import { IconHidden } from './icons/hidden';
+import EventEmitter from 'events';
function ensureAList(list?: string | string[]): string[] | null {
if (!list) {
@@ -66,6 +67,8 @@ export class ComponentMeta {
private _npm?: NpmInfo;
+ private emitter: EventEmitter = new EventEmitter();
+
get npm() {
return this._npm;
}
@@ -178,10 +181,10 @@ export class ComponentMeta {
this._title =
typeof title === 'string'
? {
- type: 'i18n',
- 'en-US': this.componentName,
- 'zh-CN': title,
- }
+ type: 'i18n',
+ 'en-US': this.componentName,
+ 'zh-CN': title,
+ }
: title;
}
@@ -229,6 +232,11 @@ export class ComponentMeta {
this._isContainer = false;
this._isModal = false;
}
+ this.emitter.emit('metadata_change');
+ }
+
+ refreshMetadata() {
+ this.parseMetadata(this.getMetadata());
}
private transformMetadata(metadta: ComponentMetadata): TransformedComponentMetadata {
@@ -297,6 +305,13 @@ export class ComponentMeta {
return true;
}
+ onMetadataChange(fn: (args: any) => void): () => void {
+ this.emitter.on('metadata_change', fn);
+ return () => {
+ this.emitter.removeListener('metadata_change', fn);
+ };
+ }
+
// compatiable vision
prototype?: any;
}
@@ -436,6 +451,21 @@ const builtinComponentActions: ComponentAction[] = [
if (parent) {
const newNode = doc.insertNode(parent, node, index + 1, true);
newNode.select();
+ const { isRGL, rglNode } = node.getRGL();
+ if (isRGL) {
+ // 复制layout信息
+ let layout = rglNode.getPropValue('layout') || [];
+ let curLayout = layout.filter((item) => item.i === node.getPropValue('fieldId'));
+ if (curLayout && curLayout[0]) {
+ layout.push({
+ ...curLayout[0],
+ i: newNode.getPropValue('fieldId'),
+ });
+ rglNode.setPropValue('layout', layout);
+ // 如果是磁贴块复制,则需要滚动到影响位置
+ setTimeout(() => newNode.document.simulator?.scrollToNode(newNode), 10);
+ }
+ }
}
},
},
diff --git a/packages/designer/src/designer/builtin-hotkey.ts b/packages/designer/src/designer/builtin-hotkey.ts
index 1ea18c9ad..73cc409b4 100644
--- a/packages/designer/src/designer/builtin-hotkey.ts
+++ b/packages/designer/src/designer/builtin-hotkey.ts
@@ -6,7 +6,9 @@ import clipboard from './clipboard';
function isInLiveEditing() {
if (globalContext.has(Editor)) {
- return Boolean(globalContext.get(Editor).get('designer')?.project?.simulator?.liveEditing?.editing);
+ return Boolean(
+ globalContext.get(Editor).get('designer')?.project?.simulator?.liveEditing?.editing,
+ );
}
}
diff --git a/packages/designer/src/designer/designer.ts b/packages/designer/src/designer/designer.ts
index bab9d20ab..3d885088e 100644
--- a/packages/designer/src/designer/designer.ts
+++ b/packages/designer/src/designer/designer.ts
@@ -13,7 +13,14 @@ import {
} from '@ali/lowcode-types';
import { megreAssets, AssetsJson } from '@ali/lowcode-utils';
import { Project } from '../project';
-import { Node, DocumentModel, insertChildren, isRootNode, ParentalNode, TransformStage } from '../document';
+import {
+ Node,
+ DocumentModel,
+ insertChildren,
+ isRootNode,
+ ParentalNode,
+ TransformStage,
+} from '../document';
import { ComponentMeta } from '../component-meta';
import { INodeSelector, Component } from '../simulator';
import { Scroller, IScrollable } from './scroller';
@@ -125,7 +132,7 @@ export class Designer {
} else if (isDragNodeDataObject(dragObject)) {
// process nodeData
const nodeData = Array.isArray(dragObject.data) ? dragObject.data : [dragObject.data];
- const isNotNodeSchema = nodeData.find(item => !isNodeSchema(item));
+ const isNotNodeSchema = nodeData.find((item) => !isNodeSchema(item));
if (isNotNodeSchema) {
return;
}
@@ -213,7 +220,11 @@ export class Designer {
}
const { currentSelection } = this;
// TODO: 避免选中 Page 组件,默认选中第一个子节点;新增规则 或 判断 Live 模式
- if (currentSelection && currentSelection.selected.length === 0 && this.simulatorProps?.designMode === 'live') {
+ if (
+ currentSelection &&
+ currentSelection.selected.length === 0 &&
+ this.simulatorProps?.designMode === 'live'
+ ) {
const rootNodeChildrens = this.currentDocument.getRoot().getChildren().children;
if (rootNodeChildrens.length > 0) {
currentSelection.select(rootNodeChildrens[0].id);
@@ -301,12 +312,18 @@ export class Designer {
/**
* 获得合适的插入位置
*/
- getSuitableInsertion(insertNode?: Node | NodeSchema | NodeSchema[]): { target: ParentalNode; index?: number } | null {
+ getSuitableInsertion(
+ insertNode?: Node | NodeSchema | NodeSchema[],
+ ): { target: ParentalNode; index?: number } | null {
const activedDoc = this.project.currentDocument;
if (!activedDoc) {
return null;
}
- if (Array.isArray(insertNode) && isNodeSchema(insertNode[0]) && this.getComponentMeta(insertNode[0].componentName).isModal) {
+ if (
+ Array.isArray(insertNode) &&
+ isNodeSchema(insertNode[0]) &&
+ this.getComponentMeta(insertNode[0].componentName).isModal
+ ) {
return {
target: activedDoc.rootNode as ParentalNode,
};
@@ -355,7 +372,10 @@ export class Designer {
if (props.suspensed !== this.props.suspensed && props.suspensed != null) {
this.suspensed = props.suspensed;
}
- if (props.componentMetadatas !== this.props.componentMetadatas && props.componentMetadatas != null) {
+ if (
+ props.componentMetadatas !== this.props.componentMetadatas &&
+ props.componentMetadatas != null
+ ) {
this.buildComponentMetasMap(props.componentMetadatas);
}
} else {
@@ -477,7 +497,10 @@ export class Designer {
return this.props?.globalComponentActions || null;
}
- getComponentMeta(componentName: string, generateMetadata?: () => ComponentMetadata | null): ComponentMeta {
+ getComponentMeta(
+ componentName: string,
+ generateMetadata?: () => ComponentMetadata | null,
+ ): ComponentMeta {
if (this._componentMetasMap.has(componentName)) {
return this._componentMetasMap.get(componentName)!;
}
@@ -558,4 +581,8 @@ export class Designer {
}
export type PropsReducerContext = { stage: TransformStage };
-export type PropsReducer = (props: CompositeObject, node: Node, ctx?: PropsReducerContext) => CompositeObject;
+export type PropsReducer = (
+ props: CompositeObject,
+ node: Node,
+ ctx?: PropsReducerContext,
+) => CompositeObject;
diff --git a/packages/designer/src/designer/dragon.ts b/packages/designer/src/designer/dragon.ts
index b53b6cf20..eb08e7b4a 100644
--- a/packages/designer/src/designer/dragon.ts
+++ b/packages/designer/src/designer/dragon.ts
@@ -4,7 +4,7 @@ import { NodeSchema } from '@ali/lowcode-types';
import { setNativeSelection, cursor } from '@ali/lowcode-utils';
import { DropLocation } from './location';
import { Node, DocumentModel } from '../document';
-import { ISimulatorHost, isSimulatorHost } from '../simulator';
+import { ISimulatorHost, isSimulatorHost, NodeInstance, ComponentInstance } from '../simulator';
import { Designer } from './designer';
export interface LocateEvent {
@@ -72,6 +72,10 @@ export interface ISensor {
* 取消激活
*/
deactiveSensor(): void;
+ /**
+ * 获取节点实例
+ */
+ getNodeInstanceFromElement(e: Element | null): NodeInstance | null;
}
export type DragObject = DragNodeObject | DragNodeDataObject | DragAnyObject;
@@ -126,7 +130,9 @@ export function isShaken(e1: MouseEvent | DragEvent, e2: MouseEvent | DragEvent)
if (e1.target !== e2.target) {
return true;
}
- return Math.pow(e1.clientY - e2.clientY, 2) + Math.pow(e1.clientX - e2.clientX, 2) > SHAKE_DISTANCE;
+ return (
+ Math.pow(e1.clientY - e2.clientY, 2) + Math.pow(e1.clientX - e2.clientX, 2) > SHAKE_DISTANCE
+ );
}
function isInvalidPoint(e: any, last: any): boolean {
@@ -199,6 +205,8 @@ export class Dragon {
@obx.ref private _dragging = false;
+ @obx.ref private _canDrop = false;
+
get dragging(): boolean {
return this._dragging;
}
@@ -239,17 +247,26 @@ export class Dragon {
* @param dragObject 拖拽对象
* @param boostEvent 拖拽初始时事件
*/
- boost(dragObject: DragObject, boostEvent: MouseEvent | DragEvent) {
+ boost(dragObject: DragObject, boostEvent: MouseEvent | DragEvent, isFromRGLNode?: boolean) {
const { designer } = this;
const masterSensors = this.getMasterSensors();
const handleEvents = makeEventsHandler(boostEvent, masterSensors);
const newBie = !isDragNodeObject(dragObject);
- const forceCopyState = isDragNodeObject(dragObject) && dragObject.nodes.some((node) => node.isSlot());
+ const forceCopyState =
+ isDragNodeObject(dragObject) && dragObject.nodes.some((node) => node.isSlot());
const isBoostFromDragAPI = isDragEvent(boostEvent);
let lastSensor: ISensor | undefined;
this._dragging = false;
+ const getRGL = (e: MouseEvent | DragEvent) => {
+ const locateEvent = createLocateEvent(e);
+ const sensor = chooseSensor(locateEvent);
+ if (!sensor || !sensor.getNodeInstanceFromElement) return {};
+ const nodeInst = sensor.getNodeInstanceFromElement(e.target as Element);
+ return nodeInst?.node?.getRGL() || {};
+ };
+
const checkesc = (e: KeyboardEvent) => {
if (e.keyCode === 27) {
designer.clearLocation();
@@ -301,9 +318,26 @@ export class Dragon {
return;
}
lastArrive = e;
-
const locateEvent = createLocateEvent(e);
const sensor = chooseSensor(locateEvent);
+ const { isRGL, rglNode } = getRGL(e);
+ if (isRGL) {
+ this._canDrop = !!sensor?.locate(locateEvent);
+ if (this._canDrop) {
+ this.emitter.emit('rgl.add.placeholder', {
+ rglNode,
+ node: locateEvent.dragObject.nodes[0],
+ event: e,
+ });
+ designer.clearLocation();
+ this.clearState();
+ this.emitter.emit('drag', locateEvent);
+ return;
+ }
+ } else {
+ this._canDrop = false;
+ this.emitter.emit('rgl.remove.placeholder');
+ }
if (sensor) {
sensor.fixEvent(locateEvent);
sensor.locate(locateEvent);
@@ -363,6 +397,23 @@ export class Dragon {
// end-tail drag process
const over = (e?: any) => {
+ // 发送drop事件
+ if (e) {
+ const { isRGL, rglNode } = getRGL(e);
+ if (isRGL && this._canDrop) {
+ const tarNode = dragObject.nodes[0];
+ if (rglNode.id !== tarNode.id) {
+ // 避免死循环
+ this.emitter.emit('rgl.drop', {
+ rglNode,
+ node: tarNode,
+ });
+ const { selection } = designer.project.currentDocument;
+ selection.select(tarNode.id);
+ }
+ }
+ }
+
/* istanbul ignore next */
if (e && isDragEvent(e)) {
e.preventDefault();
@@ -461,7 +512,10 @@ export class Dragon {
const chooseSensor = (e: LocateEvent) => {
// this.sensors will change on dragstart
const sensors: ISensor[] = (masterSensors as ISensor[]).concat(this.sensors);
- let sensor = e.sensor && e.sensor.isEnter(e) ? e.sensor : sensors.find((s) => s.sensorAvailable && s.isEnter(e));
+ let sensor =
+ e.sensor && e.sensor.isEnter(e)
+ ? e.sensor
+ : sensors.find((s) => s.sensorAvailable && s.isEnter(e));
if (!sensor) {
// TODO: enter some area like componentspanel cancel
if (lastSensor) {
@@ -547,7 +601,7 @@ export class Dragon {
}
private getSimulators() {
- return new Set(this.designer.project.documents.map(doc => doc.simulator));
+ return new Set(this.designer.project.documents.map((doc) => doc.simulator));
}
// #region ======== drag and drop helpers ============
diff --git a/packages/designer/src/designer/setting/setting-prop-entry.ts b/packages/designer/src/designer/setting/setting-prop-entry.ts
index 351af3cfe..5a8a369d1 100644
--- a/packages/designer/src/designer/setting/setting-prop-entry.ts
+++ b/packages/designer/src/designer/setting/setting-prop-entry.ts
@@ -118,6 +118,7 @@ export class SettingPropEntry implements SettingEntry {
* 1 类似值,比如数组长度一样
* 2 单一植
*/
+ /* istanbul ignore next */
@computed get valueState(): number {
if (this.type !== 'field') {
const { getValue } = this.extraProps;
@@ -155,7 +156,6 @@ export class SettingPropEntry implements SettingEntry {
try {
return getValue ? getValue(this, val) : val;
} catch (e) {
- // todo: add log
console.warn(e);
return val;
}
@@ -175,7 +175,7 @@ export class SettingPropEntry implements SettingEntry {
try {
setValue(this, val);
} catch (e) {
- // todo: add log
+ /* istanbul ignore next */
console.warn(e);
}
}
@@ -198,7 +198,7 @@ export class SettingPropEntry implements SettingEntry {
try {
setValue(this, undefined);
} catch (e) {
- // todo: add log
+ /* istanbul ignore next */
console.warn(e);
}
}
@@ -320,7 +320,7 @@ export class SettingPropEntry implements SettingEntry {
return;
}
const v = this.getValue();
- if (isJSExpression(v)) {
+ if (this.isUseVariable()) {
this.setValue(v.mock);
} else {
this.setValue({
diff --git a/packages/designer/src/designer/setting/setting-top-entry.ts b/packages/designer/src/designer/setting/setting-top-entry.ts
index ab09d355c..6e03cc66a 100644
--- a/packages/designer/src/designer/setting/setting-top-entry.ts
+++ b/packages/designer/src/designer/setting/setting-top-entry.ts
@@ -80,6 +80,8 @@ export class SettingTopEntry implements SettingEntry {
// clear fields
this.setupItems();
+
+ this.setupEvents();
}
private setupComponentMeta() {
@@ -120,6 +122,12 @@ export class SettingTopEntry implements SettingEntry {
}
}
+ private setupEvents() {
+ this.componentMeta?.onMetadataChange(() => {
+ this.setupItems();
+ });
+ }
+
/**
* 获取当前属性值
*/
diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts
index d2dede1bc..0bc849f1a 100644
--- a/packages/designer/src/document/node/node.ts
+++ b/packages/designer/src/document/node/node.ts
@@ -110,7 +110,7 @@ export class Node {
/**
* @deprecated
*/
- private _addons: { [key: string]: { exportData: () => any; isProp: boolean; } } = {};
+ private _addons: { [key: string]: { exportData: () => any; isProp: boolean } } = {};
@obx.ref private _parent: ParentalNode | null = null;
@@ -156,8 +156,6 @@ export class Node {
return this.componentMeta.icon;
}
- readonly settingEntry: SettingTopEntry;
-
private isInited = false;
constructor(readonly document: DocumentModel, nodeSchema: Schema, options: any = {}) {
@@ -168,16 +166,17 @@ export class Node {
this.props = new Props(this, {
children: isDOMText(children) || isJSExpression(children) ? children : '',
});
- this.settingEntry = this.document.designer.createSettingEntry([this]);
} else {
// 这里 props 被初始化两次,一次 new,一次 import,new 的实例需要给 propsReducer 的钩子去使用,
// import 是为了使用钩子返回的值,并非完全幂等的操作,部分行为执行两次会有 bug,
// 所以在 props 里会对 new / import 做一些区别化的解析
this.props = new Props(this, props, extras);
- this.settingEntry = this.document.designer.createSettingEntry([this]);
this._children = new NodeChildren(this as ParentalNode, this.initialChildren(children));
this._children.internalInitParent();
- this.props.import(this.upgradeProps(this.initProps(props || {})), this.upgradeProps(extras || {}));
+ this.props.import(
+ this.upgradeProps(this.initProps(props || {})),
+ this.upgradeProps(extras || {}),
+ );
this.setupAutoruns();
}
@@ -185,6 +184,14 @@ export class Node {
this.emitter = new EventEmitter();
}
+ _settingEntry: SettingTopEntry;
+
+ get settingEntry(): SettingTopEntry {
+ if (this._settingEntry) return this._settingEntry;
+ this._settingEntry = this.document.designer.createSettingEntry([this]);
+ return this._settingEntry;
+ }
+
private initProps(props: any): any {
return this.document.designer.transformProps(props, this, TransformStage.Init);
}
@@ -221,6 +228,16 @@ export class Node {
return children || [];
}
+ private _isRGLContainer = false;
+
+ set isRGLContainer(status: boolean) {
+ this._isRGLContainer = status;
+ }
+
+ get isRGLContainer(): boolean {
+ return !!this._isRGLContainer;
+ }
+
isContainer(): boolean {
return this.isParental() && this.componentMeta.isContainer;
}
@@ -335,7 +352,11 @@ export class Node {
/**
* 移除当前节点
*/
- remove(useMutator = true, purge = true, options: NodeRemoveOptions = { suppressRemoveEvent: false }) {
+ remove(
+ useMutator = true,
+ purge = true,
+ options: NodeRemoveOptions = { suppressRemoveEvent: false },
+ ) {
if (this.parent) {
if (!options.suppressRemoveEvent) {
this.document.designer.editor?.emit('node.remove.topLevel', {
@@ -616,15 +637,21 @@ export class Node {
import(data: Schema, checkId = false) {
const { componentName, id, children, props, ...extras } = data;
if (this.isSlot()) {
- foreachReverse(this.children, (subNode: Node) => {
- subNode.remove(true, true);
- }, (iterable, idx) => (iterable as NodeChildren).get(idx));
+ foreachReverse(
+ this.children,
+ (subNode: Node) => {
+ subNode.remove(true, true);
+ },
+ (iterable, idx) => (iterable as NodeChildren).get(idx),
+ );
}
if (this.isParental()) {
this.props.import(props, extras);
(this._children as NodeChildren).import(children, checkId);
} else {
- this.props.get('children', true)!.setValue(isDOMText(children) || isJSExpression(children) ? children : '');
+ this.props
+ .get('children', true)!
+ .setValue(isDOMText(children) || isJSExpression(children) ? children : '');
}
}
@@ -792,7 +819,8 @@ export class Node {
* 是否可执行某action
*/
canPerformAction(action: string): boolean {
- const availableActions = this.componentMeta?.availableActions?.map((action) => action.name) || [];
+ const availableActions =
+ this.componentMeta?.availableActions?.map((action) => action.name) || [];
return availableActions.indexOf(action) >= 0;
}
@@ -854,7 +882,11 @@ export class Node {
return this.children?.onChange(fn);
}
- mergeChildren(remover: () => any, adder: (children: Node[]) => NodeData[] | null, sorter: () => any) {
+ mergeChildren(
+ remover: () => any,
+ adder: (children: Node[]) => NodeData[] | null,
+ sorter: () => any,
+ ) {
this.children?.mergeChildren(remover, adder, sorter);
}
@@ -907,6 +939,21 @@ export class Node {
return this.document;
}
+ /**
+ * 获取磁贴相关信息
+ */
+ getRGL() {
+ const isContainerNode = this.isContainer();
+ const isEmptyNode = this.isEmpty();
+ const isRGLContainerNode = this.isRGLContainer;
+ const isRGLNode = this.getParent()?.isRGLContainer;
+ const isRGL = isRGLContainerNode || (isRGLNode && (!isContainerNode || !isEmptyNode));
+ let rglNode = isRGLContainerNode ? this : isRGL ? this?.getParent() : {};
+ return { isContainerNode, isEmptyNode, isRGLContainerNode, isRGLNode, isRGL, rglNode };
+ }
+
+ /**
+
/**
* @deprecated
*/
@@ -933,9 +980,11 @@ export class Node {
return { container: dropElement, ref };
}
const rootCanDropIn = this.componentMeta?.prototype?.options?.canDropIn;
- if (rootCanDropIn === undefined
- || rootCanDropIn === true
- || (typeof rootCanDropIn === 'function' && rootCanDropIn(node))) {
+ if (
+ rootCanDropIn === undefined ||
+ rootCanDropIn === true ||
+ (typeof rootCanDropIn === 'function' && rootCanDropIn(node))
+ ) {
return { container: this, ref };
}
// 假如最后找不到合适位置,返回 null 阻止继续插入节点
@@ -944,9 +993,11 @@ export class Node {
const canDropIn = this.componentMeta?.prototype?.options?.canDropIn;
if (this.isContainer()) {
- if (canDropIn === undefined ||
+ if (
+ canDropIn === undefined ||
(typeof canDropIn === 'boolean' && canDropIn) ||
- (typeof canDropIn === 'function' && canDropIn(node))) {
+ (typeof canDropIn === 'function' && canDropIn(node))
+ ) {
return { container: this, ref };
}
}
@@ -1044,6 +1095,10 @@ export function isRootNode(node: Node): node is RootNode {
return node && node.isRoot();
}
+export function isLowCodeComponent(node: Node): boolean {
+ return node.componentMeta?.getMetadata().devMode === 'lowcode';
+}
+
export function getZLevelTop(child: Node, zLevel: number): Node | null {
let l = child.zLevel;
if (l < zLevel || zLevel < 0) {
@@ -1113,7 +1168,12 @@ export function comparePosition(node1: Node, node2: Node): PositionNO {
return PositionNO.BeforeOrAfter;
}
-export function insertChild(container: ParentalNode, thing: Node | NodeData, at?: number | null, copy?: boolean): Node {
+export function insertChild(
+ container: ParentalNode,
+ thing: Node | NodeData,
+ at?: number | null,
+ copy?: boolean,
+): Node {
let node: Node;
if (isNode(thing) && (copy || thing.isSlot())) {
thing = thing.export(TransformStage.Clone);
diff --git a/packages/designer/src/document/node/props/prop.ts b/packages/designer/src/document/node/props/prop.ts
index 79a3564f9..f8237e8f0 100644
--- a/packages/designer/src/document/node/props/prop.ts
+++ b/packages/designer/src/document/node/props/prop.ts
@@ -98,7 +98,7 @@ export class Prop implements IPropParent {
return this.export(TransformStage.Serilize);
}
- export(stage: TransformStage = TransformStage.Save): CompositeValue | UNSET {
+ export(stage: TransformStage = TransformStage.Save): CompositeValue {
stage = compatStage(stage);
const type = this._type;
if (stage === TransformStage.Render && this.key === '___condition___') {
@@ -110,7 +110,6 @@ export class Prop implements IPropParent {
}
if (type === 'unset') {
- // return UNSET; @康为 之后 review 下这块改造
return undefined;
}
@@ -147,10 +146,6 @@ export class Prop implements IPropParent {
const maps: any = {};
this.items!.forEach((prop, key) => {
const v = prop.export(stage);
- // if (v !== UNSET) {
- // maps[prop.key == null ? key : prop.key] = v;
- // }
- // @康为 之后 review 下这块改造
maps[prop.key == null ? key : prop.key] = v;
});
return maps;
@@ -161,12 +156,9 @@ export class Prop implements IPropParent {
return this._value;
}
return this.items!.map((prop) => {
- const v = prop.export(stage);
- return v === UNSET ? undefined : v;
+ return prop.export(stage);
});
}
-
- return undefined;
}
private _code: string | null = null;
@@ -246,7 +238,7 @@ export class Prop implements IPropParent {
} else {
this._type = 'map';
}
- } else {
+ } /* istanbul ignore next */ else {
this._type = 'expression';
this._value = {
type: 'JSExpression',
@@ -267,11 +259,7 @@ export class Prop implements IPropParent {
}
@computed getValue(): CompositeValue {
- const v = this.export(TransformStage.Serilize);
- if (v === UNSET) {
- return undefined;
- }
- return v;
+ return this.export(TransformStage.Serilize);
}
private dispose() {
@@ -563,7 +551,7 @@ export class Prop implements IPropParent {
items.push(prop);
maps.set(key, prop);
}
- } else {
+ } /* istanbul ignore next */ else {
return null;
}
diff --git a/packages/designer/src/document/node/props/props.ts b/packages/designer/src/document/node/props/props.ts
index 2d24e477d..1e900710f 100644
--- a/packages/designer/src/document/node/props/props.ts
+++ b/packages/designer/src/document/node/props/props.ts
@@ -161,8 +161,9 @@ export class Props implements IPropParent {
/**
* @deprecated
*/
+ /* istanbul ignore next */
private transformToStatic(props: any) {
- let transducers = this.owner.componentMeta.prototype?.options?.transducers;
+ let transducers = this.owner.componentMeta?.prototype?.options?.transducers;
if (!transducers) {
return props;
}
diff --git a/packages/designer/tests/builtin-simulator/host.test.ts b/packages/designer/tests/builtin-simulator/host.test.ts
index 9b4121267..ab96b20ec 100644
--- a/packages/designer/tests/builtin-simulator/host.test.ts
+++ b/packages/designer/tests/builtin-simulator/host.test.ts
@@ -408,7 +408,7 @@ describe('Host 测试', () => {
host.setupContextMenu();
host.getNodeInstanceFromElement = () => {
return {
- node: { componentMeta: { componentName: 'Button' } },
+ node: { componentMeta: { componentName: 'Button', getMetadata() { return {} } } },
};
};
const mockFn = jest.fn();
@@ -428,7 +428,7 @@ describe('Host 测试', () => {
dispatchEvent() {},
};
- // 非法分支测试
+ // 非法分支测试
host.mountContentFrame();
expect(host._iframe).toBeUndefined();
diff --git a/packages/designer/tests/designer/setting/setting-prop-entry.test.ts b/packages/designer/tests/designer/setting/setting-prop-entry.test.ts
index 655dea54c..e5bb5f6c5 100644
--- a/packages/designer/tests/designer/setting/setting-prop-entry.test.ts
+++ b/packages/designer/tests/designer/setting/setting-prop-entry.test.ts
@@ -1,8 +1,11 @@
+// @ts-nocheck
import set from 'lodash/set';
import cloneDeep from 'lodash/cloneDeep';
import '../../fixtures/window';
import { Editor } from '@ali/lowcode-editor-core';
import { Project } from '../../../src/project/project';
+import { SettingTopEntry } from '../../../src/designer/setting/setting-top-entry';
+import { SettingPropEntry } from '../../../src/designer/setting/setting-prop-entry';
import { Node } from '../../../src/document/node/node';
import { Designer } from '../../../src/designer/designer';
import formSchema from '../../../fixtures/schema/form';
@@ -28,6 +31,119 @@ describe('setting-prop-entry 测试', () => {
doc = null;
});
+ describe('纯粹的 UnitTest', () => {
+ let mockNode: Node;
+ let mockTopEntry: SettingTopEntry;
+ beforeEach(() => {
+ mockNode = new Node(designer.currentDocument, {
+ componentName: 'Button',
+ props: {
+ a: 'str',
+ b: 222,
+ obj: {
+ x: 1,
+ },
+ jse: {
+ type: 'JSExpression',
+ value: 'state.a',
+ mock: 111,
+ }
+ },
+ });
+ mockTopEntry = new SettingTopEntry(editor, [mockNode]);
+ });
+ afterEach(() => {
+ mockNode = null;
+ mockTopEntry = null;
+ });
+
+ it('常规方法', () => {
+ // type: group 类型
+ const prop = new SettingPropEntry(mockTopEntry, 'xGroup', 'group');
+ expect(prop.setKey('xxx')).toBeUndefined();
+ expect(prop.remove()).toBeUndefined();
+
+ const prop2 = new SettingPropEntry(mockTopEntry, '#xGroup');
+ expect(prop2.setKey('xxx')).toBeUndefined();
+ expect(prop2.remove()).toBeUndefined();
+
+ expect(prop.getVariableValue()).toBe('');
+ });
+
+ it('setValue / getValue / onValueChange', () => {
+ // 获取已有的 prop
+ const prop1 = mockTopEntry.getProp('a');
+ prop1.extraProps = {
+ getValue: (prop, val) => `prefix ${val}`,
+ setValue: (prop, val) => { prop.setValue(`modified ${val}`, false, false, { disableMutator: true }) },
+ defaultValue: 'default',
+ };
+
+ expect(prop1.getDefaultValue()).toBe('default');
+ expect(prop1.getValue()).toBe('prefix str');
+
+ // disableMutator: true
+ prop1.setValue('bbb', false, false, { disableMutator: true });
+ expect(prop1.getValue()).toBe('prefix bbb');
+
+ // disableMutator: false
+ prop1.setValue('bbb');
+ expect(prop1.getValue()).toBe('prefix modified bbb');
+
+ const mockFn3 = jest.fn();
+ const prop2 = mockTopEntry.getProp('obj');
+ const prop3 = prop2.get('x');
+ const offFn = prop3.onValueChange(mockFn3);
+ expect(prop3.getValue()).toBe(1);
+ prop3.setValue(2);
+ expect(mockFn3).toHaveBeenCalled();
+
+ offFn();
+ prop3.setValue(3);
+ mockFn3.mockClear();
+ expect(mockFn3).toHaveBeenCalledTimes(0);
+
+ const prop4 = mockTopEntry.getProp('b');
+ prop4.extraProps = {
+ getValue: () => { throw 'error'; },
+ };
+ expect(prop4.getValue()).toBe(222);
+ });
+
+ it('clearValue', () => {
+ const prop1 = mockTopEntry.getProp('a');
+ prop1.clearValue();
+ expect(prop1.getValue()).toBeUndefined();
+
+ const mockFn = jest.fn();
+ prop1.extraProps = {
+ setValue: mockFn,
+ };
+ prop1.clearValue();
+ expect(mockFn).toHaveBeenCalled();
+ });
+
+ it('getVariableValue/ setUseVariable / isUseVariable / getMockOrValue', () => {
+ const prop1 = mockTopEntry.getProp('jse');
+
+ expect(prop1.isUseVariable()).toBeTruthy();
+ expect(prop1.useVariable).toBeTruthy();
+
+ expect(prop1.getMockOrValue()).toEqual(111);
+ expect(prop1.getVariableValue()).toEqual('state.a');
+
+ prop1.setUseVariable(false);
+ expect(prop1.getValue()).toEqual(111);
+ prop1.setUseVariable(true);
+ expect(prop1.getValue()).toEqual({
+ type: 'JSExpression',
+ value: '',
+ mock: 111,
+ });
+ prop1.setUseVariable(true);
+ });
+ });
+
describe('node 构造函数生成 settingEntry', () => {
it('常规方法测试', () => {
const divNode = doc?.getNode('div');
@@ -81,9 +197,7 @@ describe('setting-prop-entry 测试', () => {
expect(divNode?.getProp('behavior').getValue()).toBeUndefined();
});
- it.skip('type: group 场景测试', () => {
-
- });
+ it.skip('type: group 场景测试', () => {});
it('JSExpression 类型的 prop', () => {
designer.createComponentMeta(divMeta);
diff --git a/packages/designer/tests/designer/setting/setting-top-entry.test.ts b/packages/designer/tests/designer/setting/setting-top-entry.test.ts
index 94fdbab90..b0dc27012 100644
--- a/packages/designer/tests/designer/setting/setting-top-entry.test.ts
+++ b/packages/designer/tests/designer/setting/setting-top-entry.test.ts
@@ -1,3 +1,4 @@
+// @ts-nocheck
import set from 'lodash/set';
import cloneDeep from 'lodash/cloneDeep';
import '../../fixtures/window';
@@ -75,6 +76,31 @@ describe('setting-top-entry 测试', () => {
settingEntry.getValue();
});
+ it('onMetadataChange', () => {
+ designer.createComponentMeta(divMeta);
+ designer.project.open(settingSchema);
+ const { currentDocument } = designer.project;
+ const divNode = currentDocument?.getNode('div') as Node;
+
+ const { settingEntry } = divNode!;
+ const mockFn = jest.fn();
+ settingEntry.componentMeta.onMetadataChange(mockFn);
+ settingEntry.componentMeta.refreshMetadata();
+ expect(mockFn).toHaveBeenCalled();
+ });
+
+ it.skip('setupItems - customView', () => {
+ designer.createComponentMeta(divMeta);
+ designer.project.open(settingSchema);
+ const { currentDocument } = designer.project;
+ const divNode = currentDocument?.getNode('div') as Node;
+
+ const { settingEntry } = divNode;
+ // 模拟将第一个配置变成 react funcional component
+ settingEntry.componentMeta.getMetadata().combined[0].items[0] = props => props.xx;
+ settingEntry.setupItems();
+ });
+
it('清理方法测试', () => {
designer.createComponentMeta(divMeta);
designer.project.open(settingSchema);
diff --git a/packages/designer/tests/document/node/node.add.test.ts b/packages/designer/tests/document/node/node.add.test.ts
index 200fe524f..c9dd53d1f 100644
--- a/packages/designer/tests/document/node/node.add.test.ts
+++ b/packages/designer/tests/document/node/node.add.test.ts
@@ -64,6 +64,10 @@ describe('schema 生成节点模型测试', () => {
const exportSchema = currentDocument?.export(1);
expect(getIdsFromSchema(exportSchema).length).toBe(expectedNodeCnt);
+ nodesMap.forEach(node => {
+ // 触发 getter
+ node.settingEntry;
+ });
expect(mockCreateSettingEntry).toBeCalledTimes(expectedNodeCnt);
});
diff --git a/packages/designer/tests/document/node/props/prop.test.ts b/packages/designer/tests/document/node/props/prop.test.ts
index 00ab084e5..3c01de7ec 100644
--- a/packages/designer/tests/document/node/props/prop.test.ts
+++ b/packages/designer/tests/document/node/props/prop.test.ts
@@ -1,16 +1,32 @@
+// @ts-nocheck
import '../../../fixtures/window';
-import { set, delayObxTick } from '../../../utils';
-import { Editor } from '@ali/lowcode-editor-core';
-import { Props } from '../../../../src/document/node/props/props';
+import { delayObxTick } from '../../../utils';
+import { Editor, engineConfig } from '@ali/lowcode-editor-core';
import { Designer } from '../../../../src/designer/designer';
-import { Project } from '../../../../src/project/project';
import { DocumentModel } from '../../../../src/document/document-model';
import { Prop, isProp, isValidArrayIndex } from '../../../../src/document/node/props/prop';
import { TransformStage } from '@ali/lowcode-types';
-
+const slotNodeImportMockFn = jest.fn();
+const slotNodeRemoveMockFn = jest.fn();
const mockedOwner = {
componentName: 'Div',
+ addSlot() {},
+ document: {
+ createNode(schema) {
+ return {
+ ...schema,
+ addSlot() {},
+ internalSetSlotFor() {},
+ import: slotNodeImportMockFn,
+ export() {
+ return schema;
+ },
+ remove: slotNodeRemoveMockFn,
+ };
+ },
+ designer: {},
+ },
};
const mockedPropsInst = {
@@ -32,7 +48,19 @@ describe('Prop 类测试', () => {
numProp = new Prop(mockedPropsInst, 1, 'numProp');
nullProp = new Prop(mockedPropsInst, null, 'nullProp');
expProp = new Prop(mockedPropsInst, { type: 'JSExpression', value: 'state.haha' }, 'expProp');
- // slotProp = new Prop(mockedPropsInst, { type: 'JSSlot', value: [{ componentName: 'Button' }] }, 'slotProp');
+ slotProp = new Prop(
+ mockedPropsInst,
+ {
+ type: 'JSSlot',
+ title: '测试 slot',
+ name: 'testSlot',
+ params: { a: 1 },
+ value: [{ componentName: 'Button' }],
+ },
+ 'slotProp',
+ );
+ slotNodeImportMockFn.mockClear();
+ slotNodeRemoveMockFn.mockClear();
});
afterEach(() => {
boolProp.purge();
@@ -40,7 +68,7 @@ describe('Prop 类测试', () => {
numProp.purge();
nullProp.purge();
expProp.purge();
- // slotProp.purge();
+ slotProp.purge();
});
it('consturctor / getProps / getNode', () => {
@@ -60,6 +88,7 @@ describe('Prop 类测试', () => {
expect(numProp.set()).toBeNull();
expect(numProp.has()).toBeFalsy();
+ expect(numProp.path).toEqual(['numProp']);
});
it('getValue / getAsString / setValue', () => {
@@ -121,7 +150,28 @@ describe('Prop 类测试', () => {
expect(
new Prop(mockedPropsInst, false, '___condition___').export(TransformStage.Render),
).toBeTruthy();
- // console.log(slotProp.export(TransformStage.Render));
+ engineConfig.set('enableCondition', true);
+ expect(
+ new Prop(mockedPropsInst, false, '___condition___').export(TransformStage.Render),
+ ).toBeFalsy();
+ expect(slotProp.export(TransformStage.Render)).toEqual({
+ type: 'JSSlot',
+ params: { a: 1 },
+ value: {
+ componentName: 'Slot',
+ title: '测试 slot',
+ name: 'testSlot',
+ params: { a: 1 },
+ children: [{ componentName: 'Button' }],
+ },
+ });
+ expect(slotProp.export(TransformStage.Save)).toEqual({
+ type: 'JSSlot',
+ params: { a: 1 },
+ value: [{ componentName: 'Button' }],
+ title: '测试 slot',
+ name: 'testSlot',
+ });
});
it('compare', () => {
@@ -145,6 +195,21 @@ describe('Prop 类测试', () => {
boolProp.purge();
});
+ it('slot', () => {
+ // 更新 slot
+ slotProp.setValue({
+ type: 'JSSlot',
+ value: [{
+ componentName: 'Form',
+ }]
+ });
+ expect(slotNodeImportMockFn).toBeCalled();
+
+ // 节点类型转换
+ slotProp.setValue(true);
+ expect(slotNodeRemoveMockFn).toBeCalled();
+ });
+
it('迭代器 / map / forEach', () => {
const mockedFn = jest.fn();
for (const item of strProp) {
@@ -153,13 +218,13 @@ describe('Prop 类测试', () => {
expect(mockedFn).not.toHaveBeenCalled();
mockedFn.mockClear();
- strProp.forEach(item => {
+ strProp.forEach((item) => {
mockedFn();
});
expect(mockedFn).not.toHaveBeenCalled();
mockedFn.mockClear();
- strProp.map(item => {
+ strProp.map((item) => {
return mockedFn();
});
expect(mockedFn).not.toHaveBeenCalled();
@@ -201,7 +266,6 @@ describe('Prop 类测试', () => {
z2: 'str',
});
-
expect(prop.getPropValue('a')).toBe(1);
prop.setPropValue('a', 2);
expect(prop.getPropValue('a')).toBe(2);
@@ -283,13 +347,13 @@ describe('Prop 类测试', () => {
expect(mockedFn).toHaveBeenCalledTimes(5);
mockedFn.mockClear();
- prop.forEach(item => {
+ prop.forEach((item) => {
mockedFn();
});
expect(mockedFn).toHaveBeenCalledTimes(5);
mockedFn.mockClear();
- prop.map(item => {
+ prop.map((item) => {
return mockedFn();
});
expect(mockedFn).toHaveBeenCalledTimes(5);
@@ -297,6 +361,7 @@ describe('Prop 类测试', () => {
});
it('dispose', () => {
+ prop.items;
prop.dispose();
expect(prop._items).toBeNull();
@@ -321,9 +386,15 @@ describe('Prop 类测试', () => {
expect(prop.get(2).getValue()).toBe('haha');
expect(prop.getAsString()).toBe('');
+
+ prop.unset();
+ prop.set(0, true);
+ expect(prop.set('x', 'invalid')).toBeNull();
+ expect(prop.get(0).getValue()).toBeTruthy();
});
it('export', () => {
+ expect(prop.export()).toEqual([1, true, 'haha']);
// 触发构造
prop.items;
expect(prop.export()).toEqual([1, true, 'haha']);
@@ -351,18 +422,22 @@ describe('Prop 类测试', () => {
const designer = new Designer({ editor });
const doc = new DocumentModel(designer.project, {
componentName: 'Page',
- children: [{
- id: 'div',
- componentName: 'Div',
- }],
+ children: [
+ {
+ id: 'div',
+ componentName: 'Div',
+ },
+ ],
});
const div = doc.getNode('div');
const slotProp = new Prop(div?.getProps(), {
type: 'JSSlot',
- value: [{
- componentName: 'Button',
- }],
+ value: [
+ {
+ componentName: 'Button',
+ },
+ ],
});
expect(slotProp.slotNode?.componentName).toBe('Slot');
diff --git a/packages/designer/tests/document/node/props/props.test.ts b/packages/designer/tests/document/node/props/props.test.ts
index 56597ecc2..eb49568a5 100644
--- a/packages/designer/tests/document/node/props/props.test.ts
+++ b/packages/designer/tests/document/node/props/props.test.ts
@@ -1,4 +1,4 @@
-
+// @ts-nocheck
import '../../../fixtures/window';
import { set, delayObxTick } from '../../../utils';
import { Editor } from '@ali/lowcode-editor-core';
diff --git a/packages/designer/tests/document/node/props/value-to-source.test.ts b/packages/designer/tests/document/node/props/value-to-source.test.ts
index 2694211e8..43ed19b2a 100644
--- a/packages/designer/tests/document/node/props/value-to-source.test.ts
+++ b/packages/designer/tests/document/node/props/value-to-source.test.ts
@@ -1,3 +1,4 @@
+// @ts-nocheck
import '../../../fixtures/silent-console';
import { getSource, valueToSource } from '../../../../src/document/node/props/value-to-source';
diff --git a/packages/designer/tests/project/project.test.ts b/packages/designer/tests/project/project.test.ts
index 1fa17f8e4..6f2ddddb5 100644
--- a/packages/designer/tests/project/project.test.ts
+++ b/packages/designer/tests/project/project.test.ts
@@ -59,6 +59,10 @@ describe('schema 生成节点模型测试', () => {
const exportSchema = currentDocument?.export(1);
expect(getIdsFromSchema(exportSchema).length).toBe(expectedNodeCnt);
+ nodesMap.forEach(node => {
+ // 触发 getter
+ node.settingEntry;
+ });
expect(mockCreateSettingEntry).toBeCalledTimes(expectedNodeCnt);
});
@@ -77,6 +81,10 @@ describe('schema 生成节点模型测试', () => {
const exportSchema = currentDocument?.export(1);
expect(getIdsFromSchema(exportSchema).length).toBe(expectedNodeCnt);
+ nodesMap.forEach(node => {
+ // 触发 getter
+ node.settingEntry;
+ });
expect(mockCreateSettingEntry).toBeCalledTimes(expectedNodeCnt);
});
diff --git a/packages/editor-core/package.json b/packages/editor-core/package.json
index afca8834e..02912993e 100644
--- a/packages/editor-core/package.json
+++ b/packages/editor-core/package.json
@@ -1,6 +1,6 @@
{
"name": "@ali/lowcode-editor-core",
- "version": "1.0.55",
+ "version": "1.0.56",
"description": "Core Api for Ali lowCode engine",
"license": "MIT",
"main": "lib/index.js",
@@ -13,8 +13,8 @@
"build": "build-scripts build --skip-demo"
},
"dependencies": {
- "@ali/lowcode-types": "1.0.55",
- "@ali/lowcode-utils": "1.0.55",
+ "@ali/lowcode-types": "1.0.56",
+ "@ali/lowcode-utils": "1.0.56",
"@alifd/next": "^1.19.16",
"@recore/obx": "^1.0.9",
"@recore/obx-react": "^1.0.8",
diff --git a/packages/editor-preset-general/package.json b/packages/editor-preset-general/package.json
index 281e2c9b0..d5a669f1e 100644
--- a/packages/editor-preset-general/package.json
+++ b/packages/editor-preset-general/package.json
@@ -1,6 +1,6 @@
{
"name": "@ali/lowcode-editor-preset-general",
- "version": "1.0.55",
+ "version": "1.0.56",
"description": "Ali General Editor Preset",
"main": "lib/index.js",
"private": true,
@@ -14,12 +14,12 @@
},
"license": "MIT",
"dependencies": {
- "@ali/lowcode-editor-core": "1.0.55",
- "@ali/lowcode-editor-skeleton": "1.0.55",
- "@ali/lowcode-plugin-designer": "1.0.55",
- "@ali/lowcode-plugin-outline-pane": "1.0.55",
- "@ali/lowcode-types": "1.0.55",
- "@ali/lowcode-utils": "1.0.55",
+ "@ali/lowcode-editor-core": "1.0.56",
+ "@ali/lowcode-editor-skeleton": "1.0.56",
+ "@ali/lowcode-plugin-designer": "1.0.56",
+ "@ali/lowcode-plugin-outline-pane": "1.0.56",
+ "@ali/lowcode-types": "1.0.56",
+ "@ali/lowcode-utils": "1.0.56",
"@alifd/next": "^1.19.12",
"@alife/theme-lowcode-dark": "^0.1.0",
"@alife/theme-lowcode-light": "^0.1.0",
diff --git a/packages/editor-skeleton/package.json b/packages/editor-skeleton/package.json
index a64ac2e17..fe517ad60 100644
--- a/packages/editor-skeleton/package.json
+++ b/packages/editor-skeleton/package.json
@@ -1,6 +1,6 @@
{
"name": "@ali/lowcode-editor-skeleton",
- "version": "1.0.55",
+ "version": "1.0.56",
"description": "alibaba lowcode editor skeleton",
"main": "lib/index.js",
"module": "es/index.js",
@@ -17,10 +17,10 @@
"editor"
],
"dependencies": {
- "@ali/lowcode-designer": "1.0.55",
- "@ali/lowcode-editor-core": "1.0.55",
- "@ali/lowcode-types": "1.0.55",
- "@ali/lowcode-utils": "1.0.55",
+ "@ali/lowcode-designer": "1.0.56",
+ "@ali/lowcode-editor-core": "1.0.56",
+ "@ali/lowcode-types": "1.0.56",
+ "@ali/lowcode-utils": "1.0.56",
"@ali/ve-icons": "latest",
"@ali/ve-less-variables": "^2.0.0",
"@alifd/next": "^1.20.12",
diff --git a/packages/engine/package.json b/packages/engine/package.json
index 3c6576546..4e346c917 100644
--- a/packages/engine/package.json
+++ b/packages/engine/package.json
@@ -1,6 +1,6 @@
{
"name": "@ali/lowcode-engine",
- "version": "1.0.55",
+ "version": "1.0.56",
"description": "Universal API for AliLowCode engine",
"main": "lib/engine-core.js",
"module": "es/engine-core.js",
@@ -18,14 +18,14 @@
},
"license": "MIT",
"dependencies": {
- "@ali/lowcode-designer": "1.0.55",
- "@ali/lowcode-editor-core": "1.0.55",
+ "@ali/lowcode-designer": "1.0.56",
+ "@ali/lowcode-editor-core": "1.0.56",
"@ali/lowcode-editor-setters": "1.0.30",
- "@ali/lowcode-editor-skeleton": "1.0.55",
+ "@ali/lowcode-editor-skeleton": "1.0.56",
"@ali/lowcode-engine-ext": "^1.0.0",
- "@ali/lowcode-plugin-designer": "1.0.55",
- "@ali/lowcode-plugin-outline-pane": "1.0.55",
- "@ali/lowcode-utils": "1.0.55",
+ "@ali/lowcode-plugin-designer": "1.0.56",
+ "@ali/lowcode-plugin-outline-pane": "1.0.56",
+ "@ali/lowcode-utils": "1.0.56",
"@ali/ve-i18n-util": "^2.0.0",
"@ali/ve-icons": "^4.1.9",
"@ali/ve-less-variables": "2.0.3",
diff --git a/packages/engine/src/engine-core.ts b/packages/engine/src/engine-core.ts
index a4b1c21ab..9ba16ed12 100644
--- a/packages/engine/src/engine-core.ts
+++ b/packages/engine/src/engine-core.ts
@@ -195,6 +195,14 @@ interface EngineOptions {
* 关闭画布自动渲染,在资产包多重异步加载的场景有效,默认值:false
*/
disableAutoRender?: boolean;
+ /**
+ * 关闭拖拽组件时的虚线响应,性能考虑,默认值:false
+ */
+ disableDetecting?: boolean;
+ /**
+ * 定制画布中点击被忽略的 selectors,默认值:(selectors) => selectors
+ */
+ customizeIgnoreSelectors?: (defaultIgnoreSelectors: string[]) => string[];
/**
* Vision-polyfill settings
*/
@@ -203,7 +211,7 @@ interface EngineOptions {
disableCompatibleReducer?: boolean;
// 是否开启在 render 阶段开启 filter reducer,默认值:false
enableFilterReducerInRenderStage?: boolean;
- }
+ };
[key: string]: any;
}
export async function init(container?: Element, options?: EngineOptions) {
diff --git a/packages/ignitor/package.json b/packages/ignitor/package.json
index a82250e27..31d7b9097 100644
--- a/packages/ignitor/package.json
+++ b/packages/ignitor/package.json
@@ -1,6 +1,6 @@
{
"name": "@ali/lowcode-ignitor",
- "version": "1.0.55",
+ "version": "1.0.56",
"description": "点火器,bootstrap lce project",
"main": "lib/index.js",
"private": true,
diff --git a/packages/plugin-designer/package.json b/packages/plugin-designer/package.json
index f4a868f2d..935375040 100644
--- a/packages/plugin-designer/package.json
+++ b/packages/plugin-designer/package.json
@@ -1,6 +1,6 @@
{
"name": "@ali/lowcode-plugin-designer",
- "version": "1.0.55",
+ "version": "1.0.56",
"description": "alibaba lowcode editor designer plugin",
"files": [
"es",
@@ -18,7 +18,7 @@
],
"author": "xiayang.xy",
"dependencies": {
- "@ali/lowcode-editor-core": "1.0.55",
+ "@ali/lowcode-editor-core": "1.0.56",
"react": "^16.8.1",
"react-dom": "^16.8.1"
},
diff --git a/packages/plugin-outline-pane/package.json b/packages/plugin-outline-pane/package.json
index 727c13a0f..d33f7821f 100644
--- a/packages/plugin-outline-pane/package.json
+++ b/packages/plugin-outline-pane/package.json
@@ -1,6 +1,6 @@
{
"name": "@ali/lowcode-plugin-outline-pane",
- "version": "1.0.55",
+ "version": "1.0.56",
"description": "Outline pane for Ali lowCode engine",
"files": [
"es",
@@ -12,10 +12,10 @@
"build": "build-scripts build --skip-demo"
},
"dependencies": {
- "@ali/lowcode-designer": "1.0.55",
- "@ali/lowcode-editor-core": "1.0.55",
- "@ali/lowcode-types": "1.0.55",
- "@ali/lowcode-utils": "1.0.55",
+ "@ali/lowcode-designer": "1.0.56",
+ "@ali/lowcode-editor-core": "1.0.56",
+ "@ali/lowcode-types": "1.0.56",
+ "@ali/lowcode-utils": "1.0.56",
"@alifd/next": "^1.19.16",
"classnames": "^2.2.6",
"react": "^16",
diff --git a/packages/rax-renderer/package.json b/packages/rax-renderer/package.json
index 70f4cc679..3f59ed409 100644
--- a/packages/rax-renderer/package.json
+++ b/packages/rax-renderer/package.json
@@ -1,6 +1,6 @@
{
"name": "@ali/lowcode-rax-renderer",
- "version": "1.0.55",
+ "version": "1.0.56",
"description": "Rax renderer for Ali lowCode engine",
"main": "lib/index.js",
"module": "es/index.js",
@@ -30,8 +30,8 @@
"build": "build-scripts build"
},
"dependencies": {
- "@ali/lowcode-renderer-core": "1.0.55",
- "@ali/lowcode-utils": "1.0.55",
+ "@ali/lowcode-renderer-core": "1.0.56",
+ "@ali/lowcode-utils": "1.0.56",
"rax-find-dom-node": "^1.0.1"
},
"devDependencies": {
diff --git a/packages/rax-simulator-renderer/package.json b/packages/rax-simulator-renderer/package.json
index 50084cabf..e62863647 100644
--- a/packages/rax-simulator-renderer/package.json
+++ b/packages/rax-simulator-renderer/package.json
@@ -1,6 +1,6 @@
{
"name": "@ali/lowcode-rax-simulator-renderer",
- "version": "1.0.55",
+ "version": "1.0.56",
"description": "rax simulator renderer for alibaba lowcode designer",
"main": "lib/index.js",
"module": "es/index.js",
@@ -11,10 +11,10 @@
"cloud-build": "build-scripts build --skip-demo"
},
"dependencies": {
- "@ali/lowcode-designer": "1.0.55",
- "@ali/lowcode-rax-renderer": "1.0.55",
- "@ali/lowcode-types": "1.0.55",
- "@ali/lowcode-utils": "1.0.55",
+ "@ali/lowcode-designer": "1.0.56",
+ "@ali/lowcode-rax-renderer": "1.0.56",
+ "@ali/lowcode-types": "1.0.56",
+ "@ali/lowcode-utils": "1.0.56",
"@ali/recore-rax": "^1.2.4",
"@ali/vu-css-style": "^1.0.2",
"@recore/obx": "^1.0.8",
@@ -55,6 +55,6 @@
"publishConfig": {
"registry": "https://registry.npm.alibaba-inc.com"
},
- "homepage": "https://unpkg.alibaba-inc.com/@ali/lowcode-rax-simulator-renderer@1.0.54/build/index.html",
+ "homepage": "https://unpkg.alibaba-inc.com/@ali/lowcode-rax-simulator-renderer@1.0.55/build/index.html",
"gitHead": "3bfd7df92985ec6c9d2ccb8ba95d7b0829fa2b1d"
}
diff --git a/packages/react-renderer/package.json b/packages/react-renderer/package.json
index 5514c39a2..75918c668 100644
--- a/packages/react-renderer/package.json
+++ b/packages/react-renderer/package.json
@@ -1,6 +1,6 @@
{
"name": "@ali/lowcode-react-renderer",
- "version": "1.0.55",
+ "version": "1.0.56",
"description": "react renderer for ali lowcode engine",
"main": "lib/index.js",
"module": "es/index.js",
@@ -23,7 +23,7 @@
"react"
],
"dependencies": {
- "@ali/lowcode-renderer-core": "1.0.55",
+ "@ali/lowcode-renderer-core": "1.0.56",
"@alifd/next": "^1.21.16"
},
"devDependencies": {
diff --git a/packages/react-simulator-renderer/package.json b/packages/react-simulator-renderer/package.json
index aa942e06c..16b44f27b 100644
--- a/packages/react-simulator-renderer/package.json
+++ b/packages/react-simulator-renderer/package.json
@@ -1,6 +1,6 @@
{
"name": "@ali/lowcode-react-simulator-renderer",
- "version": "1.0.55",
+ "version": "1.0.56",
"description": "react simulator renderer for alibaba lowcode designer",
"main": "lib/index.js",
"module": "es/index.js",
@@ -14,10 +14,10 @@
"build": "NODE_OPTIONS=--max_old_space_size=8192 build-scripts build --skip-demo"
},
"dependencies": {
- "@ali/lowcode-designer": "1.0.55",
- "@ali/lowcode-react-renderer": "1.0.55",
- "@ali/lowcode-types": "1.0.55",
- "@ali/lowcode-utils": "1.0.55",
+ "@ali/lowcode-designer": "1.0.56",
+ "@ali/lowcode-react-renderer": "1.0.56",
+ "@ali/lowcode-types": "1.0.56",
+ "@ali/lowcode-utils": "1.0.56",
"@ali/vu-css-style": "^1.0.2",
"@recore/obx": "^1.0.8",
"@recore/obx-react": "^1.0.7",
diff --git a/packages/renderer-core/package.json b/packages/renderer-core/package.json
index 3f28ae2ba..efaaa5862 100644
--- a/packages/renderer-core/package.json
+++ b/packages/renderer-core/package.json
@@ -1,6 +1,6 @@
{
"name": "@ali/lowcode-renderer-core",
- "version": "1.0.55",
+ "version": "1.0.56",
"description": "renderer core",
"license": "MIT",
"main": "lib/index.js",
diff --git a/packages/types/package.json b/packages/types/package.json
index a2df7bc5c..96a876dd4 100644
--- a/packages/types/package.json
+++ b/packages/types/package.json
@@ -1,6 +1,6 @@
{
"name": "@ali/lowcode-types",
- "version": "1.0.55",
+ "version": "1.0.56",
"description": "Types for Ali lowCode engine",
"files": [
"es",
diff --git a/packages/utils/package.json b/packages/utils/package.json
index b9af19e92..2641ee7da 100644
--- a/packages/utils/package.json
+++ b/packages/utils/package.json
@@ -1,6 +1,6 @@
{
"name": "@ali/lowcode-utils",
- "version": "1.0.55",
+ "version": "1.0.56",
"description": "Utils for Ali lowCode engine",
"files": [
"es",
@@ -12,7 +12,7 @@
"build": "build-scripts build --skip-demo"
},
"dependencies": {
- "@ali/lowcode-types": "1.0.55",
+ "@ali/lowcode-types": "1.0.56",
"@alifd/next": "^1.19.16",
"lodash.get": "^4.4.2",
"react": "^16"
diff --git a/packages/vision-polyfill/package.json b/packages/vision-polyfill/package.json
index d3099ab8d..234ad6655 100644
--- a/packages/vision-polyfill/package.json
+++ b/packages/vision-polyfill/package.json
@@ -1,6 +1,6 @@
{
"name": "@ali/lowcode-vision-polyfill",
- "version": "1.0.55",
+ "version": "1.0.56",
"description": "Vision Polyfill for Ali lowCode engine",
"main": "lib/index.js",
"private": true,
@@ -18,10 +18,10 @@
},
"license": "MIT",
"dependencies": {
- "@ali/lowcode-designer": "1.0.55",
- "@ali/lowcode-editor-core": "1.0.55",
- "@ali/lowcode-editor-skeleton": "1.0.55",
- "@ali/lowcode-utils": "1.0.55",
+ "@ali/lowcode-designer": "1.0.56",
+ "@ali/lowcode-editor-core": "1.0.56",
+ "@ali/lowcode-editor-skeleton": "1.0.56",
+ "@ali/lowcode-utils": "1.0.56",
"@ali/ve-i18n-util": "^2.0.0",
"@ali/ve-icons": "^4.1.9",
"@ali/ve-less-variables": "2.0.3",
diff --git a/tsconfig.json b/tsconfig.json
index 556a1fea8..fce8ef03d 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -37,5 +37,5 @@
},
"outDir": "lib"
},
- "exclude": ["**/test", "**/lib", "**/es", "node_modules"]
+ "exclude": ["**/tests/*", "**/*.test.ts", "**/lib", "**/es", "node_modules"]
}