mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-03-12 02:46:08 +00:00
fix: 修复 project.unload 无法正常删除 document 的 bug
chore(test): 部分完成 pages / api 等兼容测试 chore(test): 完成部分 prototype 单测
This commit is contained in:
parent
11e8e02f70
commit
5e6e91b265
@ -101,7 +101,9 @@ export class Project {
|
|||||||
if (this.documents.length < 1) {
|
if (this.documents.length < 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.documents.forEach((doc) => doc.remove());
|
for (let i = this.documents.length - 1; i >= 0; i--) {
|
||||||
|
this.documents[i].remove();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
removeDocument(doc: DocumentModel) {
|
removeDocument(doc: DocumentModel) {
|
||||||
|
|||||||
@ -1,5 +1,9 @@
|
|||||||
import { IocContext } from 'power-di';
|
import { IocContext } from 'power-di';
|
||||||
|
|
||||||
|
// 原本的 canBeKey 里判断函数的方法是 instanceof Function,在某些 babel 编译 class 后的场景不满足该判断条件,此处暴力破解
|
||||||
|
IocContext.prototype.canBeKey = (obj: any) =>
|
||||||
|
typeof obj === 'function' || ['string', 'symbol'].includes(typeof obj);
|
||||||
|
|
||||||
export * from 'power-di';
|
export * from 'power-di';
|
||||||
|
|
||||||
export const globalContext = IocContext.DefaultInstance;
|
export const globalContext = IocContext.DefaultInstance;
|
||||||
|
|||||||
@ -2,7 +2,7 @@ module.exports = {
|
|||||||
extends: 'eslint-config-ali/typescript/react',
|
extends: 'eslint-config-ali/typescript/react',
|
||||||
rules: {
|
rules: {
|
||||||
'react/no-multi-comp': 1,
|
'react/no-multi-comp': 1,
|
||||||
'no-unused-expressions': 1,
|
'no-unused-expressions': 0,
|
||||||
'implicit-arrow-linebreak': 1,
|
'implicit-arrow-linebreak': 1,
|
||||||
'no-nested-ternary': 1,
|
'no-nested-ternary': 1,
|
||||||
'no-mixed-operators': 1,
|
'no-mixed-operators': 1,
|
||||||
@ -16,5 +16,6 @@ module.exports = {
|
|||||||
'react/no-deprecated': 1,
|
'react/no-deprecated': 1,
|
||||||
'no-useless-escape': 1,
|
'no-useless-escape': 1,
|
||||||
'brace-style': 1,
|
'brace-style': 1,
|
||||||
|
'@typescript-eslint/member-ordering': 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
const esModules = [
|
const esModules = [
|
||||||
'@recore/obx-react',
|
'@recore/obx-react',
|
||||||
'@ali/lowcode-editor-core',
|
// '@ali/lowcode-editor-core',
|
||||||
].join('|');
|
].join('|');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|||||||
@ -64,15 +64,15 @@ export class Bus {
|
|||||||
|
|
||||||
const bus = new Bus();
|
const bus = new Bus();
|
||||||
|
|
||||||
editor.on('hotkey.callback.call', (data) => {
|
editor?.on('hotkey.callback.call', (data) => {
|
||||||
bus.emit('ve.hotkey.callback.call', data);
|
bus.emit('ve.hotkey.callback.call', data);
|
||||||
});
|
});
|
||||||
|
|
||||||
editor.on('history.back', (data) => {
|
editor?.on('history.back', (data) => {
|
||||||
bus.emit('ve.history.back', data);
|
bus.emit('ve.history.back', data);
|
||||||
});
|
});
|
||||||
|
|
||||||
editor.on('history.forward', (data) => {
|
editor?.on('history.forward', (data) => {
|
||||||
bus.emit('ve.history.forward', data);
|
bus.emit('ve.history.forward', data);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -3,8 +3,6 @@ import { isPlainObject, hasOwnProperty, cloneDeep, isI18NObject, isUseI18NSetter
|
|||||||
import { globalContext, Editor } from '@ali/lowcode-editor-core';
|
import { globalContext, Editor } from '@ali/lowcode-editor-core';
|
||||||
import { Designer, LiveEditing, TransformStage, Node, getConvertedExtraKey } from '@ali/lowcode-designer';
|
import { Designer, LiveEditing, TransformStage, Node, getConvertedExtraKey } from '@ali/lowcode-designer';
|
||||||
import Outline, { OutlineBackupPane, getTreeMaster } from '@ali/lowcode-plugin-outline-pane';
|
import Outline, { OutlineBackupPane, getTreeMaster } from '@ali/lowcode-plugin-outline-pane';
|
||||||
import { toCss } from '@ali/vu-css-style';
|
|
||||||
import logger from '@ali/vu-logger';
|
|
||||||
import bus from './bus';
|
import bus from './bus';
|
||||||
import { VE_EVENTS } from './base/const';
|
import { VE_EVENTS } from './base/const';
|
||||||
|
|
||||||
@ -13,7 +11,16 @@ import { Skeleton, SettingsPrimaryPane, registerDefaults } from '@ali/lowcode-ed
|
|||||||
|
|
||||||
import { deepValueParser } from './deep-value-parser';
|
import { deepValueParser } from './deep-value-parser';
|
||||||
import { liveEditingRule, liveEditingSaveHander } from './vc-live-editing';
|
import { liveEditingRule, liveEditingSaveHander } from './vc-live-editing';
|
||||||
import { isVariable } from './utils';
|
import {
|
||||||
|
compatibleReducer,
|
||||||
|
compatiblePageReducer,
|
||||||
|
stylePropsReducer,
|
||||||
|
upgradePropsReducer,
|
||||||
|
filterReducer,
|
||||||
|
removeEmptyPropsReducer,
|
||||||
|
initNodeReducer,
|
||||||
|
liveLifecycleReducer,
|
||||||
|
} from './props-reducers';
|
||||||
|
|
||||||
export const editor = new Editor();
|
export const editor = new Editor();
|
||||||
globalContext.register(editor, Editor);
|
globalContext.register(editor, Editor);
|
||||||
@ -31,313 +38,31 @@ designer.project.onCurrentDocumentChange((doc) => {
|
|||||||
bus.emit(VE_EVENTS.VE_PAGE_PAGE_READY);
|
bus.emit(VE_EVENTS.VE_PAGE_PAGE_READY);
|
||||||
});
|
});
|
||||||
|
|
||||||
interface Variable {
|
|
||||||
type: 'variable';
|
|
||||||
variable: string;
|
|
||||||
value: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
function upgradePropsReducer(props: any) {
|
|
||||||
if (!props || !isPlainObject(props)) {
|
|
||||||
return props;
|
|
||||||
}
|
|
||||||
if (isJSBlock(props)) {
|
|
||||||
if (props.value.componentName === 'Slot') {
|
|
||||||
return {
|
|
||||||
type: 'JSSlot',
|
|
||||||
title: (props.value.props as any)?.slotTitle,
|
|
||||||
name: (props.value.props as any)?.slotName,
|
|
||||||
value: props.value.children,
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return props.value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (isVariable(props)) {
|
|
||||||
return {
|
|
||||||
type: 'JSExpression',
|
|
||||||
value: props.variable,
|
|
||||||
mock: props.value,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
const newProps: any = {};
|
|
||||||
Object.keys(props).forEach((key) => {
|
|
||||||
if (/^__slot__/.test(key) && props[key] === true) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
newProps[key] = upgradePropsReducer(props[key]);
|
|
||||||
});
|
|
||||||
return newProps;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 升级 Props
|
// 升级 Props
|
||||||
designer.addPropsReducer(upgradePropsReducer, TransformStage.Upgrade);
|
designer.addPropsReducer(upgradePropsReducer, TransformStage.Upgrade);
|
||||||
|
|
||||||
function getCurrentFieldIds() {
|
|
||||||
const fieldIds: any = [];
|
|
||||||
const nodesMap = designer?.currentDocument?.nodesMap || new Map();
|
|
||||||
nodesMap.forEach((curNode: any) => {
|
|
||||||
const fieldId = nodesMap?.get(curNode.id)?.getPropValue('fieldId');
|
|
||||||
if (fieldId) {
|
|
||||||
fieldIds.push(fieldId);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return fieldIds;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 节点 props 初始化
|
// 节点 props 初始化
|
||||||
designer.addPropsReducer((props, node) => {
|
designer.addPropsReducer(initNodeReducer, TransformStage.Init);
|
||||||
// debugger;
|
|
||||||
// run initials
|
|
||||||
const newProps: any = {
|
|
||||||
...props,
|
|
||||||
};
|
|
||||||
if (newProps.fieldId) {
|
|
||||||
const fieldIds = getCurrentFieldIds();
|
|
||||||
|
|
||||||
// 全局的关闭 uniqueIdChecker 信号,在 ve-utils 中实现
|
designer.addPropsReducer(liveLifecycleReducer, TransformStage.Render);
|
||||||
if (fieldIds.indexOf(props.fieldId) >= 0 && !(window as any).__disable_unique_id_checker__) {
|
|
||||||
newProps.fieldId = undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const initials = node.componentMeta.getMetadata().experimental?.initials;
|
|
||||||
if (initials) {
|
|
||||||
const getRealValue = (propValue: any) => {
|
|
||||||
if (isVariable(propValue)) {
|
|
||||||
return propValue.value;
|
|
||||||
}
|
|
||||||
if (isJSExpression(propValue)) {
|
|
||||||
return propValue.mock;
|
|
||||||
}
|
|
||||||
return propValue;
|
|
||||||
};
|
|
||||||
initials.forEach((item) => {
|
|
||||||
// FIXME! this implements SettingTarget
|
|
||||||
try {
|
|
||||||
// FIXME! item.name could be 'xxx.xxx'
|
|
||||||
const ov = newProps[item.name];
|
|
||||||
const v = item.initial(node as any, getRealValue(ov));
|
|
||||||
if (ov === undefined && v !== undefined) {
|
|
||||||
newProps[item.name] = v;
|
|
||||||
}
|
|
||||||
// 兼容 props 中的属性为 i18n 类型,但是仅提供了一个字符串值,非变量绑定
|
|
||||||
if (isUseI18NSetter(node.componentMeta.prototype, item.name) &&
|
|
||||||
!isI18NObject(ov) &&
|
|
||||||
!isJSExpression(ov) &&
|
|
||||||
!isJSBlock(ov) &&
|
|
||||||
!isJSSlot(ov) &&
|
|
||||||
!isVariable(ov) &&
|
|
||||||
(isString(v) || isI18NObject(v))) {
|
|
||||||
newProps[item.name] = convertToI18NObject(v);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
if (hasOwnProperty(props, item.name)) {
|
|
||||||
newProps[item.name] = props[item.name];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (newProps[item.name] && !node.props.has(item.name)) {
|
|
||||||
node.props.add(newProps[item.name], item.name, false, { skipSetSlot: true });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return newProps;
|
|
||||||
}, TransformStage.Init);
|
|
||||||
|
|
||||||
designer.addPropsReducer((props: any, node: Node) => {
|
|
||||||
// live 模式下解析 lifeCycles
|
|
||||||
if (node.isRoot() && props && props.lifeCycles) {
|
|
||||||
if (editor.get('designMode') === 'live') {
|
|
||||||
const lifeCycleMap = {
|
|
||||||
didMount: 'componentDidMount',
|
|
||||||
willUnmount: 'componentWillUnMount',
|
|
||||||
};
|
|
||||||
const lifeCycles = props.lifeCycles;
|
|
||||||
Object.keys(lifeCycleMap).forEach(key => {
|
|
||||||
if (lifeCycles[key]) {
|
|
||||||
lifeCycles[lifeCycleMap[key]] = lifeCycles[key];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return props;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
...props,
|
|
||||||
lifeCycles: {},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return props;
|
|
||||||
}, TransformStage.Render);
|
|
||||||
|
|
||||||
function filterReducer(props: any, node: Node): any {
|
|
||||||
const filters = node.componentMeta.getMetadata().experimental?.filters;
|
|
||||||
if (filters && filters.length) {
|
|
||||||
const newProps = { ...props };
|
|
||||||
filters.forEach((item) => {
|
|
||||||
// FIXME! item.name could be 'xxx.xxx'
|
|
||||||
if (!hasOwnProperty(newProps, item.name)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
if (item.filter(node.settingEntry.getProp(item.name), props[item.name]) === false) {
|
|
||||||
delete newProps[item.name];
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.warn(e);
|
|
||||||
logger.trace(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return newProps;
|
|
||||||
}
|
|
||||||
return props;
|
|
||||||
}
|
|
||||||
designer.addPropsReducer(filterReducer, TransformStage.Save);
|
designer.addPropsReducer(filterReducer, TransformStage.Save);
|
||||||
designer.addPropsReducer(filterReducer, TransformStage.Render);
|
designer.addPropsReducer(filterReducer, TransformStage.Render);
|
||||||
|
|
||||||
function compatiableReducer(props: any) {
|
|
||||||
if (!props || !isPlainObject(props)) {
|
|
||||||
return props;
|
|
||||||
}
|
|
||||||
// 为了能降级到老版本,建议在后期版本去掉以下代码
|
|
||||||
if (isJSSlot(props)) {
|
|
||||||
return {
|
|
||||||
type: 'JSBlock',
|
|
||||||
value: {
|
|
||||||
componentName: 'Slot',
|
|
||||||
children: props.value,
|
|
||||||
props: {
|
|
||||||
slotTitle: props.title,
|
|
||||||
slotName: props.name,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (isJSExpression(props) && !props.events) {
|
|
||||||
return {
|
|
||||||
type: 'variable',
|
|
||||||
value: props.mock,
|
|
||||||
variable: props.value,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
const newProps: any = {};
|
|
||||||
Object.entries<any>(props).forEach(([key, val]) => {
|
|
||||||
newProps[key] = compatiableReducer(val);
|
|
||||||
});
|
|
||||||
return newProps;
|
|
||||||
}
|
|
||||||
// FIXME: Dirty fix, will remove this reducer
|
// FIXME: Dirty fix, will remove this reducer
|
||||||
designer.addPropsReducer(compatiableReducer, TransformStage.Save);
|
designer.addPropsReducer(compatibleReducer, TransformStage.Save);
|
||||||
// 兼容历史版本的 Page 组件
|
// 兼容历史版本的 Page 组件
|
||||||
designer.addPropsReducer((props: any, node: Node) => {
|
designer.addPropsReducer(compatiblePageReducer, TransformStage.Save);
|
||||||
const lifeCycleNames = ['didMount', 'willUnmount'];
|
|
||||||
if (node.isRoot()) {
|
|
||||||
lifeCycleNames.forEach((key) => {
|
|
||||||
if (props[key]) {
|
|
||||||
const lifeCycles = node.props.getPropValue(getConvertedExtraKey('lifeCycles')) || {};
|
|
||||||
lifeCycles[key] = props[key];
|
|
||||||
node.props.setPropValue(getConvertedExtraKey('lifeCycles'), lifeCycles);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return props;
|
|
||||||
}, TransformStage.Save);
|
|
||||||
|
|
||||||
// designer.addPropsReducer((props: any, node: Node) => {
|
|
||||||
// const lifeCycleNames = ['didMount', 'willUnmount'];
|
|
||||||
// const lifeCycleMap = {
|
|
||||||
// didMount: 'componentDidMount',
|
|
||||||
// willUnmount: 'componentWillUnMount',
|
|
||||||
// };
|
|
||||||
// if (node.componentName === 'Page') {
|
|
||||||
// debugger;
|
|
||||||
// lifeCycleNames.forEach(key => {
|
|
||||||
// if (props[key]) {
|
|
||||||
// const lifeCycles = node.props.getPropValue(getConvertedExtraKey('lifeCycles')) || {};
|
|
||||||
// lifeCycles[lifeCycleMap[key]] = props[key];
|
|
||||||
// node.props.setPropValue(getConvertedExtraKey('lifeCycles'), lifeCycles);
|
|
||||||
// } else if (node.props.getPropValue(getConvertedExtraKey('lifeCycles'))) {
|
|
||||||
// const lifeCycles = node.props.getPropValue(getConvertedExtraKey('lifeCycles')) || {};
|
|
||||||
// lifeCycles[lifeCycleMap[key]] = lifeCycles[key];
|
|
||||||
// node.props.setPropValue(getConvertedExtraKey('lifeCycles'), lifeCycles);
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// return props;
|
|
||||||
// }, TransformStage.Init);
|
|
||||||
|
|
||||||
// 设计器组件样式处理
|
// 设计器组件样式处理
|
||||||
function stylePropsReducer(props: any, node: any) {
|
|
||||||
if (props && typeof props === 'object' && props.__style__) {
|
|
||||||
const cssId = `_style_pesudo_${ node.id.replace(/\$/g, '_')}`;
|
|
||||||
const cssClass = `_css_pesudo_${ node.id.replace(/\$/g, '_')}`;
|
|
||||||
const styleProp = props.__style__;
|
|
||||||
appendStyleNode(props, styleProp, cssClass, cssId);
|
|
||||||
}
|
|
||||||
if (props && typeof props === 'object' && props.pageStyle) {
|
|
||||||
const cssId = '_style_pesudo_engine-document';
|
|
||||||
const cssClass = 'engine-document';
|
|
||||||
const styleProp = props.pageStyle;
|
|
||||||
appendStyleNode(props, styleProp, cssClass, cssId);
|
|
||||||
}
|
|
||||||
if (props && typeof props === 'object' && props.containerStyle) {
|
|
||||||
const cssId = `_style_pesudo_${ node.id}`;
|
|
||||||
const cssClass = `_css_pesudo_${ node.id.replace(/\$/g, '_')}`;
|
|
||||||
const styleProp = props.containerStyle;
|
|
||||||
appendStyleNode(props, styleProp, cssClass, cssId);
|
|
||||||
}
|
|
||||||
return props;
|
|
||||||
}
|
|
||||||
|
|
||||||
function appendStyleNode(props: any, styleProp: any, cssClass: string, cssId: string) {
|
|
||||||
const doc = designer.currentDocument?.simulator?.contentDocument;
|
|
||||||
if (!doc) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const dom = doc.getElementById(cssId);
|
|
||||||
if (dom) {
|
|
||||||
dom.parentNode?.removeChild(dom);
|
|
||||||
}
|
|
||||||
if (typeof styleProp === 'object') {
|
|
||||||
styleProp = toCss(styleProp);
|
|
||||||
}
|
|
||||||
if (typeof styleProp === 'string') {
|
|
||||||
const s = doc.createElement('style');
|
|
||||||
props.className = cssClass;
|
|
||||||
s.setAttribute('type', 'text/css');
|
|
||||||
s.setAttribute('id', cssId);
|
|
||||||
doc.getElementsByTagName('head')[0].appendChild(s);
|
|
||||||
|
|
||||||
s.appendChild(doc.createTextNode(styleProp.replace(/(\d+)rpx/g, (a, b) => {
|
|
||||||
return `${b / 2}px`;
|
|
||||||
}).replace(/:root/g, `.${ cssClass}`)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
designer.addPropsReducer(stylePropsReducer, TransformStage.Render);
|
designer.addPropsReducer(stylePropsReducer, TransformStage.Render);
|
||||||
// 国际化 & Expression 渲染时处理
|
// 国际化 & Expression 渲染时处理
|
||||||
designer.addPropsReducer(deepValueParser, TransformStage.Render);
|
designer.addPropsReducer(deepValueParser, TransformStage.Render);
|
||||||
|
|
||||||
// 清除空的 props value
|
|
||||||
function removeEmptyProps(props: any, node: Node) {
|
|
||||||
if (node.isRoot() && props.dataSource && Array.isArray(props.dataSource.online)) {
|
|
||||||
const online = cloneDeep(props.dataSource.online);
|
|
||||||
online.forEach((item: any) => {
|
|
||||||
const newParam: any = {};
|
|
||||||
if (Array.isArray(item?.options?.params)) {
|
|
||||||
item.options.params.forEach((element: any) => {
|
|
||||||
if (element.name) {
|
|
||||||
newParam[element.name] = element.value;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
item.options.params = newParam;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
props.dataSource.list = online;
|
|
||||||
}
|
|
||||||
return props;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Init 的时候没有拿到 dataSource, 只能在 Render 和 Save 的时候都调用一次,理论上执行时机在 Init
|
// Init 的时候没有拿到 dataSource, 只能在 Render 和 Save 的时候都调用一次,理论上执行时机在 Init
|
||||||
// Render 和 Save 都要各调用一次,感觉也是有问题的,是不是应该在 Render 执行一次就行了?见上 filterReducer 也是一样的处理方式。
|
// Render 和 Save 都要各调用一次,感觉也是有问题的,是不是应该在 Render 执行一次就行了?见上 filterReducer 也是一样的处理方式。
|
||||||
designer.addPropsReducer(removeEmptyProps, TransformStage.Render);
|
designer.addPropsReducer(removeEmptyPropsReducer, TransformStage.Render);
|
||||||
designer.addPropsReducer(removeEmptyProps, TransformStage.Save);
|
designer.addPropsReducer(removeEmptyPropsReducer, TransformStage.Save);
|
||||||
|
|
||||||
skeleton.add({
|
skeleton.add({
|
||||||
area: 'mainArea',
|
area: 'mainArea',
|
||||||
|
|||||||
@ -162,7 +162,7 @@ export {
|
|||||||
Symbols,
|
Symbols,
|
||||||
};
|
};
|
||||||
|
|
||||||
const version = '6.0.0(LowcodeEngine 0.9.3)';
|
const version = '6.0.0 (LowcodeEngine 0.9.32)';
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
`%c VisionEngine %c v${version} `,
|
`%c VisionEngine %c v${version} `,
|
||||||
|
|||||||
@ -64,7 +64,6 @@ const pages = Object.assign(project, {
|
|||||||
item.methods = {};
|
item.methods = {};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
console.log(pages, componentsTree);
|
|
||||||
project.load(
|
project.load(
|
||||||
{
|
{
|
||||||
version: '1.0.0',
|
version: '1.0.0',
|
||||||
|
|||||||
@ -0,0 +1,51 @@
|
|||||||
|
import { getConvertedExtraKey } from '@ali/lowcode-designer';
|
||||||
|
import {
|
||||||
|
isPlainObject,
|
||||||
|
} from '@ali/lowcode-utils';
|
||||||
|
import { isJSExpression, isJSSlot } from '@ali/lowcode-types';
|
||||||
|
|
||||||
|
export function compatibleReducer(props: any) {
|
||||||
|
if (!props || !isPlainObject(props)) {
|
||||||
|
return props;
|
||||||
|
}
|
||||||
|
// 为了能降级到老版本,建议在后期版本去掉以下代码
|
||||||
|
if (isJSSlot(props)) {
|
||||||
|
return {
|
||||||
|
type: 'JSBlock',
|
||||||
|
value: {
|
||||||
|
componentName: 'Slot',
|
||||||
|
children: props.value,
|
||||||
|
props: {
|
||||||
|
slotTitle: props.title,
|
||||||
|
slotName: props.name,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (isJSExpression(props) && !props.events) {
|
||||||
|
return {
|
||||||
|
type: 'variable',
|
||||||
|
value: props.mock,
|
||||||
|
variable: props.value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const newProps: any = {};
|
||||||
|
Object.entries<any>(props).forEach(([key, val]) => {
|
||||||
|
newProps[key] = compatibleReducer(val);
|
||||||
|
});
|
||||||
|
return newProps;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function compatiblePageReducer(props: any, node: Node) {
|
||||||
|
const lifeCycleNames = ['didMount', 'willUnmount'];
|
||||||
|
if (node.isRoot()) {
|
||||||
|
lifeCycleNames.forEach(key => {
|
||||||
|
if (props[key]) {
|
||||||
|
const lifeCycles = node.props.getPropValue(getConvertedExtraKey('lifeCycles')) || {};
|
||||||
|
lifeCycles[key] = props[key];
|
||||||
|
node.props.setPropValue(getConvertedExtraKey('lifeCycles'), lifeCycles);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return props;
|
||||||
|
}
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
import logger from '@ali/vu-logger';
|
||||||
|
import { hasOwnProperty } from '@ali/lowcode-utils';
|
||||||
|
|
||||||
|
export function filterReducer(props: any, node: Node): any {
|
||||||
|
const filters = node.componentMeta.getMetadata().experimental?.filters;
|
||||||
|
if (filters && filters.length) {
|
||||||
|
const newProps = { ...props };
|
||||||
|
filters.forEach((item) => {
|
||||||
|
// FIXME! item.name could be 'xxx.xxx'
|
||||||
|
if (!hasOwnProperty(newProps, item.name)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (item.filter(node.settingEntry.getProp(item.name), props[item.name]) === false) {
|
||||||
|
delete newProps[item.name];
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn(e);
|
||||||
|
logger.trace(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return newProps;
|
||||||
|
}
|
||||||
|
return props;
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
export * from './downgrade-schema-reducer';
|
||||||
|
export * from './filter-reducer';
|
||||||
|
export * from './init-node-reducer';
|
||||||
|
export * from './live-lifecycle-reducer';
|
||||||
|
export * from './remove-empty-prop-reducer';
|
||||||
|
export * from './style-reducer';
|
||||||
|
export * from './upgrade-reducer';
|
||||||
@ -0,0 +1,68 @@
|
|||||||
|
import {
|
||||||
|
hasOwnProperty,
|
||||||
|
isI18NObject,
|
||||||
|
isUseI18NSetter,
|
||||||
|
convertToI18NObject,
|
||||||
|
isString,
|
||||||
|
} from '@ali/lowcode-utils';
|
||||||
|
import { isJSExpression, isJSBlock, isJSSlot } from '@ali/lowcode-types';
|
||||||
|
import { isVariable, getCurrentFieldIds } from '../utils';
|
||||||
|
|
||||||
|
export function initNodeReducer(props, node) {
|
||||||
|
// debugger;
|
||||||
|
// run initials
|
||||||
|
const newProps: any = {
|
||||||
|
...props,
|
||||||
|
};
|
||||||
|
if (newProps.fieldId) {
|
||||||
|
const fieldIds = getCurrentFieldIds();
|
||||||
|
|
||||||
|
// 全局的关闭 uniqueIdChecker 信号,在 ve-utils 中实现
|
||||||
|
if (fieldIds.indexOf(props.fieldId) >= 0 && !(window as any).__disable_unique_id_checker__) {
|
||||||
|
newProps.fieldId = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const initials = node.componentMeta.getMetadata().experimental?.initials;
|
||||||
|
if (initials) {
|
||||||
|
const getRealValue = (propValue: any) => {
|
||||||
|
if (isVariable(propValue)) {
|
||||||
|
return propValue.value;
|
||||||
|
}
|
||||||
|
if (isJSExpression(propValue)) {
|
||||||
|
return propValue.mock;
|
||||||
|
}
|
||||||
|
return propValue;
|
||||||
|
};
|
||||||
|
initials.forEach(item => {
|
||||||
|
// FIXME! this implements SettingTarget
|
||||||
|
try {
|
||||||
|
// FIXME! item.name could be 'xxx.xxx'
|
||||||
|
const ov = newProps[item.name];
|
||||||
|
const v = item.initial(node as any, getRealValue(ov));
|
||||||
|
if (ov === undefined && v !== undefined) {
|
||||||
|
newProps[item.name] = v;
|
||||||
|
}
|
||||||
|
// 兼容 props 中的属性为 i18n 类型,但是仅提供了一个字符串值,非变量绑定
|
||||||
|
if (
|
||||||
|
isUseI18NSetter(node.componentMeta.prototype, item.name) &&
|
||||||
|
!isI18NObject(ov) &&
|
||||||
|
!isJSExpression(ov) &&
|
||||||
|
!isJSBlock(ov) &&
|
||||||
|
!isJSSlot(ov) &&
|
||||||
|
!isVariable(ov) &&
|
||||||
|
(isString(v) || isI18NObject(v))
|
||||||
|
) {
|
||||||
|
newProps[item.name] = convertToI18NObject(v);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
if (hasOwnProperty(props, item.name)) {
|
||||||
|
newProps[item.name] = props[item.name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (newProps[item.name] && !node.props.has(item.name)) {
|
||||||
|
node.props.add(newProps[item.name], item.name, false, { skipSetSlot: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return newProps;
|
||||||
|
}
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
import { globalContext, Editor } from '@ali/lowcode-editor-core';
|
||||||
|
import { Node } from '@ali/lowcode-designer';
|
||||||
|
|
||||||
|
export function liveLifecycleReducer(props: any, node: Node) {
|
||||||
|
const editor = globalContext.get(Editor);
|
||||||
|
// live 模式下解析 lifeCycles
|
||||||
|
if (node.isRoot() && props && props.lifeCycles) {
|
||||||
|
if (editor.get('designMode') === 'live') {
|
||||||
|
const lifeCycleMap = {
|
||||||
|
didMount: 'componentDidMount',
|
||||||
|
willUnmount: 'componentWillUnMount',
|
||||||
|
};
|
||||||
|
const lifeCycles = props.lifeCycles;
|
||||||
|
Object.keys(lifeCycleMap).forEach(key => {
|
||||||
|
if (lifeCycles[key]) {
|
||||||
|
lifeCycles[lifeCycleMap[key]] = lifeCycles[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return props;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...props,
|
||||||
|
lifeCycles: {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return props;
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
import {
|
||||||
|
cloneDeep,
|
||||||
|
} from '@ali/lowcode-utils';
|
||||||
|
|
||||||
|
// 清除空的 props value
|
||||||
|
export function removeEmptyPropsReducer(props: any, node: Node) {
|
||||||
|
if (node.isRoot() && props.dataSource && Array.isArray(props.dataSource.online)) {
|
||||||
|
const online = cloneDeep(props.dataSource.online);
|
||||||
|
online.forEach((item: any) => {
|
||||||
|
const newParam: any = {};
|
||||||
|
if (Array.isArray(item?.options?.params)) {
|
||||||
|
item.options.params.forEach((element: any) => {
|
||||||
|
if (element.name) {
|
||||||
|
newParam[element.name] = element.value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
item.options.params = newParam;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
props.dataSource.list = online;
|
||||||
|
}
|
||||||
|
return props;
|
||||||
|
}
|
||||||
@ -0,0 +1,51 @@
|
|||||||
|
import { globalContext, Editor } from '@ali/lowcode-editor-core';
|
||||||
|
import { toCss } from '@ali/vu-css-style';
|
||||||
|
|
||||||
|
export function stylePropsReducer(props: any, node: any) {
|
||||||
|
if (props && typeof props === 'object' && props.__style__) {
|
||||||
|
const cssId = `_style_pesudo_${ node.id.replace(/\$/g, '_')}`;
|
||||||
|
const cssClass = `_css_pesudo_${ node.id.replace(/\$/g, '_')}`;
|
||||||
|
const styleProp = props.__style__;
|
||||||
|
appendStyleNode(props, styleProp, cssClass, cssId);
|
||||||
|
}
|
||||||
|
if (props && typeof props === 'object' && props.pageStyle) {
|
||||||
|
const cssId = '_style_pesudo_engine-document';
|
||||||
|
const cssClass = 'engine-document';
|
||||||
|
const styleProp = props.pageStyle;
|
||||||
|
appendStyleNode(props, styleProp, cssClass, cssId);
|
||||||
|
}
|
||||||
|
if (props && typeof props === 'object' && props.containerStyle) {
|
||||||
|
const cssId = `_style_pesudo_${ node.id}`;
|
||||||
|
const cssClass = `_css_pesudo_${ node.id.replace(/\$/g, '_')}`;
|
||||||
|
const styleProp = props.containerStyle;
|
||||||
|
appendStyleNode(props, styleProp, cssClass, cssId);
|
||||||
|
}
|
||||||
|
return props;
|
||||||
|
}
|
||||||
|
|
||||||
|
function appendStyleNode(props: any, styleProp: any, cssClass: string, cssId: string) {
|
||||||
|
const editor = globalContext.get(Editor);
|
||||||
|
const designer = editor.get('designer');
|
||||||
|
const doc = designer.currentDocument?.simulator?.contentDocument;
|
||||||
|
if (!doc) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const dom = doc.getElementById(cssId);
|
||||||
|
if (dom) {
|
||||||
|
dom.parentNode?.removeChild(dom);
|
||||||
|
}
|
||||||
|
if (typeof styleProp === 'object') {
|
||||||
|
styleProp = toCss(styleProp);
|
||||||
|
}
|
||||||
|
if (typeof styleProp === 'string') {
|
||||||
|
const s = doc.createElement('style');
|
||||||
|
props.className = cssClass;
|
||||||
|
s.setAttribute('type', 'text/css');
|
||||||
|
s.setAttribute('id', cssId);
|
||||||
|
doc.getElementsByTagName('head')[0].appendChild(s);
|
||||||
|
|
||||||
|
s.appendChild(doc.createTextNode(styleProp.replace(/(\d+)rpx/g, (a, b) => {
|
||||||
|
return `${b / 2}px`;
|
||||||
|
}).replace(/:root/g, `.${ cssClass}`)));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
import {
|
||||||
|
isPlainObject,
|
||||||
|
} from '@ali/lowcode-utils';
|
||||||
|
import { isJSBlock } from '@ali/lowcode-types';
|
||||||
|
import { isVariable } from '../utils';
|
||||||
|
|
||||||
|
export function upgradePropsReducer(props: any) {
|
||||||
|
if (!props || !isPlainObject(props)) {
|
||||||
|
return props;
|
||||||
|
}
|
||||||
|
if (isJSBlock(props)) {
|
||||||
|
if (props.value.componentName === 'Slot') {
|
||||||
|
return {
|
||||||
|
type: 'JSSlot',
|
||||||
|
title: (props.value.props as any)?.slotTitle,
|
||||||
|
name: (props.value.props as any)?.slotName,
|
||||||
|
value: props.value.children,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return props.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isVariable(props)) {
|
||||||
|
return {
|
||||||
|
type: 'JSExpression',
|
||||||
|
value: props.variable,
|
||||||
|
mock: props.value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const newProps: any = {};
|
||||||
|
Object.keys(props).forEach((key) => {
|
||||||
|
if (/^__slot__/.test(key) && props[key] === true) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
newProps[key] = upgradePropsReducer(props[key]);
|
||||||
|
});
|
||||||
|
return newProps;
|
||||||
|
}
|
||||||
@ -1,3 +1,25 @@
|
|||||||
export function isVariable(obj: any) {
|
import { globalContext, Editor } from '@ali/lowcode-editor-core';
|
||||||
|
|
||||||
|
interface Variable {
|
||||||
|
type: 'variable';
|
||||||
|
variable: string;
|
||||||
|
value: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isVariable(obj: any): obj is Variable {
|
||||||
return obj && obj.type === 'variable';
|
return obj && obj.type === 'variable';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getCurrentFieldIds() {
|
||||||
|
const editor = globalContext.get(Editor);
|
||||||
|
const designer = editor.get('designer');
|
||||||
|
const fieldIds: any = [];
|
||||||
|
const nodesMap = designer?.currentDocument?.nodesMap || new Map();
|
||||||
|
nodesMap.forEach((curNode: any) => {
|
||||||
|
const fieldId = nodesMap?.get(curNode.id)?.getPropValue('fieldId');
|
||||||
|
if (fieldId) {
|
||||||
|
fieldIds.push(fieldId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return fieldIds;
|
||||||
|
}
|
||||||
|
|||||||
71
packages/editor-preset-vision/tests/bundle/prototype.test.ts
Normal file
71
packages/editor-preset-vision/tests/bundle/prototype.test.ts
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
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 divPrototypeConfig from '../fixtures/prototype/div-vision';
|
||||||
|
import divPrototypeMeta from '../fixtures/prototype/div-meta';
|
||||||
|
// import VisualEngine from '../../src';
|
||||||
|
import { designer } from '../../src/editor';
|
||||||
|
import Prototype from '../../src/bundle/prototype';
|
||||||
|
import { Editor } from '@ali/lowcode-editor-core';
|
||||||
|
// import { getIdsFromSchema, getNodeFromSchemaById } from '../utils';
|
||||||
|
|
||||||
|
|
||||||
|
describe('Prototype', () => {
|
||||||
|
it('构造函数 - OldPrototypeConfig', () => {
|
||||||
|
const proto = new Prototype(divPrototypeConfig);
|
||||||
|
expect(proto.getComponentName()).toBe('Div');
|
||||||
|
expect(proto.getId()).toBe('Div');
|
||||||
|
expect(proto.getCategory()).toBe('布局');
|
||||||
|
expect(proto.getDocUrl()).toBe('http://gitlab.alibaba-inc.com/vision-components/vc-block/blob/master/README.md');
|
||||||
|
expect(proto.getIcon()).toBeUndefined;
|
||||||
|
expect(proto.getTitle()).toBe('Div');
|
||||||
|
expect(proto.isPrototype).toBeTruthy;
|
||||||
|
expect(proto.isContainer()).toBeTruthy;
|
||||||
|
expect(proto.isModal()).toBeFalsy;
|
||||||
|
});
|
||||||
|
it('构造函数 - ComponentMetadata', () => {
|
||||||
|
const proto = new Prototype(divPrototypeMeta);
|
||||||
|
expect(proto.getComponentName()).toBe('Div');
|
||||||
|
expect(proto.getId()).toBe('Div');
|
||||||
|
expect(proto.getCategory()).toBe('布局');
|
||||||
|
expect(proto.getDocUrl()).toBe('http://gitlab.alibaba-inc.com/vision-components/vc-block/blob/master/README.md');
|
||||||
|
expect(proto.getIcon()).toBeUndefined;
|
||||||
|
expect(proto.getTitle()).toBe('Div');
|
||||||
|
expect(proto.isPrototype).toBeTruthy;
|
||||||
|
expect(proto.isContainer()).toBeTruthy;
|
||||||
|
expect(proto.isModal()).toBeFalsy;
|
||||||
|
});
|
||||||
|
it('构造函数 - ComponentMeta', () => {
|
||||||
|
const meta = designer.createComponentMeta(divPrototypeMeta);
|
||||||
|
const proto = new Prototype(meta);
|
||||||
|
expect(proto.getComponentName()).toBe('Div');
|
||||||
|
expect(proto.getId()).toBe('Div');
|
||||||
|
expect(proto.getCategory()).toBe('布局');
|
||||||
|
expect(proto.getDocUrl()).toBe('http://gitlab.alibaba-inc.com/vision-components/vc-block/blob/master/README.md');
|
||||||
|
expect(proto.getIcon()).toBeUndefined;
|
||||||
|
expect(proto.getTitle()).toBe('Div');
|
||||||
|
expect(proto.isPrototype).toBeTruthy;
|
||||||
|
expect(proto.isContainer()).toBeTruthy;
|
||||||
|
expect(proto.isModal()).toBeFalsy;
|
||||||
|
});
|
||||||
|
it('构造函数 - 静态函数 create', () => {
|
||||||
|
const proto = Prototype.create(divPrototypeConfig);
|
||||||
|
expect(proto.getComponentName()).toBe('Div');
|
||||||
|
expect(proto.getId()).toBe('Div');
|
||||||
|
expect(proto.getCategory()).toBe('布局');
|
||||||
|
expect(proto.getDocUrl()).toBe('http://gitlab.alibaba-inc.com/vision-components/vc-block/blob/master/README.md');
|
||||||
|
expect(proto.getIcon()).toBeUndefined;
|
||||||
|
expect(proto.getTitle()).toBe('Div');
|
||||||
|
expect(proto.isPrototype).toBeTruthy;
|
||||||
|
expect(proto.isContainer()).toBeTruthy;
|
||||||
|
expect(proto.isModal()).toBeFalsy;
|
||||||
|
});
|
||||||
|
it('构造函数 - lookup: true', () => {
|
||||||
|
const proto = Prototype.create(divPrototypeConfig);
|
||||||
|
const proto2 = Prototype.create(divPrototypeConfig, {}, true);
|
||||||
|
expect(proto).toBe(proto2);
|
||||||
|
});
|
||||||
|
});
|
||||||
259
packages/editor-preset-vision/tests/fixtures/prototype/div-meta.ts
vendored
Normal file
259
packages/editor-preset-vision/tests/fixtures/prototype/div-meta.ts
vendored
Normal file
@ -0,0 +1,259 @@
|
|||||||
|
export default {
|
||||||
|
componentName: 'Div',
|
||||||
|
title: '容器',
|
||||||
|
docUrl: 'http://gitlab.alibaba-inc.com/vision-components/vc-block/blob/master/README.md',
|
||||||
|
devMode: 'procode',
|
||||||
|
tags: ['布局'],
|
||||||
|
configure: {
|
||||||
|
props: [
|
||||||
|
{
|
||||||
|
type: 'field',
|
||||||
|
name: 'behavior',
|
||||||
|
title: '默认状态',
|
||||||
|
extraProps: {
|
||||||
|
display: 'inline',
|
||||||
|
defaultValue: 'NORMAL',
|
||||||
|
},
|
||||||
|
setter: {
|
||||||
|
componentName: 'MixedSetter',
|
||||||
|
props: {
|
||||||
|
setters: [
|
||||||
|
{
|
||||||
|
key: null,
|
||||||
|
ref: null,
|
||||||
|
props: {
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
title: '普通',
|
||||||
|
value: 'NORMAL',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '隐藏',
|
||||||
|
value: 'HIDDEN',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
loose: false,
|
||||||
|
cancelable: false,
|
||||||
|
},
|
||||||
|
_owner: null,
|
||||||
|
},
|
||||||
|
'VariableSetter',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'field',
|
||||||
|
name: '__style__',
|
||||||
|
title: {
|
||||||
|
label: '样式设置',
|
||||||
|
tip: '点击 ? 查看样式设置器用法指南',
|
||||||
|
docUrl: 'https://lark.alipay.com/legao/help/design-tool-style',
|
||||||
|
},
|
||||||
|
extraProps: {
|
||||||
|
display: 'accordion',
|
||||||
|
defaultValue: {},
|
||||||
|
},
|
||||||
|
setter: {
|
||||||
|
key: null,
|
||||||
|
ref: null,
|
||||||
|
props: {
|
||||||
|
advanced: true,
|
||||||
|
},
|
||||||
|
_owner: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'group',
|
||||||
|
name: 'groupkh97h5kc',
|
||||||
|
title: '高级',
|
||||||
|
extraProps: {
|
||||||
|
display: 'accordion',
|
||||||
|
},
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
type: 'field',
|
||||||
|
name: 'fieldId',
|
||||||
|
title: {
|
||||||
|
label: '唯一标识',
|
||||||
|
},
|
||||||
|
extraProps: {
|
||||||
|
display: 'block',
|
||||||
|
},
|
||||||
|
setter: {
|
||||||
|
key: null,
|
||||||
|
ref: null,
|
||||||
|
props: {
|
||||||
|
placeholder: '请输入唯一标识',
|
||||||
|
multiline: false,
|
||||||
|
rows: 10,
|
||||||
|
required: false,
|
||||||
|
pattern: null,
|
||||||
|
maxLength: null,
|
||||||
|
},
|
||||||
|
_owner: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'field',
|
||||||
|
name: 'useFieldIdAsDomId',
|
||||||
|
title: {
|
||||||
|
label: '将唯一标识用作 DOM ID',
|
||||||
|
},
|
||||||
|
extraProps: {
|
||||||
|
display: 'block',
|
||||||
|
defaultValue: false,
|
||||||
|
},
|
||||||
|
setter: {
|
||||||
|
key: null,
|
||||||
|
ref: null,
|
||||||
|
props: {},
|
||||||
|
_owner: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'field',
|
||||||
|
name: 'customClassName',
|
||||||
|
title: '自定义样式类',
|
||||||
|
extraProps: {
|
||||||
|
display: 'block',
|
||||||
|
defaultValue: '',
|
||||||
|
},
|
||||||
|
setter: {
|
||||||
|
componentName: 'MixedSetter',
|
||||||
|
props: {
|
||||||
|
setters: [
|
||||||
|
{
|
||||||
|
key: null,
|
||||||
|
ref: null,
|
||||||
|
props: {
|
||||||
|
placeholder: null,
|
||||||
|
multiline: false,
|
||||||
|
rows: 10,
|
||||||
|
required: false,
|
||||||
|
pattern: null,
|
||||||
|
maxLength: null,
|
||||||
|
},
|
||||||
|
_owner: null,
|
||||||
|
},
|
||||||
|
'VariableSetter',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'field',
|
||||||
|
name: 'events',
|
||||||
|
title: {
|
||||||
|
label: '动作设置',
|
||||||
|
tip: '点击 ? 查看如何设置组件的事件响应动作',
|
||||||
|
docUrl: 'https://lark.alipay.com/legao/legao/events-call',
|
||||||
|
},
|
||||||
|
extraProps: {
|
||||||
|
display: 'accordion',
|
||||||
|
defaultValue: {
|
||||||
|
ignored: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
setter: {
|
||||||
|
key: null,
|
||||||
|
ref: null,
|
||||||
|
props: {
|
||||||
|
events: [
|
||||||
|
{
|
||||||
|
name: 'onClick',
|
||||||
|
title: '当点击时',
|
||||||
|
initialValue:
|
||||||
|
"/**\n * 容器 当点击时\n */\nfunction onClick(event) {\n console.log('onClick', event);\n}",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'onMouseEnter',
|
||||||
|
title: '当鼠标进入时',
|
||||||
|
initialValue:
|
||||||
|
"/**\n * 容器 当鼠标进入时\n */\nfunction onMouseEnter(event) {\n console.log('onMouseEnter', event);\n}",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'onMouseLeave',
|
||||||
|
title: '当鼠标离开时',
|
||||||
|
initialValue:
|
||||||
|
"/**\n * 容器 当鼠标离开时\n */\nfunction onMouseLeave(event) {\n console.log('onMouseLeave', event);\n}",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
_owner: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'field',
|
||||||
|
name: 'onClick',
|
||||||
|
extraProps: {
|
||||||
|
defaultValue: {
|
||||||
|
ignored: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
setter: 'I18nSetter',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'field',
|
||||||
|
name: 'onMouseEnter',
|
||||||
|
extraProps: {
|
||||||
|
defaultValue: {
|
||||||
|
ignored: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
setter: 'I18nSetter',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'field',
|
||||||
|
name: 'onMouseLeave',
|
||||||
|
extraProps: {
|
||||||
|
defaultValue: {
|
||||||
|
ignored: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
setter: 'I18nSetter',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
component: {
|
||||||
|
isContainer: true,
|
||||||
|
nestingRule: {},
|
||||||
|
},
|
||||||
|
supports: {},
|
||||||
|
},
|
||||||
|
experimental: {
|
||||||
|
callbacks: {},
|
||||||
|
initials: [
|
||||||
|
{
|
||||||
|
name: 'behavior',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '__style__',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'fieldId',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'useFieldIdAsDomId',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'customClassName',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'events',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'onClick',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'onMouseEnter',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'onMouseLeave',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
filters: [],
|
||||||
|
autoruns: [],
|
||||||
|
},
|
||||||
|
};
|
||||||
175
packages/editor-preset-vision/tests/fixtures/prototype/div-vision.ts
vendored
Normal file
175
packages/editor-preset-vision/tests/fixtures/prototype/div-vision.ts
vendored
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
export default {
|
||||||
|
title: '容器',
|
||||||
|
componentName: 'Div',
|
||||||
|
docUrl: 'http://gitlab.alibaba-inc.com/vision-components/vc-block/blob/master/README.md',
|
||||||
|
category: '布局',
|
||||||
|
isContainer: true,
|
||||||
|
configure: [
|
||||||
|
{
|
||||||
|
name: 'behavior',
|
||||||
|
title: '默认状态',
|
||||||
|
display: 'inline',
|
||||||
|
initialValue: 'NORMAL',
|
||||||
|
supportVariable: true,
|
||||||
|
setter: {
|
||||||
|
key: null,
|
||||||
|
ref: null,
|
||||||
|
props: {
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
title: '普通',
|
||||||
|
value: 'NORMAL',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '隐藏',
|
||||||
|
value: 'HIDDEN',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
loose: false,
|
||||||
|
cancelable: false,
|
||||||
|
},
|
||||||
|
_owner: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '__style__',
|
||||||
|
title: '样式设置',
|
||||||
|
display: 'accordion',
|
||||||
|
collapsed: false,
|
||||||
|
initialValue: {},
|
||||||
|
tip: {
|
||||||
|
url: 'https://lark.alipay.com/legao/help/design-tool-style',
|
||||||
|
content: '点击 ? 查看样式设置器用法指南',
|
||||||
|
},
|
||||||
|
setter: {
|
||||||
|
key: null,
|
||||||
|
ref: null,
|
||||||
|
props: {
|
||||||
|
advanced: true,
|
||||||
|
},
|
||||||
|
_owner: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'group',
|
||||||
|
title: '高级',
|
||||||
|
display: 'accordion',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
name: 'fieldId',
|
||||||
|
title: '唯一标识',
|
||||||
|
display: 'block',
|
||||||
|
tip:
|
||||||
|
'组件的唯一标识符,不能够与其它组件重名,不能够为空,且只能够使用以字母开头的,下划线以及数字的组合。',
|
||||||
|
setter: {
|
||||||
|
key: null,
|
||||||
|
ref: null,
|
||||||
|
props: {
|
||||||
|
placeholder: '请输入唯一标识',
|
||||||
|
multiline: false,
|
||||||
|
rows: 10,
|
||||||
|
required: false,
|
||||||
|
pattern: null,
|
||||||
|
maxLength: null,
|
||||||
|
},
|
||||||
|
_owner: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'useFieldIdAsDomId',
|
||||||
|
title: '将唯一标识用作 DOM ID',
|
||||||
|
display: 'block',
|
||||||
|
tip:
|
||||||
|
'开启这个配置项后,会在当前组件的 HTML 元素上加入 id="当前组件的 fieldId",一般用于做 utils 的绑定,不常用',
|
||||||
|
initialValue: false,
|
||||||
|
setter: {
|
||||||
|
key: null,
|
||||||
|
ref: null,
|
||||||
|
props: {},
|
||||||
|
_owner: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'customClassName',
|
||||||
|
title: '自定义样式类',
|
||||||
|
display: 'block',
|
||||||
|
supportVariable: true,
|
||||||
|
initialValue: '',
|
||||||
|
setter: {
|
||||||
|
key: null,
|
||||||
|
ref: null,
|
||||||
|
props: {
|
||||||
|
placeholder: null,
|
||||||
|
multiline: false,
|
||||||
|
rows: 10,
|
||||||
|
required: false,
|
||||||
|
pattern: null,
|
||||||
|
maxLength: null,
|
||||||
|
},
|
||||||
|
_owner: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'events',
|
||||||
|
title: '动作设置',
|
||||||
|
tip: {
|
||||||
|
url: 'https://lark.alipay.com/legao/legao/events-call',
|
||||||
|
content: '点击 ? 查看如何设置组件的事件响应动作',
|
||||||
|
},
|
||||||
|
display: 'accordion',
|
||||||
|
initialValue: {
|
||||||
|
ignored: true,
|
||||||
|
},
|
||||||
|
setter: {
|
||||||
|
key: null,
|
||||||
|
ref: null,
|
||||||
|
props: {
|
||||||
|
events: [
|
||||||
|
{
|
||||||
|
name: 'onClick',
|
||||||
|
title: '当点击时',
|
||||||
|
initialValue:
|
||||||
|
"/**\n * 容器 当点击时\n */\nfunction onClick(event) {\n console.log('onClick', event);\n}",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'onMouseEnter',
|
||||||
|
title: '当鼠标进入时',
|
||||||
|
initialValue:
|
||||||
|
"/**\n * 容器 当鼠标进入时\n */\nfunction onMouseEnter(event) {\n console.log('onMouseEnter', event);\n}",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'onMouseLeave',
|
||||||
|
title: '当鼠标离开时',
|
||||||
|
initialValue:
|
||||||
|
"/**\n * 容器 当鼠标离开时\n */\nfunction onMouseLeave(event) {\n console.log('onMouseLeave', event);\n}",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
_owner: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'onClick',
|
||||||
|
display: 'none',
|
||||||
|
initialValue: {
|
||||||
|
ignored: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'onMouseEnter',
|
||||||
|
display: 'none',
|
||||||
|
initialValue: {
|
||||||
|
ignored: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'onMouseLeave',
|
||||||
|
display: 'none',
|
||||||
|
initialValue: {
|
||||||
|
ignored: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
@ -1,76 +1,4 @@
|
|||||||
export default {
|
export default {
|
||||||
schemaType: 'superform',
|
|
||||||
schemaVersion: '5.0',
|
|
||||||
pages: [
|
|
||||||
{
|
|
||||||
componentsMap: [
|
|
||||||
{
|
|
||||||
componentName: 'Text',
|
|
||||||
package: '@ali/vc-text',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
componentName: 'Slot',
|
|
||||||
package: '@ali/vc-slot',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
componentName: 'PageHeader',
|
|
||||||
package: '@ali/vc-deep',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
componentName: 'RootHeader',
|
|
||||||
package: '@ali/vc-page',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
componentName: 'TextField',
|
|
||||||
package: '@ali/vc-deep',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
componentName: 'Column',
|
|
||||||
package: '@ali/vc-deep',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
componentName: 'SelectField',
|
|
||||||
package: '@ali/vc-deep',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
componentName: 'ColumnsLayout',
|
|
||||||
package: '@ali/vc-deep',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
componentName: 'CardContent',
|
|
||||||
package: '@ali/vc-deep',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
componentName: 'Card',
|
|
||||||
package: '@ali/vc-deep',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
componentName: 'Button',
|
|
||||||
package: '@ali/vc-deep',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
componentName: 'Div',
|
|
||||||
package: '@ali/vc-div',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
componentName: 'Form',
|
|
||||||
package: '@ali/vc-deep',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
componentName: 'RootContent',
|
|
||||||
package: '@ali/vc-page',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
componentName: 'RootFooter',
|
|
||||||
package: '@ali/vc-page',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
componentName: 'Page',
|
|
||||||
package: '@ali/vc-page',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
componentsTree: [
|
|
||||||
{
|
|
||||||
componentName: 'Page',
|
componentName: 'Page',
|
||||||
id: 'node_k1ow3cb9',
|
id: 'node_k1ow3cb9',
|
||||||
props: {
|
props: {
|
||||||
@ -131,40 +59,7 @@ export default {
|
|||||||
extraContent: '',
|
extraContent: '',
|
||||||
__slot__extraContent: false,
|
__slot__extraContent: false,
|
||||||
__slot__action: false,
|
__slot__action: false,
|
||||||
title: {
|
title: '',
|
||||||
type: 'JSBlock',
|
|
||||||
value: {
|
|
||||||
componentName: 'Slot',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
componentName: 'Text',
|
|
||||||
id: 'node_k1ow3cbf',
|
|
||||||
props: {
|
|
||||||
showTitle: false,
|
|
||||||
behavior: 'NORMAL',
|
|
||||||
content: {
|
|
||||||
type: 'variable',
|
|
||||||
value: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
en_US: 'Title',
|
|
||||||
zh_CN: '个人信息',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
variable: 'state.title',
|
|
||||||
},
|
|
||||||
__style__: {},
|
|
||||||
fieldId: 'text_k1ow3h1j',
|
|
||||||
maxLine: 0,
|
|
||||||
},
|
|
||||||
condition: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
props: {
|
|
||||||
slotTitle: '标题区域',
|
|
||||||
slotName: 'title',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
content: '',
|
content: '',
|
||||||
__slot__logo: false,
|
__slot__logo: false,
|
||||||
__slot__crumb: false,
|
__slot__crumb: false,
|
||||||
@ -176,34 +71,7 @@ export default {
|
|||||||
__style__: {},
|
__style__: {},
|
||||||
__slot__content: false,
|
__slot__content: false,
|
||||||
fieldId: 'pageHeader_k1ow3h1i',
|
fieldId: 'pageHeader_k1ow3h1i',
|
||||||
subTitle: {
|
subTitle: '',
|
||||||
type: 'JSBlock',
|
|
||||||
value: {
|
|
||||||
componentName: 'Slot',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
componentName: 'Text',
|
|
||||||
id: 'node_ockh05zr7j3',
|
|
||||||
props: {
|
|
||||||
content: {
|
|
||||||
type: 'i18n',
|
|
||||||
en_US: 'Title',
|
|
||||||
zh_CN: '副标题',
|
|
||||||
},
|
|
||||||
showTitle: false,
|
|
||||||
behavior: 'NORMAL',
|
|
||||||
maxLine: 0,
|
|
||||||
__style__: {},
|
|
||||||
fieldId: 'text_kh06n1mc',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
props: {
|
|
||||||
slotTitle: '副标题',
|
|
||||||
slotName: 'subTitle',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
condition: true,
|
condition: true,
|
||||||
},
|
},
|
||||||
@ -1084,28 +952,4 @@ export default {
|
|||||||
condition: true,
|
condition: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
|
||||||
],
|
|
||||||
id: 'FORM-MV766X71QI5KCL6T4CXKF9DJUME73BD0FQAGKE',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
actions: {
|
|
||||||
module: {
|
|
||||||
compiled:
|
|
||||||
"'use strict';\n\nexports.__esModule = true;\nexports.helloPage = helloPage;\nexports.submit = submit;\n/**\n * 私有函数,只能JS面板内部调用\n * 动作面板帮助文档:\n * @see https://lark.alipay.com/legao/help/design-tool-logic\n */\nfunction printLog(obj) {\n console.info(obj);\n}\n\n/**\n * 页面内的函数,可以被页面内任何位置调用\n */\nfunction helloPage() {\n console.log('hello page');\n}\n\n/**\n* button onClick\n*/\nfunction submit() {\n var _this = this;\n\n this.$('form').submit(function (data, error) {\n if (data) {\n console.log(data); // 这是表单提交的数据\n _this.utils.toast({\n type: 'success',\n title: '提交成功'\n });\n }\n });\n}",
|
|
||||||
source:
|
|
||||||
"/**\n * 私有函数,只能JS面板内部调用\n * 动作面板帮助文档:\n * @see https://lark.alipay.com/legao/help/design-tool-logic\n */\nfunction printLog(obj) {\n console.info(obj);\n}\n\n/**\n * 页面内的函数,可以被页面内任何位置调用\n */\nexport function helloPage() {\n console.log('hello page');\n}\n\n\n/**\n* button onClick\n*/\nexport function submit(){\n this.$('form').submit((data, error) => {\n if (data) {\n console.log(data); // 这是表单提交的数据\n this.utils.toast({\n type: 'success',\n title: '提交成功'\n });\n }\n });\n}",
|
|
||||||
},
|
|
||||||
type: 'FUNCTION',
|
|
||||||
list: [
|
|
||||||
{
|
|
||||||
id: 'helloPage',
|
|
||||||
title: 'helloPage',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'submit',
|
|
||||||
title: 'submit',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|||||||
1
packages/editor-preset-vision/tests/utils/index.ts
Normal file
1
packages/editor-preset-vision/tests/utils/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { getIdsFromSchema, getNodeFromSchemaById } from '@ali/lowcode-test-mate/es/utils';
|
||||||
@ -0,0 +1,89 @@
|
|||||||
|
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 VisualEngine, {
|
||||||
|
designer,
|
||||||
|
editor,
|
||||||
|
skeleton,
|
||||||
|
/**
|
||||||
|
* VE.Popup
|
||||||
|
*/
|
||||||
|
Popup,
|
||||||
|
/**
|
||||||
|
* VE Utils
|
||||||
|
*/
|
||||||
|
utils,
|
||||||
|
I18nUtil,
|
||||||
|
Hotkey,
|
||||||
|
Env,
|
||||||
|
monitor,
|
||||||
|
/* pub/sub 集线器 */
|
||||||
|
Bus,
|
||||||
|
/* 事件 */
|
||||||
|
EVENTS,
|
||||||
|
/* 修饰方法 */
|
||||||
|
HOOKS,
|
||||||
|
Exchange,
|
||||||
|
context,
|
||||||
|
/**
|
||||||
|
* VE.init
|
||||||
|
*
|
||||||
|
* Initialized the whole VisualEngine UI
|
||||||
|
*/
|
||||||
|
init,
|
||||||
|
ui,
|
||||||
|
Panes,
|
||||||
|
modules,
|
||||||
|
Trunk,
|
||||||
|
Prototype,
|
||||||
|
Bundle,
|
||||||
|
Pages,
|
||||||
|
DragEngine,
|
||||||
|
Viewport,
|
||||||
|
Version,
|
||||||
|
Project,
|
||||||
|
logger,
|
||||||
|
Symbols,
|
||||||
|
} from '../../src';
|
||||||
|
import { Editor } from '@ali/lowcode-editor-core';
|
||||||
|
|
||||||
|
describe('API 多种导出场景测试', () => {
|
||||||
|
it('window.VisualEngine 和 npm 导出 API 测试', () => {
|
||||||
|
expect(VisualEngine).toBe(window.VisualEngine);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('npm 导出 API 对比测试', () => {
|
||||||
|
expect(VisualEngine.designer).toBe(designer);
|
||||||
|
expect(VisualEngine.editor).toBe(editor);
|
||||||
|
expect(VisualEngine.skeleton).toBe(skeleton);
|
||||||
|
expect(VisualEngine.Popup).toBe(Popup);
|
||||||
|
expect(VisualEngine.utils).toBe(utils);
|
||||||
|
expect(VisualEngine.I18nUtil).toBe(I18nUtil);
|
||||||
|
expect(VisualEngine.Hotkey).toBe(Hotkey);
|
||||||
|
expect(VisualEngine.Env).toBe(Env);
|
||||||
|
expect(VisualEngine.monitor).toBe(monitor);
|
||||||
|
expect(VisualEngine.Bus).toBe(Bus);
|
||||||
|
expect(VisualEngine.EVENTS).toBe(EVENTS);
|
||||||
|
expect(VisualEngine.HOOKS).toBe(HOOKS);
|
||||||
|
expect(VisualEngine.Exchange).toBe(Exchange);
|
||||||
|
expect(VisualEngine.context).toBe(context);
|
||||||
|
expect(VisualEngine.init).toBe(init);
|
||||||
|
expect(VisualEngine.ui).toBe(ui);
|
||||||
|
expect(VisualEngine.Panes).toBe(Panes);
|
||||||
|
expect(VisualEngine.modules).toBe(modules);
|
||||||
|
expect(VisualEngine.Trunk).toBe(Trunk);
|
||||||
|
expect(VisualEngine.Prototype).toBe(Prototype);
|
||||||
|
expect(VisualEngine.Bundle).toBe(Bundle);
|
||||||
|
expect(VisualEngine.DragEngine).toBe(DragEngine);
|
||||||
|
expect(VisualEngine.Pages).toBe(Pages);
|
||||||
|
expect(VisualEngine.Viewport).toBe(Viewport);
|
||||||
|
expect(VisualEngine.Version).toBe(Version);
|
||||||
|
expect(VisualEngine.Project).toBe(Project);
|
||||||
|
expect(VisualEngine.logger).toBe(logger);
|
||||||
|
expect(VisualEngine.Symbols).toBe(Symbols);
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -1,46 +1,161 @@
|
|||||||
import set from 'lodash/set';
|
import set from 'lodash/set';
|
||||||
import cloneDeep from 'lodash/clonedeep';
|
import cloneDeep from 'lodash/clonedeep';
|
||||||
import '../fixtures/window';
|
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 formSchema from '../fixtures/schema/form';
|
||||||
import VisualEngine from '../../src';
|
import VisualEngine from '../../src';
|
||||||
// import { getIdsFromSchema, getNodeFromSchemaById } from '../utils';
|
import { Editor } from '@ali/lowcode-editor-core';
|
||||||
|
import { getIdsFromSchema, getNodeFromSchemaById } from '../utils';
|
||||||
|
|
||||||
// const mockCreateSettingEntry = jest.fn();
|
const pageSchema = { componentsTree: [formSchema] };
|
||||||
// jest.mock('../../src/designer/designer', () => {
|
|
||||||
// return {
|
|
||||||
// Designer: jest.fn().mockImplementation(() => {
|
|
||||||
// return {
|
|
||||||
// getComponentMeta() {
|
|
||||||
// return {
|
|
||||||
// getMetadata() {
|
|
||||||
// return { experimental: null };
|
|
||||||
// },
|
|
||||||
// };
|
|
||||||
// },
|
|
||||||
// transformProps(props) { return props; },
|
|
||||||
// createSettingEntry: mockCreateSettingEntry,
|
|
||||||
// postEvent() {},
|
|
||||||
// };
|
|
||||||
// }),
|
|
||||||
// };
|
|
||||||
// });
|
|
||||||
|
|
||||||
|
describe('VisualEngine.Pages 相关 API 测试', () => {
|
||||||
|
afterEach(() => {
|
||||||
|
VisualEngine.Pages.unload();
|
||||||
|
});
|
||||||
|
describe('addPage 系列', () => {
|
||||||
|
it('基本的节点模型初始化,初始化传入 schema', () => {
|
||||||
|
const doc = VisualEngine.Pages.addPage(pageSchema)!;
|
||||||
|
expect(doc).toBeTruthy();
|
||||||
|
const ids = getIdsFromSchema(formSchema);
|
||||||
|
const expectedNodeCnt = ids.length;
|
||||||
|
expect(doc.nodesMap.size).toBe(expectedNodeCnt);
|
||||||
|
});
|
||||||
|
it('基本的节点模型初始化,初始化传入 schema,带有 slot', () => {
|
||||||
|
const formSchemaWithSlot = set(cloneDeep(formSchema), 'children[0].children[0].props.title', {
|
||||||
|
type: 'JSBlock',
|
||||||
|
value: {
|
||||||
|
componentName: 'Slot',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
componentName: 'Text',
|
||||||
|
id: 'node_k1ow3cbf',
|
||||||
|
props: {
|
||||||
|
showTitle: false,
|
||||||
|
behavior: 'NORMAL',
|
||||||
|
content: {
|
||||||
|
type: 'variable',
|
||||||
|
value: {
|
||||||
|
use: 'zh_CN',
|
||||||
|
en_US: 'Title',
|
||||||
|
zh_CN: '个人信息',
|
||||||
|
type: 'i18n',
|
||||||
|
},
|
||||||
|
variable: 'state.title',
|
||||||
|
},
|
||||||
|
__style__: {},
|
||||||
|
fieldId: 'text_k1ow3h1j',
|
||||||
|
maxLine: 0,
|
||||||
|
},
|
||||||
|
condition: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
props: {
|
||||||
|
slotTitle: '标题区域',
|
||||||
|
slotName: 'title',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const doc = VisualEngine.Pages.addPage({ componentsTree: [formSchemaWithSlot] })!;
|
||||||
|
expect(doc).toBeTruthy();
|
||||||
|
const ids = getIdsFromSchema(formSchema);
|
||||||
|
const expectedNodeCnt = ids.length;
|
||||||
|
// slot 会多出(1 + N)个节点
|
||||||
|
expect(doc.nodesMap.size).toBe(expectedNodeCnt + 2);
|
||||||
|
});
|
||||||
|
it('导出 schema', () => {
|
||||||
|
const doc = VisualEngine.Pages.addPage(pageSchema)!;
|
||||||
|
expect(doc).toBeTruthy();
|
||||||
|
const ids = getIdsFromSchema(formSchema);
|
||||||
|
const expectedNodeCnt = ids.length;
|
||||||
|
const exportedData = doc.toData();
|
||||||
|
expect(exportedData).toHaveProperty('componentsMap');
|
||||||
|
expect(exportedData).toHaveProperty('componentsTree');
|
||||||
|
expect(exportedData.componentsTree).toHaveLength(1);
|
||||||
|
const exportedSchema = exportedData.componentsTree[0];
|
||||||
|
expect(getIdsFromSchema(exportedSchema).length).toBe(expectedNodeCnt);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('removePage 系列', () => {
|
||||||
|
it('removePage', () => {
|
||||||
|
const doc = VisualEngine.Pages.addPage(pageSchema)!;
|
||||||
|
expect(doc).toBeTruthy();
|
||||||
|
expect(VisualEngine.Pages.documents).toHaveLength(1);
|
||||||
|
VisualEngine.Pages.removePage(doc);
|
||||||
|
expect(VisualEngine.Pages.documents).toHaveLength(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('getPage 系列', () => {
|
||||||
|
it('getPage', () => {
|
||||||
|
const doc = VisualEngine.Pages.addPage(pageSchema);
|
||||||
|
const anotherFormSchema = set(cloneDeep(formSchema), 'id', 'page');
|
||||||
|
const doc2 = VisualEngine.Pages.addPage({ componentsTree: [anotherFormSchema] });
|
||||||
|
expect(VisualEngine.Pages.getPage(0)).toBe(doc);
|
||||||
|
expect(VisualEngine.Pages.getPage((_doc) => _doc.rootNode.id === 'page')).toBe(doc2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('setPages 系列', () => {
|
||||||
|
it('setPages componentsTree 只有一个元素', () => {
|
||||||
|
VisualEngine.Pages.setPages([pageSchema]);
|
||||||
|
const { currentDocument } = VisualEngine.Pages;
|
||||||
|
const ids = getIdsFromSchema(formSchema);
|
||||||
|
const expectedNodeCnt = ids.length;
|
||||||
|
const exportedData = currentDocument.toData();
|
||||||
|
expect(exportedData).toHaveProperty('componentsMap');
|
||||||
|
expect(exportedData).toHaveProperty('componentsTree');
|
||||||
|
expect(exportedData.componentsTree).toHaveLength(1);
|
||||||
|
const exportedSchema = exportedData.componentsTree[0];
|
||||||
|
expect(getIdsFromSchema(exportedSchema).length).toBe(expectedNodeCnt);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('setCurrentPage / getCurrentPage / currentPage / currentDocument 系列', () => {
|
||||||
|
it('getCurrentPage', () => {
|
||||||
|
const doc = VisualEngine.Pages.addPage(pageSchema)!;
|
||||||
|
expect(doc).toBeTruthy();
|
||||||
|
expect(doc).toBe(VisualEngine.Pages.getCurrentPage());
|
||||||
|
expect(doc).toBe(VisualEngine.Pages.currentDocument);
|
||||||
|
expect(doc).toBe(VisualEngine.Pages.currentPage);
|
||||||
|
});
|
||||||
|
it('setCurrentPage', () => {
|
||||||
|
const doc = VisualEngine.Pages.addPage(pageSchema);
|
||||||
|
expect(doc).toBe(VisualEngine.Pages.currentDocument);
|
||||||
|
const anotherFormSchema = set(cloneDeep(formSchema), 'id', 'page');
|
||||||
|
const doc2 = VisualEngine.Pages.addPage({ componentsTree: [anotherFormSchema] });
|
||||||
|
expect(doc2).toBe(VisualEngine.Pages.currentDocument);
|
||||||
|
VisualEngine.Pages.setCurrentPage(doc);
|
||||||
|
expect(doc).toBe(VisualEngine.Pages.currentDocument);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('onCurrentPageChange 系列', () => {
|
||||||
|
it('多次切换', () => {
|
||||||
|
const doc = VisualEngine.Pages.addPage(pageSchema);
|
||||||
|
const anotherFormSchema = set(cloneDeep(formSchema), 'id', 'page');
|
||||||
|
const doc2 = VisualEngine.Pages.addPage({ componentsTree: [anotherFormSchema] });
|
||||||
|
const docChangeHandler = jest.fn();
|
||||||
|
VisualEngine.Pages.onCurrentDocumentChange(docChangeHandler);
|
||||||
|
VisualEngine.Pages.setCurrentPage(doc);
|
||||||
|
expect(docChangeHandler).toHaveBeenCalledTimes(1);
|
||||||
|
expect(docChangeHandler).toHaveBeenLastCalledWith(doc);
|
||||||
|
|
||||||
|
VisualEngine.Pages.setCurrentPage(doc2);
|
||||||
// let designer = null;
|
expect(docChangeHandler).toHaveBeenCalledTimes(2);
|
||||||
// beforeAll(() => {
|
expect(docChangeHandler).toHaveBeenLastCalledWith(doc2);
|
||||||
// designer = new Designer({});
|
});
|
||||||
// });
|
});
|
||||||
|
describe('toData 系列', () => {
|
||||||
describe('schema 生成节点模型测试', () => {
|
|
||||||
describe('block ❌ | component ❌ | slot ❌', () => {
|
|
||||||
it('基本的节点模型初始化,模型导出,初始化传入 schema', () => {
|
it('基本的节点模型初始化,模型导出,初始化传入 schema', () => {
|
||||||
console.log(VisualEngine);
|
const doc = VisualEngine.Pages.addPage(pageSchema);
|
||||||
|
const anotherFormSchema = set(cloneDeep(formSchema), 'id', 'page');
|
||||||
console.log(VisualEngine.Pages.addPage(formSchema));
|
const doc2 = VisualEngine.Pages.addPage({ componentsTree: [anotherFormSchema] });
|
||||||
|
const dataList = VisualEngine.Pages.toData();
|
||||||
|
expect(dataList.length).toBe(2);
|
||||||
|
expect(dataList[0]).toHaveProperty('componentsMap');
|
||||||
|
expect(dataList[0]).toHaveProperty('componentsTree');
|
||||||
|
expect(dataList[0].componentsTree).toHaveLength(1);
|
||||||
|
expect(dataList[0].componentsTree[0].id).toBe('node_k1ow3cb9');
|
||||||
|
expect(dataList[1]).toHaveProperty('componentsMap');
|
||||||
|
expect(dataList[1]).toHaveProperty('componentsTree');
|
||||||
|
expect(dataList[1].componentsTree).toHaveLength(1);
|
||||||
|
expect(dataList[1].componentsTree[0].id).toBe('page');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
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 VisualEngine from '../../src';
|
||||||
|
import { Editor } from '@ali/lowcode-editor-core';
|
||||||
|
|
||||||
|
// import { getIdsFromSchema, getNodeFromSchemaById } from '../utils';
|
||||||
|
|
||||||
|
|
||||||
|
describe.skip('VisualEngine.Project 相关 API 测试', () => {
|
||||||
|
describe('getSchema / setSchema 系列', () => {
|
||||||
|
it('基本的节点模型初始化,模型导出,初始化传入 schema', () => {
|
||||||
|
// console.log(VisualEngine);
|
||||||
|
// console.log(Editor instanceof Function);
|
||||||
|
// console.log(Editor.toString())
|
||||||
|
// console.log(new Editor());
|
||||||
|
// console.log(Editor2 instanceof Function);
|
||||||
|
|
||||||
|
console.log(VisualEngine.Pages.addPage(formSchema));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('setConfig 系列', () => {
|
||||||
|
it('基本的节点模型初始化,模型导出,初始化传入 schema', () => {
|
||||||
|
// console.log(VisualEngine);
|
||||||
|
// console.log(Editor instanceof Function);
|
||||||
|
// console.log(Editor.toString())
|
||||||
|
// console.log(new Editor());
|
||||||
|
// console.log(Editor2 instanceof Function);
|
||||||
|
|
||||||
|
console.log(VisualEngine.Pages.addPage(formSchema));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
x
Reference in New Issue
Block a user