mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-06-02 13:41:01 +00:00
chore: 移除 vision-polyfill 代码
This commit is contained in:
parent
99e565291c
commit
392f60e86f
@ -1,7 +1,6 @@
|
|||||||
{
|
{
|
||||||
"entry": {
|
"entry": {
|
||||||
"engine-core": "../engine/src/index.ts",
|
"engine-core": "../engine/src/index.ts",
|
||||||
"vision-polyfill": "../vision-polyfill/src/index.ts",
|
|
||||||
"react-simulator-renderer": "../react-simulator-renderer/src/index.ts",
|
"react-simulator-renderer": "../react-simulator-renderer/src/index.ts",
|
||||||
"rax-simulator-renderer": "../rax-simulator-renderer/src/index.ts"
|
"rax-simulator-renderer": "../rax-simulator-renderer/src/index.ts"
|
||||||
},
|
},
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1,82 +0,0 @@
|
|||||||
子视图
|
|
||||||
prototype.view
|
|
||||||
view.Preview
|
|
||||||
view.Mobile
|
|
||||||
|
|
||||||
实时切
|
|
||||||
|
|
||||||
设备
|
|
||||||
device
|
|
||||||
创建多个 simulator
|
|
||||||
|
|
||||||
不同simulator 加载不同视图
|
|
||||||
|
|
||||||
这样有利于 环境隔离,比如 rax 和 react
|
|
||||||
|
|
||||||
适配规则
|
|
||||||
|
|
||||||
规则 1
|
|
||||||
mobile view.mobile.xxx
|
|
||||||
rax view.rax.xxx
|
|
||||||
miniapp view.miniapp.xxx
|
|
||||||
view.<device>.xxx
|
|
||||||
通配 view.xxx
|
|
||||||
|
|
||||||
universal
|
|
||||||
|
|
||||||
规则 2
|
|
||||||
urls: "view.js,view2 <device selector>, view3 <device selector>",
|
|
||||||
urls: [
|
|
||||||
"view.js",
|
|
||||||
"view.js *",
|
|
||||||
"view1.js mobile|pc",
|
|
||||||
"view2.js <device selector>"
|
|
||||||
]
|
|
||||||
|
|
||||||
环境通用资源
|
|
||||||
|
|
||||||
"react": {
|
|
||||||
"urls": [
|
|
||||||
"//g.alicdn.com/platform/c/react/16.5.2/react.min.js"
|
|
||||||
],
|
|
||||||
"library": "React",
|
|
||||||
"package": "react",
|
|
||||||
"version": "16.5.2",
|
|
||||||
"devices-for": "*" | ["mobile", "web"] | "rax|mobile"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
load legao assets
|
|
||||||
load all x-prototype-urls
|
|
||||||
|
|
||||||
|
|
||||||
load assets
|
|
||||||
|
|
||||||
build componentMeta
|
|
||||||
if has x-prototype-urls ,
|
|
||||||
load x-prototype-urls
|
|
||||||
call Bundle.createPrototype() or something register
|
|
||||||
got prototypeView
|
|
||||||
|
|
||||||
load schema
|
|
||||||
|
|
||||||
|
|
||||||
open schema
|
|
||||||
|
|
||||||
load simulator resources
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
simulator 中加载资源,根据 componentsMap 构建组件查询字典,
|
|
||||||
|
|
||||||
|
|
||||||
获取 view 相关的样式、脚本
|
|
||||||
获取 proto 相关的样式
|
|
||||||
在 simulator 中也加载一次
|
|
||||||
|
|
||||||
1. meta 信息构造
|
|
||||||
2. components 字典构造, proto.getView 或者 通过 npm 信息查询
|
|
||||||
3.
|
|
||||||
|
|
||||||
|
|
||||||
componentMeta 段描述的信息,如果包含 x-prototype-urls ,那么这个 meta 信息都可以丢掉
|
|
||||||
@ -1,38 +0,0 @@
|
|||||||
{
|
|
||||||
"entry": {
|
|
||||||
"vision-polyfill": "src/index"
|
|
||||||
},
|
|
||||||
"sourceMap": true,
|
|
||||||
"library": "___VisionPolyfill___",
|
|
||||||
"libraryTarget": "umd",
|
|
||||||
"externals": {
|
|
||||||
"react": "var window.React",
|
|
||||||
"react-dom": "var window.ReactDOM",
|
|
||||||
"prop-types": "var window.PropTypes",
|
|
||||||
"@ali/visualengine": "var window.VisualEngine",
|
|
||||||
"@ali/visualengine-utils": "var window.VisualEngineUtils",
|
|
||||||
"rax": "var window.Rax",
|
|
||||||
"monaco-editor/esm/vs/editor/editor.api": "var window.monaco",
|
|
||||||
"monaco-editor/esm/vs/editor/editor.main.js": "var window.monaco",
|
|
||||||
"@ali/lowcode-engine": "var window.AliLowCodeEngine",
|
|
||||||
"@ali/lowcode-engine-ext": "var window.AliLowCodeEngineExt",
|
|
||||||
"@alifd/next": "var Next",
|
|
||||||
"moment": "var moment",
|
|
||||||
"lodash": "var _",
|
|
||||||
"lodash.get": "var _.get",
|
|
||||||
"lodash.some": "var _.some"
|
|
||||||
},
|
|
||||||
"polyfill": false,
|
|
||||||
"outputDir": "dist",
|
|
||||||
"vendor": false,
|
|
||||||
"ignoreHtmlTemplate": true,
|
|
||||||
"plugins": [
|
|
||||||
"build-plugin-react-app",
|
|
||||||
["build-plugin-fusion", {
|
|
||||||
}],
|
|
||||||
["build-plugin-moment-locales", {
|
|
||||||
"locales": ["zh-cn"]
|
|
||||||
}],
|
|
||||||
"./build.plugin.js"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
{
|
|
||||||
"plugins": [
|
|
||||||
[
|
|
||||||
"build-plugin-component",
|
|
||||||
{
|
|
||||||
"filename": "vision-polyfill",
|
|
||||||
"library": "VisualEngine",
|
|
||||||
"libraryTarget": "umd",
|
|
||||||
"externals": {
|
|
||||||
"react": "var window.React",
|
|
||||||
"react-dom": "var window.ReactDOM",
|
|
||||||
"prop-types": "var window.PropTypes",
|
|
||||||
"@ali/visualengine": "var window.VisualEngine",
|
|
||||||
"@ali/lowcode-engine": "var window.AliLowCodeEngine",
|
|
||||||
"@ali/visualengine-utils": "var window.VisualEngineUtils",
|
|
||||||
"rax": "var window.Rax",
|
|
||||||
"moment": "var window.moment",
|
|
||||||
"monaco-editor/esm/vs/editor/editor.api": "var window.monaco",
|
|
||||||
"monaco-editor/esm/vs/editor/editor.main.js": "var window.monaco"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"build-plugin-fusion",
|
|
||||||
["build-plugin-moment-locales", {
|
|
||||||
"locales": ["zh-cn"]
|
|
||||||
}],
|
|
||||||
"./build.plugin.js"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
|
|
||||||
|
|
||||||
module.exports = ({ onGetWebpackConfig }) => {
|
|
||||||
onGetWebpackConfig((config) => {
|
|
||||||
config.resolve
|
|
||||||
.plugin('tsconfigpaths')
|
|
||||||
.use(TsconfigPathsPlugin, [{
|
|
||||||
configFile: './tsconfig.json',
|
|
||||||
}]);
|
|
||||||
|
|
||||||
/*
|
|
||||||
config
|
|
||||||
// 定义插件名称
|
|
||||||
.plugin('MonacoWebpackPlugin')
|
|
||||||
// 第一项为具体插件,第二项为插件参数
|
|
||||||
.use(new MonacoWebpackPlugin({
|
|
||||||
languages:["javascript","css","json"]
|
|
||||||
}), []);
|
|
||||||
*/
|
|
||||||
config.plugins.delete('hot');
|
|
||||||
config.devServer.hot(false);
|
|
||||||
// config.devtool('hidden-source-map');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
{
|
|
||||||
"plugins": [
|
|
||||||
[
|
|
||||||
"build-plugin-component",
|
|
||||||
{
|
|
||||||
"filename": "editor-preset-vision",
|
|
||||||
"library": "LowcodeEditor",
|
|
||||||
"libraryTarget": "umd",
|
|
||||||
"externals": {
|
|
||||||
"react": "var window.React",
|
|
||||||
"react-dom": "var window.ReactDOM",
|
|
||||||
"prop-types": "var window.PropTypes",
|
|
||||||
"rax": "var window.Rax"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"@ali/lowcode-test-mate/plugin/index.ts"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
const esModules = [
|
|
||||||
'@recore/obx-react',
|
|
||||||
// '@ali/lowcode-editor-core',
|
|
||||||
].join('|');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
// transform: {
|
|
||||||
// '^.+\\.[jt]sx?$': 'babel-jest',
|
|
||||||
// // '^.+\\.(ts|tsx)$': 'ts-jest',
|
|
||||||
// // '^.+\\.(js|jsx)$': 'babel-jest',
|
|
||||||
// },
|
|
||||||
// testMatch: ['(/tests?/.*(test))\\.[jt]s$'],
|
|
||||||
transformIgnorePatterns: [
|
|
||||||
`/node_modules/(?!${esModules})/`,
|
|
||||||
],
|
|
||||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'json'],
|
|
||||||
collectCoverage: false,
|
|
||||||
collectCoverageFrom: [
|
|
||||||
'src/**/*.{ts,tsx}',
|
|
||||||
'!src/**/*.d.ts',
|
|
||||||
'!src/base/**',
|
|
||||||
'!src/fields/**',
|
|
||||||
'!src/prop.ts',
|
|
||||||
'!**/node_modules/**',
|
|
||||||
'!**/vendor/**',
|
|
||||||
],
|
|
||||||
};
|
|
||||||
@ -1,49 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@ali/lowcode-vision-polyfill",
|
|
||||||
"version": "1.0.73",
|
|
||||||
"description": "Vision Polyfill for Ali lowCode engine",
|
|
||||||
"main": "lib/index.js",
|
|
||||||
"private": true,
|
|
||||||
"files": [
|
|
||||||
"dist",
|
|
||||||
"es",
|
|
||||||
"lib"
|
|
||||||
],
|
|
||||||
"scripts": {
|
|
||||||
"start": "build-scripts start",
|
|
||||||
"version:update": "node ./scripts/version.js",
|
|
||||||
"build": "NODE_OPTIONS=--max_old_space_size=8192 build-scripts build --skip-demo",
|
|
||||||
"cloud-build": "NODE_OPTIONS=--max_old_space_size=8192 build-scripts build --config build.cloud.json",
|
|
||||||
"test": "build-scripts test --config build.test.json"
|
|
||||||
},
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@ali/lowcode-designer": "1.0.73",
|
|
||||||
"@ali/lowcode-editor-core": "1.0.73",
|
|
||||||
"@ali/lowcode-editor-skeleton": "1.0.73",
|
|
||||||
"@ali/lowcode-types": "1.0.73",
|
|
||||||
"@ali/lowcode-utils": "1.0.73",
|
|
||||||
"@alifd/next": "^1.19.12",
|
|
||||||
"@alifd/theme-lowcode-dark": "^0.2.0",
|
|
||||||
"@alifd/theme-lowcode-light": "^0.2.0",
|
|
||||||
"react": "^16.8.1",
|
|
||||||
"react-dom": "^16.8.1"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@ali/lowcode-test-mate": "^1.0.1",
|
|
||||||
"@alib/build-scripts": "^0.1.18",
|
|
||||||
"@types/domready": "^1.0.0",
|
|
||||||
"@types/react": "^16.8.3",
|
|
||||||
"@types/react-dom": "^16.8.2",
|
|
||||||
"build-plugin-fusion": "0.1.17-beta.0",
|
|
||||||
"build-plugin-moment-locales": "^0.1.0",
|
|
||||||
"build-plugin-react-app": "^1.1.2",
|
|
||||||
"fs-extra": "^9.0.1",
|
|
||||||
"prop-types": "^15.7.2",
|
|
||||||
"tsconfig-paths-webpack-plugin": "^3.2.0"
|
|
||||||
},
|
|
||||||
"publishConfig": {
|
|
||||||
"registry": "https://registry.antfin-inc.com"
|
|
||||||
},
|
|
||||||
"gitHead": "3bfd7df92985ec6c9d2ccb8ba95d7b0829fa2b1d"
|
|
||||||
}
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
||||||
/* eslint-disable @typescript-eslint/no-require-imports */
|
|
||||||
const { execSync } = require('child_process');
|
|
||||||
const { join } = require('path');
|
|
||||||
const fse = require('fs-extra');
|
|
||||||
|
|
||||||
const gitBranchName = execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf-8' });
|
|
||||||
const reBranchVersion = /^(?:[a-z]+\/)(\d+\.\d+\.\d+)$/im;
|
|
||||||
|
|
||||||
const match = reBranchVersion.exec(gitBranchName);
|
|
||||||
if (!match) {
|
|
||||||
console.warn(`[checkversion] gitBranchName: ${gitBranchName}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const releaseVersion = match[1];
|
|
||||||
|
|
||||||
const indexFile = join(__dirname, '../src/index.ts');
|
|
||||||
|
|
||||||
const indexContent = fse.readFileSync(indexFile, 'utf-8');
|
|
||||||
|
|
||||||
fse.writeFileSync(indexFile, indexContent.replace('{VERSION}', releaseVersion));
|
|
||||||
@ -1,137 +0,0 @@
|
|||||||
import bus from '../bus';
|
|
||||||
import SchemaManager from './schemaManager';
|
|
||||||
import VisualDesigner from './visualDesigner';
|
|
||||||
import VisualManager from './visualManager';
|
|
||||||
|
|
||||||
import { findIndex, get, unionBy, uniqueId } from 'lodash';
|
|
||||||
|
|
||||||
export type removeEventListener = () => void;
|
|
||||||
|
|
||||||
export interface IEventNameMap {
|
|
||||||
[eventName: string]: string | symbol;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ISchemaController {
|
|
||||||
getSchemaManager(): SchemaManager;
|
|
||||||
getSchemaManagerById(id?: string): SchemaManager;
|
|
||||||
getSchemaManagerByName(name?: string): SchemaManager[];
|
|
||||||
getSchemaManagerList(): SchemaManager[];
|
|
||||||
connectSchemaManager(manager: SchemaManager): this;
|
|
||||||
connectSchemaManagerList(managerList: SchemaManager[]): this;
|
|
||||||
notifyAllSchemaManagers(eventName: string | symbol, eventData: any): boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IManagerController {
|
|
||||||
getManager(): VisualManager;
|
|
||||||
getManagerById(id?: string): VisualManager;
|
|
||||||
getManagerByName(name?: string): VisualManager[];
|
|
||||||
getManagerList(name?: string): VisualManager[];
|
|
||||||
connectManager(manager: VisualManager): this;
|
|
||||||
connectManagerList(managerList: VisualManager[]): this;
|
|
||||||
notifyAllManagers(eventName: string | symbol, eventData: any): boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IDesignerController {
|
|
||||||
getDesigner(): VisualDesigner;
|
|
||||||
getDesignerById(id?: string): VisualDesigner;
|
|
||||||
getDesignerByName(name?: string): VisualDesigner[];
|
|
||||||
getDesignerList(): VisualDesigner[];
|
|
||||||
connectDesigner(designer: VisualDesigner): this;
|
|
||||||
connectDesignerList(designerList: VisualDesigner[]): this;
|
|
||||||
notifyAllDesigners(eventName: string | symbol, eventData: any): boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface INameable {
|
|
||||||
getName(): string;
|
|
||||||
getId(): string;
|
|
||||||
setName(name?: string): this;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IObservable {
|
|
||||||
getEventMap(): IEventNameMap;
|
|
||||||
on(eventName: string | symbol, callback: () => any): removeEventListener;
|
|
||||||
emit(eventName: string | symbol, eventData?: any[]): boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IManagerConfigs {
|
|
||||||
name?: string;
|
|
||||||
disableEvents?: boolean;
|
|
||||||
emitter?: IEmitter;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IEmitter {
|
|
||||||
on(eventName: string | symbol, callback: () => any): removeEventListener;
|
|
||||||
emit(eventName: string | symbol, eventData?: any): boolean;
|
|
||||||
removeListener(eventName: string | symbol, callback: () => any): any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function connectGeneralManager(manager: any, managerList: any[]) {
|
|
||||||
const index = findIndex(managerList, (m) => m.getId() === manager.getId());
|
|
||||||
if (index > -1) {
|
|
||||||
managerList.push(manager);
|
|
||||||
} else {
|
|
||||||
managerList.splice(index, 1, manager);
|
|
||||||
}
|
|
||||||
return managerList;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function connectGeneralManagerList(managerList: any[], sourceManagerList: any[]): any {
|
|
||||||
return unionBy(sourceManagerList, managerList, (manager) => manager.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
export class BaseManager implements INameable, IObservable {
|
|
||||||
static EVENTS: IEventNameMap = {};
|
|
||||||
|
|
||||||
static NAME = 'BaseManager';
|
|
||||||
|
|
||||||
private name: string;
|
|
||||||
|
|
||||||
private id: string;
|
|
||||||
|
|
||||||
private emitter: any;
|
|
||||||
|
|
||||||
constructor(managerConfigs: IManagerConfigs = {}) {
|
|
||||||
this.name = managerConfigs.name || get(this, 'constructor', 'NAME');
|
|
||||||
this.id = uniqueId(this.name);
|
|
||||||
if (!managerConfigs.disableEvents) {
|
|
||||||
if (managerConfigs.emitter) {
|
|
||||||
// 使用自定义的满足 EventEmitter 接口要求的自定义事件对象
|
|
||||||
this.emitter = managerConfigs.emitter;
|
|
||||||
} else {
|
|
||||||
// Bus 为单例模式
|
|
||||||
this.emitter = bus;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getId(): string {
|
|
||||||
return this.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
setName(name: string): this {
|
|
||||||
this.name = name;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
getName(): string {
|
|
||||||
return this.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
getEventMap() {
|
|
||||||
/**
|
|
||||||
* Hack for get current constructor
|
|
||||||
* because if we write this.constructor.EVENTS
|
|
||||||
* ts compiler will show compiled error
|
|
||||||
*/
|
|
||||||
return get(this, 'constructor', BaseManager.EVENTS);
|
|
||||||
}
|
|
||||||
|
|
||||||
on(eventName: string | symbol, callback: () => any): removeEventListener {
|
|
||||||
this.emitter.on(eventName, callback);
|
|
||||||
return () => this.emitter.removeListener(eventName, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
emit(eventName: string | symbol, ...eventData: any[]): boolean {
|
|
||||||
return this.emitter.emit.call(this.emitter, eventName, ...eventData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,44 +0,0 @@
|
|||||||
/**
|
|
||||||
* Storage the const variables
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Global
|
|
||||||
*/
|
|
||||||
export const VERSION = '5.3.0';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* schema version defined in alibaba
|
|
||||||
*/
|
|
||||||
export const ALI_SCHEMA_VERSION = '1.0.0';
|
|
||||||
|
|
||||||
export const VE_EVENTS = {
|
|
||||||
/**
|
|
||||||
* node props to be dynamically replaced
|
|
||||||
* @event props the new props object been replaced
|
|
||||||
*/
|
|
||||||
VE_NODE_CREATED: 've.node.created',
|
|
||||||
VE_NODE_DESTROY: 've.node.destroyed',
|
|
||||||
VE_NODE_PROPS_REPLACE: 've.node.props.replaced',
|
|
||||||
// copy / clone node
|
|
||||||
VE_OVERLAY_ACTION_CLONE_NODE: 've.overlay.cloneElement',
|
|
||||||
// remove / delete node
|
|
||||||
VE_OVERLAY_ACTION_REMOVE_NODE: 've.overlay.removeElement',
|
|
||||||
// one page successfully mount on the DOM
|
|
||||||
VE_PAGE_PAGE_READY: 've.page.pageReady',
|
|
||||||
};
|
|
||||||
|
|
||||||
export const VE_HOOKS = {
|
|
||||||
// a decorator function
|
|
||||||
VE_NODE_PROPS_DECORATOR: 've.leaf.props.decorator',
|
|
||||||
// a remove callback function
|
|
||||||
VE_NODE_REMOVE_HELPER: 've.outline.actions.removeHelper',
|
|
||||||
/**
|
|
||||||
* provide customization field
|
|
||||||
*/
|
|
||||||
VE_SETTING_FIELD_PROVIDER: 've.settingField.provider',
|
|
||||||
/**
|
|
||||||
* VariableSetter for variable mode of a specified prop
|
|
||||||
*/
|
|
||||||
VE_SETTING_FIELD_VARIABLE_SETTER: 've.settingField.variableSetter',
|
|
||||||
};
|
|
||||||
@ -1,104 +0,0 @@
|
|||||||
import { cloneDeep, find } from 'lodash';
|
|
||||||
|
|
||||||
import {
|
|
||||||
BaseManager,
|
|
||||||
connectGeneralManager,
|
|
||||||
connectGeneralManagerList,
|
|
||||||
IManagerController,
|
|
||||||
ISchemaController,
|
|
||||||
} from './base';
|
|
||||||
import VisualManager from './visualManager';
|
|
||||||
|
|
||||||
export default class SchemaManager extends BaseManager implements IManagerController, ISchemaController {
|
|
||||||
private schemaData: object = {};
|
|
||||||
|
|
||||||
private visualManagerList: VisualManager[] = [];
|
|
||||||
|
|
||||||
private schemaManagerList: SchemaManager[] = [];
|
|
||||||
|
|
||||||
getManager(): VisualManager {
|
|
||||||
return this.visualManagerList[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
getManagerByName(name?: string): VisualManager[] {
|
|
||||||
return this.visualManagerList.filter((m) => m.getName() === name);
|
|
||||||
}
|
|
||||||
|
|
||||||
getManagerById(id?: string): VisualManager {
|
|
||||||
return find(this.visualManagerList, (m) => m.getId() === id) as VisualManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
getManagerList(): VisualManager[] {
|
|
||||||
return this.visualManagerList;
|
|
||||||
}
|
|
||||||
|
|
||||||
getSchemaManager(): SchemaManager {
|
|
||||||
return this.schemaManagerList[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
getSchemaManagerById(id?: string): SchemaManager {
|
|
||||||
return find(this.schemaManagerList, (m) => m.getId() === id) as SchemaManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
getSchemaManagerByName(name?: string): SchemaManager[] {
|
|
||||||
return this.schemaManagerList.filter((m) => m.getName() === name);
|
|
||||||
}
|
|
||||||
|
|
||||||
getSchemaManagerList() {
|
|
||||||
return this.schemaManagerList;
|
|
||||||
}
|
|
||||||
|
|
||||||
connectManager(manager: any) {
|
|
||||||
connectGeneralManager.call(this, manager, this.visualManagerList as any);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
connectSchemaManager(manager: SchemaManager): this {
|
|
||||||
connectGeneralManager.call(this, manager, this.schemaManagerList);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
connectManagerList(managerList: VisualManager[]): this {
|
|
||||||
this.visualManagerList = connectGeneralManagerList.call(this, managerList as any, this.visualManagerList as any);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
connectSchemaManagerList(managerList: SchemaManager[]): this {
|
|
||||||
this.schemaManagerList = connectGeneralManagerList.call(this, managerList, this.schemaManagerList);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
notifyAllManagers(eventName: string | symbol, ...eventData: any[]): boolean {
|
|
||||||
return this.visualManagerList.map((m) => m.emit(eventName, eventData)).every((r) => r);
|
|
||||||
}
|
|
||||||
|
|
||||||
notifyAllSchemaManagers(eventName: string | symbol, ...eventData: any[]): boolean {
|
|
||||||
return this.schemaManagerList.map((m) => m.emit(eventName, eventData)).every((r) => r);
|
|
||||||
}
|
|
||||||
|
|
||||||
exportSchema(): string {
|
|
||||||
try {
|
|
||||||
return JSON.stringify(this.schemaData);
|
|
||||||
} catch (e) {
|
|
||||||
throw new Error(e.message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
exportSchemaObject(): object {
|
|
||||||
return cloneDeep(this.schemaData);
|
|
||||||
}
|
|
||||||
|
|
||||||
importSchema(schemaString: string): this {
|
|
||||||
try {
|
|
||||||
this.schemaData = JSON.parse(schemaString);
|
|
||||||
return this;
|
|
||||||
} catch (e) {
|
|
||||||
throw new Error(e.message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
importSchemaObject(schema: object): this {
|
|
||||||
this.schemaData = schema;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,116 +0,0 @@
|
|||||||
import { assign, find, get } from 'lodash';
|
|
||||||
import { Component } from 'react';
|
|
||||||
|
|
||||||
import bus from '../bus';
|
|
||||||
import {
|
|
||||||
BaseManager,
|
|
||||||
connectGeneralManager,
|
|
||||||
connectGeneralManagerList,
|
|
||||||
IEmitter,
|
|
||||||
IEventNameMap,
|
|
||||||
IManagerController,
|
|
||||||
INameable,
|
|
||||||
IObservable,
|
|
||||||
} from './base';
|
|
||||||
import VisualManager from './visualManager';
|
|
||||||
|
|
||||||
interface IDesignerProps {
|
|
||||||
name?: string;
|
|
||||||
visualManagers?: VisualManager[];
|
|
||||||
emitter?: IEmitter;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class VisualDesigner extends Component implements IManagerController, IObservable, INameable {
|
|
||||||
static NAME = 'VisualDesigner';
|
|
||||||
|
|
||||||
static EVENTS: IEventNameMap = {};
|
|
||||||
|
|
||||||
props: IDesignerProps = {};
|
|
||||||
|
|
||||||
defaultProps: IDesignerProps = {
|
|
||||||
name: 'defaultDesigner',
|
|
||||||
visualManagers: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
private visualManagerList: VisualManager[] = [];
|
|
||||||
|
|
||||||
private name = '';
|
|
||||||
|
|
||||||
private id = '';
|
|
||||||
|
|
||||||
private emitter: IEmitter;
|
|
||||||
|
|
||||||
constructor(props: IDesignerProps) {
|
|
||||||
super(props);
|
|
||||||
this.setName(props.name || get(this, 'constructor', 'NAME'));
|
|
||||||
this.connectManagerList(this.props.visualManagers as any);
|
|
||||||
|
|
||||||
if (props.emitter) {
|
|
||||||
// 使用自定义的满足 EventEmitter 接口要求的自定义事件对象
|
|
||||||
this.emitter = props.emitter;
|
|
||||||
} else {
|
|
||||||
this.emitter = bus;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getId(): string {
|
|
||||||
return this.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
setName(name: string): this {
|
|
||||||
this.name = name;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
getName() {
|
|
||||||
return this.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
getManager(): VisualManager {
|
|
||||||
return this.visualManagerList[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
getManagerByName(name?: string): VisualManager[] {
|
|
||||||
return this.visualManagerList.filter((m) => m.getName() === name);
|
|
||||||
}
|
|
||||||
|
|
||||||
getManagerById(id: string): VisualManager {
|
|
||||||
return find(this.visualManagerList, (m) => m.getId() === id) as VisualManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
getManagerList(): VisualManager[] {
|
|
||||||
return this.visualManagerList;
|
|
||||||
}
|
|
||||||
|
|
||||||
connectManager(manager: VisualManager) {
|
|
||||||
connectGeneralManager.call(this, manager, this.visualManagerList);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
connectManagerList(managerList: VisualManager[]): this {
|
|
||||||
this.visualManagerList = connectGeneralManagerList.call(this, managerList, this.visualManagerList);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
getEventMap() {
|
|
||||||
/**
|
|
||||||
* Hack for get current constructor
|
|
||||||
* because if we write this.constructor.EVENTS
|
|
||||||
* ts compiler will show compiled error
|
|
||||||
*/
|
|
||||||
return get(this, 'constructor', BaseManager.EVENTS);
|
|
||||||
}
|
|
||||||
|
|
||||||
notifyAllManagers(eventName: string | symbol, ...eventData: any[]): boolean {
|
|
||||||
return this.visualManagerList.map((m) => m.emit(eventName, eventData)).every((r) => r);
|
|
||||||
}
|
|
||||||
|
|
||||||
on(eventName: string | symbol, callback: () => any) {
|
|
||||||
this.emitter.on(eventName, callback);
|
|
||||||
return () => this.emitter.removeListener(eventName, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
emit(eventName: string | symbol, ...eventData: any[]): boolean {
|
|
||||||
return this.emitter.emit.call(this.emitter, eventName, ...eventData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,80 +0,0 @@
|
|||||||
import { find } from 'lodash';
|
|
||||||
|
|
||||||
import {
|
|
||||||
BaseManager,
|
|
||||||
connectGeneralManager,
|
|
||||||
connectGeneralManagerList,
|
|
||||||
IDesignerController,
|
|
||||||
IManagerController,
|
|
||||||
} from './base';
|
|
||||||
import VisualDesigner from './visualDesigner';
|
|
||||||
|
|
||||||
export default class VisualManager extends BaseManager implements IManagerController, IDesignerController {
|
|
||||||
private visualManagerList: VisualManager[] = [];
|
|
||||||
|
|
||||||
private visualDesignerList: VisualDesigner[] = [];
|
|
||||||
|
|
||||||
getManager(): VisualManager {
|
|
||||||
return this.visualManagerList[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
getManagerByName(name?: string): VisualManager[] {
|
|
||||||
return this.visualManagerList.filter((m) => m.getName() === name);
|
|
||||||
}
|
|
||||||
|
|
||||||
getManagerById(id?: string): VisualManager {
|
|
||||||
return find(this.visualManagerList, (m) => m.getId() === id) as VisualManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
getManagerList(): VisualManager[] {
|
|
||||||
return this.visualManagerList;
|
|
||||||
}
|
|
||||||
|
|
||||||
getDesigner(): VisualDesigner {
|
|
||||||
return this.visualDesignerList[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
getDesignerByName(name?: string): VisualDesigner[] {
|
|
||||||
return this.visualDesignerList.filter((m) => m.getName() === name);
|
|
||||||
}
|
|
||||||
|
|
||||||
getDesignerById(id?: string): VisualDesigner {
|
|
||||||
return find(this.visualDesignerList, (m) => m.getId() === id) as VisualDesigner;
|
|
||||||
}
|
|
||||||
|
|
||||||
getDesignerList() {
|
|
||||||
return this.visualDesignerList;
|
|
||||||
}
|
|
||||||
|
|
||||||
connectManager(manager: VisualManager) {
|
|
||||||
connectGeneralManager.call(this, manager, this.visualManagerList);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
connectDesigner(manager: VisualDesigner): this {
|
|
||||||
connectGeneralManager.call(this, manager, this.visualDesignerList);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
connectManagerList(managerList: VisualManager[]): this {
|
|
||||||
this.visualManagerList = connectGeneralManagerList.call(this, managerList, this.visualManagerList);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
connectDesignerList(managerList: VisualDesigner[]): this {
|
|
||||||
this.visualDesignerList = connectGeneralManagerList.call(this, managerList, this.visualDesignerList);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
notifyAllManagers(eventName: string | symbol, ...eventData: any[]): boolean {
|
|
||||||
return this.getManagerList()
|
|
||||||
.map((m) => m.emit(eventName, eventData))
|
|
||||||
.every((r) => r);
|
|
||||||
}
|
|
||||||
|
|
||||||
notifyAllDesigners(eventName: string | symbol, ...eventData: any[]): boolean {
|
|
||||||
return this.getDesignerList()
|
|
||||||
.map((m) => m.emit(eventName, eventData))
|
|
||||||
.every((r) => r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,48 +0,0 @@
|
|||||||
import { find } from 'lodash';
|
|
||||||
|
|
||||||
import { BaseManager, connectGeneralManager, connectGeneralManagerList, IManagerController } from './base';
|
|
||||||
import VisualManager from './visualManager';
|
|
||||||
|
|
||||||
export default class VisualRender extends BaseManager implements IManagerController {
|
|
||||||
private visualManagerList: VisualManager[] = [];
|
|
||||||
|
|
||||||
getManager(): VisualManager {
|
|
||||||
return this.visualManagerList[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
getManagerByName(name?: string): VisualManager[] {
|
|
||||||
return this.visualManagerList.filter((m) => m.getName() === name);
|
|
||||||
}
|
|
||||||
|
|
||||||
getManagerById(id?: string): VisualManager {
|
|
||||||
return find(this.visualManagerList, (m) => m.getId() === id) as VisualManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
getManagerList(): VisualManager[] {
|
|
||||||
return this.visualManagerList;
|
|
||||||
}
|
|
||||||
|
|
||||||
connectManager(manager: VisualManager) {
|
|
||||||
connectGeneralManager.call(this, manager, this.visualManagerList);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
connectManagerList(managerList: VisualManager[]): this {
|
|
||||||
this.visualManagerList = connectGeneralManagerList.call(this, managerList, this.visualManagerList);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
notifyAllManagers(eventName: string | symbol, ...eventData: any[]): boolean {
|
|
||||||
return this.visualManagerList.map((m) => m.emit(eventName, eventData)).every((r) => r);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render function
|
|
||||||
* @override
|
|
||||||
*
|
|
||||||
* @memberof VisualRender
|
|
||||||
*/
|
|
||||||
render(): any {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,248 +0,0 @@
|
|||||||
import lg from '@ali/vu-logger';
|
|
||||||
import { ComponentClass, ComponentType } from 'react';
|
|
||||||
import Prototype, { isPrototype } from './prototype';
|
|
||||||
import { designer } from '@ali/lowcode-engine';
|
|
||||||
import { upgradeMetadata } from './upgrade-metadata';
|
|
||||||
import trunk from './trunk';
|
|
||||||
|
|
||||||
function basename(name: string) {
|
|
||||||
return name ? (/[^\/]+$/.exec(name) || [''])[0] : '';
|
|
||||||
}
|
|
||||||
|
|
||||||
function getCamelName(name: string) {
|
|
||||||
const words = basename(name)
|
|
||||||
.replace(/^((vc)-)?(.+)/, '$3')
|
|
||||||
.split('-');
|
|
||||||
return words.reduce((s, word) => s + word[0].toUpperCase() + word.substring(1), '');
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ComponentProtoBundle {
|
|
||||||
// @ali/vc-xxx
|
|
||||||
name: string;
|
|
||||||
version?: string;
|
|
||||||
componentName?: string;
|
|
||||||
category?: string;
|
|
||||||
module: Prototype | Prototype[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ComponentViewBundle {
|
|
||||||
// @ali/vc-xxx
|
|
||||||
name: string;
|
|
||||||
// alias to property name
|
|
||||||
componentName?: string;
|
|
||||||
category?: string;
|
|
||||||
module: ComponentType<any>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const prototypeViewWrapperList: any[] = [];
|
|
||||||
|
|
||||||
function registerPrototypeViewWrapper(name: string, prototypeViewWrapper: Function) {
|
|
||||||
if (!prototypeViewWrapperList.find(p => p.name === name) && typeof prototypeViewWrapper === 'function') {
|
|
||||||
prototypeViewWrapperList.push({
|
|
||||||
name,
|
|
||||||
prototypeViewWrapper,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function wrapPrototypeView(view: ComponentClass) {
|
|
||||||
const newView = prototypeViewWrapperList.reduce((acc, { prototypeViewWrapper }) => {
|
|
||||||
return prototypeViewWrapper(acc.displayName, acc) || acc;
|
|
||||||
}, view);
|
|
||||||
if (!newView.displayName && view.displayName) {
|
|
||||||
newView.displayName = view.displayName;
|
|
||||||
}
|
|
||||||
if (!newView.propTypes && view.propTypes) {
|
|
||||||
newView.propTypes = view.propTypes;
|
|
||||||
}
|
|
||||||
if (!newView.defaultProps && view.defaultProps) {
|
|
||||||
newView.defaultProps = view.defaultProps;
|
|
||||||
}
|
|
||||||
return newView;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPrototypeViewWrapperList() {
|
|
||||||
return prototypeViewWrapperList;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class Bundle {
|
|
||||||
static createPrototype = Prototype.create;
|
|
||||||
|
|
||||||
static addGlobalPropsReducer = Prototype.addGlobalPropsReducer;
|
|
||||||
|
|
||||||
static addGlobalPropsConfigure = Prototype.addGlobalPropsConfigure;
|
|
||||||
|
|
||||||
static addGlobalExtraActions = Prototype.addGlobalExtraActions;
|
|
||||||
|
|
||||||
static removeGlobalPropsConfigure = Prototype.removeGlobalPropsConfigure;
|
|
||||||
|
|
||||||
static overridePropsConfigure = Prototype.overridePropsConfigure;
|
|
||||||
|
|
||||||
static registerPrototypeConfigPreprocessor = Prototype.registerPrototypeConfigPreprocessor;
|
|
||||||
|
|
||||||
static getPrototypeConfigPreprocessorList = Prototype.getPrototypeConfigPreprocessorList;
|
|
||||||
|
|
||||||
static registerPrototypeViewWrapper = registerPrototypeViewWrapper;
|
|
||||||
|
|
||||||
static getPrototypeViewWrapperList = getPrototypeViewWrapperList;
|
|
||||||
|
|
||||||
static create(protos: ComponentProtoBundle[], views?: ComponentViewBundle[]) {
|
|
||||||
return new Bundle(protos, views);
|
|
||||||
}
|
|
||||||
|
|
||||||
private viewsMap: { [componentName: string]: ComponentType } = {};
|
|
||||||
|
|
||||||
private registry: { [componentName: string]: Prototype } = {};
|
|
||||||
|
|
||||||
private prototypeList: Prototype[] = [];
|
|
||||||
|
|
||||||
constructor(protos?: ComponentProtoBundle[], views?: ComponentViewBundle[]) {
|
|
||||||
// 注册 prototypeView 视图
|
|
||||||
if (views && Array.isArray(views)) {
|
|
||||||
this.recursivelyRegisterViews(views);
|
|
||||||
}
|
|
||||||
protos?.forEach((item) => {
|
|
||||||
const prototype = item.module;
|
|
||||||
if (prototype instanceof Prototype) {
|
|
||||||
this.revisePrototype(item, prototype);
|
|
||||||
const componentName = item.componentName || prototype.getComponentName()!;
|
|
||||||
const matchedView = this.viewsMap[componentName] || null;
|
|
||||||
if (matchedView) {
|
|
||||||
prototype.setView(matchedView);
|
|
||||||
}
|
|
||||||
this.registerPrototype(prototype);
|
|
||||||
} else if (Array.isArray(prototype)) {
|
|
||||||
this.recursivelyRegisterPrototypes(prototype, item);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// invoke prototype mocker while the prototype does not exist
|
|
||||||
Object.keys(this.viewsMap).forEach((viewName) => {
|
|
||||||
if (!this.prototypeList.find((proto) => proto.getComponentName() === viewName)) {
|
|
||||||
const mockedPrototype = trunk.mockComponentPrototype(this.viewsMap[viewName]);
|
|
||||||
if (mockedPrototype) {
|
|
||||||
mockedPrototype.setView(this.viewsMap[viewName]);
|
|
||||||
this.registerPrototype(mockedPrototype);
|
|
||||||
if (!mockedPrototype.getPackageName()) {
|
|
||||||
mockedPrototype.setPackageName((this.viewsMap[viewName] as any)._packageName_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getFromMeta(componentName: string): Prototype {
|
|
||||||
if (this.registry[componentName]) {
|
|
||||||
return this.registry[componentName];
|
|
||||||
}
|
|
||||||
const meta = designer.getComponentMeta(componentName);
|
|
||||||
const prototype = Prototype.create(meta);
|
|
||||||
this.prototypeList.push(prototype);
|
|
||||||
this.registry[componentName] = prototype;
|
|
||||||
return prototype;
|
|
||||||
}
|
|
||||||
|
|
||||||
removeComponentBundle(componentName: string) {
|
|
||||||
const cIndex = this.prototypeList.findIndex((proto) => proto.getComponentName() === componentName);
|
|
||||||
delete this.registry[componentName];
|
|
||||||
this.prototypeList.splice(cIndex, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
getList() {
|
|
||||||
return this.prototypeList;
|
|
||||||
}
|
|
||||||
|
|
||||||
get(componentName: string) {
|
|
||||||
return this.registry[componentName];
|
|
||||||
}
|
|
||||||
|
|
||||||
replacePrototype(componentName: string, cp: Prototype) {
|
|
||||||
const view: any = this.get(componentName).getView();
|
|
||||||
this.removeComponentBundle(componentName);
|
|
||||||
this.registry[cp.getComponentName()!] = cp;
|
|
||||||
this.prototypeList.push(cp);
|
|
||||||
cp.setView(view);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO dirty fix
|
|
||||||
*/
|
|
||||||
addComponentBundle(bundles: any) {
|
|
||||||
/**
|
|
||||||
* Normal Component bundle: [ Prototype, PrototypeView ]
|
|
||||||
* Component without Prototype.js: [ View ]
|
|
||||||
*/
|
|
||||||
if (bundles.length >= 2) {
|
|
||||||
const prototype = bundles[0];
|
|
||||||
const metadata = upgradeMetadata({ ...prototype.options, packageName: prototype.packageName });
|
|
||||||
prototype.meta = designer.createComponentMeta(metadata);
|
|
||||||
const prototypeView = bundles[1];
|
|
||||||
prototype.setView(prototypeView);
|
|
||||||
this.registerPrototype(prototype);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private recursivelyRegisterViews(list: any[], viewName?: string): void {
|
|
||||||
list.forEach((item: any) => {
|
|
||||||
if (Array.isArray(item.module)) {
|
|
||||||
return this.recursivelyRegisterViews(item.module, item.name);
|
|
||||||
} else if (Array.isArray(item)) {
|
|
||||||
return this.recursivelyRegisterViews(item, viewName);
|
|
||||||
}
|
|
||||||
let viewDetail: ComponentClass;
|
|
||||||
if (item.module && typeof item.module === 'function') {
|
|
||||||
viewDetail = item.module;
|
|
||||||
} else {
|
|
||||||
viewDetail = item;
|
|
||||||
}
|
|
||||||
if (!viewDetail.displayName) {
|
|
||||||
lg.log('ERROR_NO_PROTOTYPE_VIEW');
|
|
||||||
lg.error('WARNING: the package without displayName is', item);
|
|
||||||
viewDetail.displayName = getCamelName(viewName || item.name);
|
|
||||||
}
|
|
||||||
(viewDetail as any)._packageName_ = viewName || item.name;
|
|
||||||
this.viewsMap[viewDetail.displayName] = wrapPrototypeView(viewDetail);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private recursivelyRegisterPrototypes(list: any[], cp: ComponentProtoBundle) {
|
|
||||||
const propList: ComponentProtoBundle[] = list;
|
|
||||||
propList.forEach((proto: any, index: number) => {
|
|
||||||
if (Array.isArray(proto)) {
|
|
||||||
this.recursivelyRegisterPrototypes(proto, cp);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (isPrototype(proto)) {
|
|
||||||
const componentName = proto.getComponentName()!;
|
|
||||||
if (this.viewsMap[componentName]) {
|
|
||||||
proto.setView(this.viewsMap[componentName]);
|
|
||||||
}
|
|
||||||
if (cp.name && !proto.getPackageName()) {
|
|
||||||
proto.setPackageName(cp.name, cp.version);
|
|
||||||
}
|
|
||||||
this.registerPrototype(proto);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private revisePrototype(item: ComponentProtoBundle, prototype: Prototype) {
|
|
||||||
if (item.category) {
|
|
||||||
prototype.setCategory(item.category);
|
|
||||||
}
|
|
||||||
if (item.name && !prototype.getPackageName()) {
|
|
||||||
prototype.setPackageName(item.name, item.version);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private registerPrototype(prototype: Prototype) {
|
|
||||||
const componentName = prototype.getComponentName()!;
|
|
||||||
if (this.registry[componentName]) {
|
|
||||||
lg.warn('WARN: override prototype', prototype, componentName);
|
|
||||||
const idx = this.prototypeList.findIndex((proto) => componentName === proto.getComponentName());
|
|
||||||
this.prototypeList[idx] = prototype;
|
|
||||||
} else {
|
|
||||||
this.prototypeList.push(prototype);
|
|
||||||
}
|
|
||||||
this.registry[componentName] = prototype;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,404 +0,0 @@
|
|||||||
import { ComponentType, ReactElement, Component, FunctionComponent } from 'react';
|
|
||||||
import { ComponentMetadata, FieldConfig, InitialItem, FilterItem, AutorunItem } from '@ali/lowcode-types';
|
|
||||||
import {
|
|
||||||
ComponentMeta,
|
|
||||||
} from '@ali/lowcode-designer';
|
|
||||||
import {
|
|
||||||
OldPropConfig,
|
|
||||||
OldPrototypeConfig,
|
|
||||||
upgradeMetadata,
|
|
||||||
upgradeActions,
|
|
||||||
upgradePropConfig,
|
|
||||||
upgradeConfigure,
|
|
||||||
} from './upgrade-metadata';
|
|
||||||
import { accessLibrary } from '@ali/lowcode-utils';
|
|
||||||
import { designer, designerCabin, editorCabin } from '@ali/lowcode-engine';
|
|
||||||
|
|
||||||
const {
|
|
||||||
addBuiltinComponentAction,
|
|
||||||
isComponentMeta,
|
|
||||||
registerMetadataTransducer,
|
|
||||||
TransformStage,
|
|
||||||
} = designerCabin;
|
|
||||||
const { intl } = editorCabin;
|
|
||||||
|
|
||||||
const GlobalPropsConfigure: Array<{
|
|
||||||
position: string;
|
|
||||||
initials?: InitialItem[];
|
|
||||||
filters?: FilterItem[];
|
|
||||||
autoruns?: AutorunItem[];
|
|
||||||
config: FieldConfig;
|
|
||||||
}> = [];
|
|
||||||
const Overrides: {
|
|
||||||
[componentName: string]: {
|
|
||||||
initials?: InitialItem[];
|
|
||||||
filters?: FilterItem[];
|
|
||||||
autoruns?: AutorunItem[];
|
|
||||||
override: any;
|
|
||||||
};
|
|
||||||
} = {};
|
|
||||||
|
|
||||||
function addGlobalPropsConfigure(config: OldGlobalPropConfig) {
|
|
||||||
const initials: InitialItem[] = [];
|
|
||||||
const filters: FilterItem[] = [];
|
|
||||||
const autoruns: AutorunItem[] = [];
|
|
||||||
GlobalPropsConfigure.push({
|
|
||||||
position: config.position || 'bottom',
|
|
||||||
initials,
|
|
||||||
filters,
|
|
||||||
autoruns,
|
|
||||||
config: upgradePropConfig(config, {
|
|
||||||
addInitial: (item) => {
|
|
||||||
initials.push(item);
|
|
||||||
},
|
|
||||||
addFilter: (item) => {
|
|
||||||
filters.push(item);
|
|
||||||
},
|
|
||||||
addAutorun: (item) => {
|
|
||||||
autoruns.push(item);
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
function removeGlobalPropsConfigure(name: string) {
|
|
||||||
let l = GlobalPropsConfigure.length;
|
|
||||||
while (l-- > 0) {
|
|
||||||
if (GlobalPropsConfigure[l].config.name === name) {
|
|
||||||
GlobalPropsConfigure.splice(l, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function overridePropsConfigure(componentName: string, config: { [name: string]: OldPropConfig } | OldPropConfig[]) {
|
|
||||||
const initials: InitialItem[] = [];
|
|
||||||
const filters: FilterItem[] = [];
|
|
||||||
const autoruns: AutorunItem[] = [];
|
|
||||||
const addInitial = (item: InitialItem) => {
|
|
||||||
initials.push(item);
|
|
||||||
};
|
|
||||||
const addFilter = (item: FilterItem) => {
|
|
||||||
filters.push(item);
|
|
||||||
};
|
|
||||||
const addAutorun = (item: AutorunItem) => {
|
|
||||||
autoruns.push(item);
|
|
||||||
};
|
|
||||||
let override: any;
|
|
||||||
if (Array.isArray(config)) {
|
|
||||||
override = upgradeConfigure(config, { addInitial, addFilter, addAutorun });
|
|
||||||
} else {
|
|
||||||
override = {};
|
|
||||||
Object.keys(config).forEach((key) => {
|
|
||||||
override[key] = upgradePropConfig(config[key], { addInitial, addFilter, addAutorun });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Overrides[componentName] = {
|
|
||||||
initials,
|
|
||||||
filters,
|
|
||||||
autoruns,
|
|
||||||
override,
|
|
||||||
};
|
|
||||||
|
|
||||||
// refresh metadata
|
|
||||||
window.VisualEngine.designer.getComponentMeta(componentName).parseMetadata(window.VisualEngine.designer.getComponentMeta(componentName).getMetadata());
|
|
||||||
}
|
|
||||||
registerMetadataTransducer(
|
|
||||||
(metadata) => {
|
|
||||||
const {
|
|
||||||
configure: { combined, props },
|
|
||||||
componentName,
|
|
||||||
} = metadata;
|
|
||||||
let top: FieldConfig[];
|
|
||||||
let bottom: FieldConfig[];
|
|
||||||
if (combined) {
|
|
||||||
top = combined?.[0]?.items || combined;
|
|
||||||
bottom = combined?.[combined.length - 1]?.items || combined;
|
|
||||||
} else if (props) {
|
|
||||||
top = props;
|
|
||||||
bottom = props;
|
|
||||||
} else {
|
|
||||||
metadata.configure.props = top = bottom = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
GlobalPropsConfigure.forEach((item) => {
|
|
||||||
const position = item.position || 'bottom';
|
|
||||||
|
|
||||||
if (position === 'top') {
|
|
||||||
top.unshift(item.config);
|
|
||||||
} else if (position === 'bottom') {
|
|
||||||
bottom.push(item.config);
|
|
||||||
}
|
|
||||||
// TODO: replace autoruns,initials,filters
|
|
||||||
});
|
|
||||||
|
|
||||||
const override = Overrides[componentName]?.override;
|
|
||||||
if (override) {
|
|
||||||
if (Array.isArray(override)) {
|
|
||||||
// 替换 #props,其他暂时忽略
|
|
||||||
const idx = metadata.configure.combined?.findIndex(item => item.name === '#props');
|
|
||||||
if (idx > -1) {
|
|
||||||
metadata.configure.combined[idx].items = override;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let l = top.length;
|
|
||||||
let item;
|
|
||||||
while (l-- > 0) {
|
|
||||||
item = top[l];
|
|
||||||
if (item.name in override) {
|
|
||||||
if (override[item.name]) {
|
|
||||||
top.splice(l, 1, override[item.name]);
|
|
||||||
} else {
|
|
||||||
top.splice(l, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (metadata.experimental) {
|
|
||||||
metadata.experimental.initials = Overrides[componentName]?.initials;
|
|
||||||
metadata.experimental.autoruns = Overrides[componentName]?.autoruns;
|
|
||||||
metadata.experimental.filters = Overrides[componentName]?.filters;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return metadata;
|
|
||||||
},
|
|
||||||
100,
|
|
||||||
'vision-polyfill',
|
|
||||||
);
|
|
||||||
|
|
||||||
function addGlobalExtraActions(action: () => ReactElement) {
|
|
||||||
upgradeActions(action)?.forEach(addBuiltinComponentAction);
|
|
||||||
}
|
|
||||||
|
|
||||||
// const GlobalPropsReducers: any[] = [];
|
|
||||||
function addGlobalPropsReducer(reducer: () => any) {
|
|
||||||
// GlobalPropsReducers.push(reducer);
|
|
||||||
designer.addPropsReducer(reducer, TransformStage.Render);
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface OldGlobalPropConfig extends OldPropConfig {
|
|
||||||
position?: 'top' | 'bottom';
|
|
||||||
}
|
|
||||||
|
|
||||||
const packageMaps: any = {};
|
|
||||||
|
|
||||||
export function setPackages(packages: Array<{ package: string; library: object | string }>) {
|
|
||||||
packages.forEach((item) => {
|
|
||||||
let lib: any;
|
|
||||||
if (packageMaps.hasOwnProperty(item.package)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Object.defineProperty(packageMaps, item.package, {
|
|
||||||
get() {
|
|
||||||
if (lib === undefined) {
|
|
||||||
lib = accessLibrary(item.library);
|
|
||||||
}
|
|
||||||
return lib;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getPackage(name: string): object | null {
|
|
||||||
if (packageMaps.hasOwnProperty(name)) {
|
|
||||||
return packageMaps[name];
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isNewSpec(options: any): options is ComponentMetadata {
|
|
||||||
return (
|
|
||||||
options &&
|
|
||||||
(options.npm || options.props || (options.configure && (options.configure.props || options.configure.component)))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const prototypeConfigPreprocessorList: any[] = [];
|
|
||||||
|
|
||||||
function registerPrototypeConfigPreprocessor(name: String, preprocessor: Function) {
|
|
||||||
if (!prototypeConfigPreprocessorList.find(p => p.name === name) && typeof preprocessor === 'function') {
|
|
||||||
prototypeConfigPreprocessorList.push({
|
|
||||||
name,
|
|
||||||
preprocessor,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function modifyPrototypeConfig(config: any) {
|
|
||||||
const { componentName } = config;
|
|
||||||
return prototypeConfigPreprocessorList.reduce((acc, { preprocessor }) => {
|
|
||||||
return preprocessor(componentName, acc) || acc;
|
|
||||||
}, config);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPrototypeConfigPreprocessorList() {
|
|
||||||
return prototypeConfigPreprocessorList;
|
|
||||||
}
|
|
||||||
class Prototype {
|
|
||||||
static addGlobalPropsReducer = addGlobalPropsReducer;
|
|
||||||
|
|
||||||
static addGlobalPropsConfigure = addGlobalPropsConfigure;
|
|
||||||
|
|
||||||
static addGlobalExtraActions = addGlobalExtraActions;
|
|
||||||
|
|
||||||
static removeGlobalPropsConfigure = removeGlobalPropsConfigure;
|
|
||||||
|
|
||||||
static overridePropsConfigure = overridePropsConfigure;
|
|
||||||
|
|
||||||
static registerPrototypeConfigPreprocessor = registerPrototypeConfigPreprocessor;
|
|
||||||
|
|
||||||
static getPrototypeConfigPreprocessorList = getPrototypeConfigPreprocessorList;
|
|
||||||
|
|
||||||
static create(config: OldPrototypeConfig | ComponentMetadata | ComponentMeta, extraConfigs: any = null, lookup = false) {
|
|
||||||
const modifiedConfig = modifyPrototypeConfig(config);
|
|
||||||
return new Prototype(modifiedConfig, extraConfigs, lookup);
|
|
||||||
}
|
|
||||||
|
|
||||||
readonly isPrototype = true;
|
|
||||||
|
|
||||||
readonly meta: ComponentMeta;
|
|
||||||
|
|
||||||
readonly options: OldPrototypeConfig | ComponentMetadata;
|
|
||||||
|
|
||||||
get componentName() {
|
|
||||||
return this.getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
get packageName() {
|
|
||||||
return this.meta.npm?.package;
|
|
||||||
}
|
|
||||||
|
|
||||||
set packageName(pkgName) {
|
|
||||||
if (this.meta.npm) {
|
|
||||||
this.meta.npm.package = pkgName;
|
|
||||||
} else {
|
|
||||||
this.meta.npm = { package: pkgName };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 兼容原 vision 用法
|
|
||||||
view: ComponentType | undefined;
|
|
||||||
|
|
||||||
constructor(input: OldPrototypeConfig | ComponentMetadata | ComponentMeta, extraConfigs: any = null, lookup = false) {
|
|
||||||
if (lookup) {
|
|
||||||
this.meta = designer.getComponentMeta(input.componentName);
|
|
||||||
this.options = this.meta.getMetadata();
|
|
||||||
return this.meta.prototype || this;
|
|
||||||
} else {
|
|
||||||
if (isComponentMeta(input)) {
|
|
||||||
this.meta = input;
|
|
||||||
this.options = input.getMetadata();
|
|
||||||
} else {
|
|
||||||
this.options = input;
|
|
||||||
const metadata = isNewSpec(input) ? input : upgradeMetadata(input);
|
|
||||||
this.meta = designer.createComponentMeta(metadata);
|
|
||||||
}
|
|
||||||
(this.meta as any).prototype = this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getId() {
|
|
||||||
return this.getComponentName();
|
|
||||||
}
|
|
||||||
|
|
||||||
getConfig(configName?: keyof (OldPrototypeConfig | ComponentMetadata)) {
|
|
||||||
if (configName) {
|
|
||||||
return this.options[configName];
|
|
||||||
}
|
|
||||||
return this.options;
|
|
||||||
}
|
|
||||||
|
|
||||||
getPackageName() {
|
|
||||||
return this.packageName;
|
|
||||||
}
|
|
||||||
|
|
||||||
getContextInfo(name: string): any {
|
|
||||||
return this.meta.getMetadata().experimental?.context?.[name];
|
|
||||||
}
|
|
||||||
|
|
||||||
getTitle() {
|
|
||||||
return intl(this.meta.title);
|
|
||||||
}
|
|
||||||
|
|
||||||
getComponentName() {
|
|
||||||
return this.meta.componentName;
|
|
||||||
}
|
|
||||||
|
|
||||||
getDocUrl() {
|
|
||||||
return this.meta.getMetadata().docUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
getPropConfigs() {
|
|
||||||
return this.options;
|
|
||||||
}
|
|
||||||
|
|
||||||
private category?: string;
|
|
||||||
|
|
||||||
getCategory() {
|
|
||||||
if (this.options.category != null) {
|
|
||||||
return this.options.category;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.meta.getMetadata().tags?.[0] || '*';
|
|
||||||
}
|
|
||||||
|
|
||||||
setCategory(category: string) {
|
|
||||||
this.options.category = category;
|
|
||||||
}
|
|
||||||
|
|
||||||
getIcon() {
|
|
||||||
return this.meta.icon;
|
|
||||||
}
|
|
||||||
|
|
||||||
getConfigure() {
|
|
||||||
return this.meta.configure;
|
|
||||||
}
|
|
||||||
|
|
||||||
getRectSelector() {
|
|
||||||
return this.meta.rootSelector;
|
|
||||||
}
|
|
||||||
|
|
||||||
isContainer() {
|
|
||||||
return this.meta.isContainer;
|
|
||||||
}
|
|
||||||
|
|
||||||
isModal() {
|
|
||||||
return this.meta.isModal;
|
|
||||||
}
|
|
||||||
|
|
||||||
isAutoGenerated() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
setPackageName(name: string, version?: string) {
|
|
||||||
this.meta.setNpm({
|
|
||||||
package: name,
|
|
||||||
version,
|
|
||||||
componentName: this.getComponentName(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setView(view: ComponentType<any>) {
|
|
||||||
this.view = view;
|
|
||||||
const metadata = this.meta.getMetadata();
|
|
||||||
if (!metadata.experimental) {
|
|
||||||
metadata.experimental = {
|
|
||||||
view,
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
metadata.experimental.view = view;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getView() {
|
|
||||||
return (
|
|
||||||
this.view ||
|
|
||||||
this.meta.getMetadata().experimental?.view ||
|
|
||||||
designer.currentDocument?.simulator?.getComponent(this.getComponentName())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isPrototype(obj: any): obj is Prototype {
|
|
||||||
return obj && obj.isPrototype;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Prototype;
|
|
||||||
@ -1,144 +0,0 @@
|
|||||||
import { ReactElement, ComponentType } from 'react';
|
|
||||||
import { EventEmitter } from 'events';
|
|
||||||
import { setters } from '@ali/lowcode-engine';
|
|
||||||
import { RegisteredSetter } from '@ali/lowcode-editor-core';
|
|
||||||
import lg from '@ali/vu-logger';
|
|
||||||
import { CustomView } from '@ali/lowcode-types';
|
|
||||||
import Bundle from './bundle';
|
|
||||||
import Prototype from './prototype';
|
|
||||||
|
|
||||||
const { registerSetter, getSetter } = setters;
|
|
||||||
|
|
||||||
export class Trunk {
|
|
||||||
private trunk: any[] = [];
|
|
||||||
|
|
||||||
private emitter: EventEmitter = new EventEmitter();
|
|
||||||
|
|
||||||
private metaBundle = new Bundle();
|
|
||||||
|
|
||||||
private componentPrototypeMocker: any;
|
|
||||||
|
|
||||||
isReady() {
|
|
||||||
return this.getList().length > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
addBundle(bundle: Bundle) {
|
|
||||||
this.trunk.push(bundle);
|
|
||||||
this.emitter.emit('trunkchange');
|
|
||||||
}
|
|
||||||
|
|
||||||
getBundle(): Bundle {
|
|
||||||
console.warn('Trunk.getBundle is deprecated');
|
|
||||||
return this.trunk[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
getList(): any[] {
|
|
||||||
const list = this.trunk.filter(o => o).reduceRight((prev, cur) => prev.concat(cur.getList()), []);
|
|
||||||
const result: Prototype[] = [];
|
|
||||||
list.forEach((item: Prototype) => {
|
|
||||||
if (!result.find(r => r.options.componentName === item.options.componentName)) {
|
|
||||||
result.push(item);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
getPrototype(name: string) {
|
|
||||||
let i = this.trunk.length;
|
|
||||||
let bundle;
|
|
||||||
let prototype;
|
|
||||||
while (i-- > 0) {
|
|
||||||
bundle = this.trunk[i];
|
|
||||||
prototype = bundle.get(name);
|
|
||||||
if (prototype) {
|
|
||||||
return (prototype.meta as any).prototype;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return this.metaBundle.getFromMeta(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
getPrototypeById(id: string) {
|
|
||||||
return this.getPrototype(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
listByCategory() {
|
|
||||||
const categories: any[] = [];
|
|
||||||
const categoryMap: any = {};
|
|
||||||
const categoryItems: any[] = [];
|
|
||||||
const defaultCategory = {
|
|
||||||
items: categoryItems,
|
|
||||||
name: '*',
|
|
||||||
};
|
|
||||||
categories.push(defaultCategory);
|
|
||||||
categoryMap['*'] = defaultCategory;
|
|
||||||
this.getList().forEach((prototype) => {
|
|
||||||
const cat = prototype.getCategory();
|
|
||||||
if (!cat) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!categoryMap.hasOwnProperty(cat)) {
|
|
||||||
const categoryMapItems: any[] = [];
|
|
||||||
categoryMap[cat] = {
|
|
||||||
items: categoryMapItems,
|
|
||||||
name: cat,
|
|
||||||
};
|
|
||||||
categories.push(categoryMap[cat]);
|
|
||||||
}
|
|
||||||
categoryMap[cat].items.push(prototype);
|
|
||||||
});
|
|
||||||
return categories;
|
|
||||||
}
|
|
||||||
|
|
||||||
getPrototypeView(componentName: string) {
|
|
||||||
return this.getPrototype(componentName)?.getView();
|
|
||||||
}
|
|
||||||
|
|
||||||
onTrunkChange(func: () => any) {
|
|
||||||
this.emitter.on('trunkchange', func);
|
|
||||||
return () => {
|
|
||||||
this.emitter.removeListener('trunkchange', func);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
registerSetter(type: string, setter: CustomView | RegisteredSetter) {
|
|
||||||
registerSetter(type, setter);
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeLoadBundle() {
|
|
||||||
console.warn('Trunk.beforeLoadBundle is deprecated');
|
|
||||||
}
|
|
||||||
|
|
||||||
afterLoadBundle() {
|
|
||||||
console.warn('Trunk.afterLoadBundle is deprecated');
|
|
||||||
}
|
|
||||||
|
|
||||||
registerComponentPrototypeMocker(mocker: any) {
|
|
||||||
this.componentPrototypeMocker = mocker;
|
|
||||||
}
|
|
||||||
|
|
||||||
mockComponentPrototype(bundle: any) {
|
|
||||||
if (!this.componentPrototypeMocker) {
|
|
||||||
lg.error('ERROR: no component prototypeMocker is set');
|
|
||||||
}
|
|
||||||
return this.componentPrototypeMocker
|
|
||||||
&& this.componentPrototypeMocker.mockPrototype(bundle);
|
|
||||||
}
|
|
||||||
|
|
||||||
setPackages() {
|
|
||||||
console.warn('Trunk.setPackages is deprecated');
|
|
||||||
}
|
|
||||||
|
|
||||||
getSetter(type: string): any {
|
|
||||||
const setter = getSetter(type);
|
|
||||||
if (setter?.component) {
|
|
||||||
return setter.component;
|
|
||||||
}
|
|
||||||
return setter;
|
|
||||||
}
|
|
||||||
|
|
||||||
getRecents(limit: number) {
|
|
||||||
return this.getList().filter((prototype) => prototype.getCategory()).slice(0, limit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default new Trunk();
|
|
||||||
@ -1,936 +0,0 @@
|
|||||||
import { ComponentType, ReactElement, isValidElement, ComponentClass } from 'react';
|
|
||||||
import { omit } from 'lodash';
|
|
||||||
import { isPlainObject, uniqueId, isVariable } from '@ali/lowcode-utils';
|
|
||||||
import {
|
|
||||||
isI18nData,
|
|
||||||
SettingTarget,
|
|
||||||
InitialItem,
|
|
||||||
FilterItem,
|
|
||||||
isJSSlot,
|
|
||||||
ProjectSchema,
|
|
||||||
AutorunItem,
|
|
||||||
isJSBlock,
|
|
||||||
isJSExpression,
|
|
||||||
} from '@ali/lowcode-types';
|
|
||||||
import { editorCabin, designerCabin } from '@ali/lowcode-engine';
|
|
||||||
|
|
||||||
const { SettingField } = designerCabin;
|
|
||||||
const { untracked } = editorCabin;
|
|
||||||
|
|
||||||
type Field = SettingTarget;
|
|
||||||
|
|
||||||
export enum DISPLAY_TYPE {
|
|
||||||
NONE = 'none', // => condition'plain'
|
|
||||||
PLAIN = 'plain',
|
|
||||||
INLINE = 'inline',
|
|
||||||
BLOCK = 'block',
|
|
||||||
ACCORDION = 'accordion',
|
|
||||||
TAB = 'tab', // => 'accordion'
|
|
||||||
ENTRY = 'entry',
|
|
||||||
}
|
|
||||||
|
|
||||||
type Tip = string | {
|
|
||||||
content?: string;
|
|
||||||
url?: string;
|
|
||||||
[key: string]: string | undefined;
|
|
||||||
};
|
|
||||||
// from vision 5.4
|
|
||||||
export interface OldPropConfig {
|
|
||||||
/**
|
|
||||||
* composite share the namespace
|
|
||||||
* group just be tie up together
|
|
||||||
*/
|
|
||||||
type?: 'composite' | 'group'; // => composite as objectSetter
|
|
||||||
/**
|
|
||||||
* when type is composite or group
|
|
||||||
*/
|
|
||||||
items?: OldPropConfig[]; // => items
|
|
||||||
/**
|
|
||||||
* property name: the field key in props of schema
|
|
||||||
*/
|
|
||||||
name: string; // =>
|
|
||||||
title?: string; // =>
|
|
||||||
tip?: Tip;
|
|
||||||
defaultValue?: any; // => extraProps.defaultValue
|
|
||||||
initialValue?: any | ((value: any, defaultValue: any) => any); // => initials.initialValue
|
|
||||||
initial?: (value: any, defaultValue: any) => any; // => initials.initialValue
|
|
||||||
|
|
||||||
display?: DISPLAY_TYPE; // => fieldExtraProps
|
|
||||||
fieldStyle?: DISPLAY_TYPE; // => fieldExtraProps
|
|
||||||
setter?: ComponentClass | ISetterConfig[] | string | SetterGetter; // =>
|
|
||||||
supportVariable?: boolean; // => use MixedSetter
|
|
||||||
/**
|
|
||||||
* the prop should be collapsed while display value is accordion
|
|
||||||
*/
|
|
||||||
collapse?: boolean; // => extraProps.defaultCollapsed
|
|
||||||
/**
|
|
||||||
* alias to collapse
|
|
||||||
*/
|
|
||||||
collapsed?: boolean; // => extraProps.defaultCollapsed
|
|
||||||
fieldCollapsed?: boolean; // => extraProps.defaultCollapsed
|
|
||||||
/**
|
|
||||||
* if a prop is declared as disabled, it will not be saved into
|
|
||||||
* schema
|
|
||||||
*/
|
|
||||||
disabled?: boolean | ReturnBooleanFunction; // => hide & virtual ? thinkof global transform
|
|
||||||
/**
|
|
||||||
* will not export data to schema
|
|
||||||
*/
|
|
||||||
ignore?: boolean | ReturnBooleanFunction; // => ?virtualProp ? thinkof global transform
|
|
||||||
hidden?: boolean | ReturnBooleanFunction; // => condition
|
|
||||||
|
|
||||||
/**
|
|
||||||
* when use getValue(), accessor shall be called as initializer
|
|
||||||
*/
|
|
||||||
accessor?(this: Field, value: any): any; // => getValue
|
|
||||||
/**
|
|
||||||
* when current prop value mutate, the mutator function shall be called
|
|
||||||
*/
|
|
||||||
mutator?( // => setValue
|
|
||||||
this: Field,
|
|
||||||
value: any,
|
|
||||||
hotValue: any,
|
|
||||||
): /*
|
|
||||||
preValue: any, // => x
|
|
||||||
preHotValue: any, // => x
|
|
||||||
*/
|
|
||||||
void;
|
|
||||||
/**
|
|
||||||
* other values' change will trigger sync function here
|
|
||||||
*/
|
|
||||||
sync?(this: Field, value: any): void; // => autorun
|
|
||||||
/**
|
|
||||||
* user click var to change current field to
|
|
||||||
* variable setting field
|
|
||||||
*/
|
|
||||||
useVariableChange?(this: Field, data: { isUseVariable: boolean }): any; // => as MixinSetter param
|
|
||||||
|
|
||||||
slotName?: string;
|
|
||||||
slotTitle?: string;
|
|
||||||
initialChildren?: any; // schema
|
|
||||||
allowTextInput: boolean;
|
|
||||||
liveTextEditing?: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
type ResizeHandler = (dragment: any, triggerDirection: string) => boolean;
|
|
||||||
type ResizeCompositeHandler = { handle: ResizeHandler; availableDirects: string[] | undefined };
|
|
||||||
type CanResize = boolean | ResizeHandler | ResizeCompositeHandler;
|
|
||||||
|
|
||||||
function isResizeCompositeHandler(resize: CanResize): resize is ResizeCompositeHandler {
|
|
||||||
if ((resize as any).handle) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// from vision 5.4
|
|
||||||
export interface OldPrototypeConfig {
|
|
||||||
packageName: string; // => npm.package
|
|
||||||
/**
|
|
||||||
* category display in the component pane·
|
|
||||||
* component will be hidden while the value is: null
|
|
||||||
*/
|
|
||||||
category: string; // => tags
|
|
||||||
componentName: string; // =>
|
|
||||||
docUrl?: string; // =>
|
|
||||||
defaultProps?: any; // => ?
|
|
||||||
isMinimalRenderUnit?: boolean; // => false
|
|
||||||
/**
|
|
||||||
* extra actions on the outline of current selected node
|
|
||||||
* by default we have: remove / clone
|
|
||||||
*/
|
|
||||||
extraActions?: Array<ComponentType<any> | ReactElement> | (() => ReactElement); // => configure.component.actions
|
|
||||||
title?: string; // =>
|
|
||||||
icon?: ComponentType<any> | ReactElement; // =>
|
|
||||||
view: ComponentType; // => ?
|
|
||||||
initialChildren?: (props: any) => any[]; // => snippets
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Props configurations of node
|
|
||||||
*/
|
|
||||||
configure: OldPropConfig[]; // => configure.props
|
|
||||||
snippets?: any[]; // => snippets
|
|
||||||
transducers?: any; // => ?
|
|
||||||
/**
|
|
||||||
* Selector expression rectangle of a node, it is usually a querySelector string
|
|
||||||
* @example '.classname > div'
|
|
||||||
*/
|
|
||||||
rectSelector?: string; // => configure.component.rectSelector
|
|
||||||
context?: {
|
|
||||||
// => ?
|
|
||||||
[contextInfoName: string]: any;
|
|
||||||
};
|
|
||||||
|
|
||||||
isContainer?: boolean; // => configure.component.isContainer
|
|
||||||
isAbsoluteLayoutContainer?: boolean; // => meta.experimental.isAbsoluteLayoutContainer 是否是绝对定位容器
|
|
||||||
hideSelectTools?: boolean; // => meta.experimental.hideSelectTools
|
|
||||||
isModal?: boolean; // => configure.component.isModal
|
|
||||||
isFloating?: boolean; // => configure.component.isFloating
|
|
||||||
descriptor?: string; // => configure.component.descriptor
|
|
||||||
|
|
||||||
// alias to canDragging
|
|
||||||
canDraging?: boolean; // => onDrag
|
|
||||||
canDragging?: boolean; // => ?
|
|
||||||
canHovering?: ((dragment: Node) => boolean) | boolean;
|
|
||||||
canSelecting?: boolean; // => onClickHook
|
|
||||||
canOperating?: boolean; // => disabledActions
|
|
||||||
canUseCondition?: boolean;
|
|
||||||
canLoop?: boolean;
|
|
||||||
canContain?: (dragment: Node) => boolean; // => nestingRule
|
|
||||||
|
|
||||||
canDropTo?: ((container: Node) => boolean) | boolean | string | string[]; // => nestingRule
|
|
||||||
canDropto?: ((container: Node) => boolean) | boolean | string | string[]; // => nestingRule
|
|
||||||
|
|
||||||
canDropIn?: ((dragment: Node) => boolean) | boolean | string | string[]; // => nestingRule
|
|
||||||
canDroping?: ((dragment: Node) => boolean) | boolean | string | string[]; // => nestingRule
|
|
||||||
|
|
||||||
didDropOut?: (dragment: any, container: any) => void; // => hooks
|
|
||||||
didDropIn?: (dragment: any, container: any) => void; // => hooks
|
|
||||||
|
|
||||||
/**
|
|
||||||
* when sub-node of the current node changed
|
|
||||||
* including: sub-node insert / remove
|
|
||||||
*/
|
|
||||||
subtreeModified?(this: Node): any; // => ? hooks
|
|
||||||
|
|
||||||
// => ?
|
|
||||||
canResizing?: CanResize;
|
|
||||||
onResizeStart?: (e: MouseEvent, triggerDirection: string, dragment: Node) => void;
|
|
||||||
onResize?: (
|
|
||||||
e: MouseEvent,
|
|
||||||
triggerDirection: string,
|
|
||||||
dragment: Node,
|
|
||||||
moveX: number,
|
|
||||||
moveY: number,
|
|
||||||
) => void;
|
|
||||||
onResizeEnd?: (e: MouseEvent, triggerDirection: string, dragment: Node) => void;
|
|
||||||
devMode?: string;
|
|
||||||
schema?: ProjectSchema;
|
|
||||||
isTopFixed?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ISetterConfig {
|
|
||||||
setter?: ComponentClass;
|
|
||||||
// use value to decide whether this setter is available
|
|
||||||
condition?: (value: any) => boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
type SetterGetter = (this: Field, value: any) => ComponentClass;
|
|
||||||
|
|
||||||
type ReturnBooleanFunction = (this: Field, value: any) => boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取剥去 variable / JSExpression 结构后的值
|
|
||||||
* @param propValue
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
function getRawValue(propValue: any) {
|
|
||||||
if (isVariable(propValue)) {
|
|
||||||
return propValue.value;
|
|
||||||
}
|
|
||||||
if (isJSExpression(propValue)) {
|
|
||||||
return propValue.mock;
|
|
||||||
}
|
|
||||||
return propValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据原始值的数据结构(JSExpression / variable / 普通)转换 value,保持相同结构
|
|
||||||
* @param originalValue
|
|
||||||
* @param value
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
function formatPropValue(originalValue: any, value: any) {
|
|
||||||
if (isJSExpression(originalValue)) {
|
|
||||||
return {
|
|
||||||
type: originalValue.type,
|
|
||||||
value: originalValue.value,
|
|
||||||
mock: value,
|
|
||||||
...omit(originalValue, ['type', 'value']),
|
|
||||||
};
|
|
||||||
} else if (isVariable(originalValue)) {
|
|
||||||
return {
|
|
||||||
type: originalValue.type,
|
|
||||||
variable: originalValue.variable,
|
|
||||||
value,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isTipString(tip: Tip): tip is string {
|
|
||||||
return typeof tip === 'string';
|
|
||||||
}
|
|
||||||
|
|
||||||
function getTipAttr(tip: Tip, attrName: string, decorator: (originalValue: string) => string = v => v): string {
|
|
||||||
if (isTipString(tip)) {
|
|
||||||
return attrName === 'content' ? decorator(tip) : '';
|
|
||||||
}
|
|
||||||
return decorator(tip[attrName]!);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getTipContent(tip: Tip, name: string): string {
|
|
||||||
return getTipAttr(tip, 'content', (v) => `属性:${name} | 说明:${v}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function upgradePropConfig(config: OldPropConfig, collector: ConfigCollector) {
|
|
||||||
const {
|
|
||||||
type,
|
|
||||||
name,
|
|
||||||
title,
|
|
||||||
tip,
|
|
||||||
slotName,
|
|
||||||
slotTitle,
|
|
||||||
initialChildren,
|
|
||||||
allowTextInput,
|
|
||||||
initialValue,
|
|
||||||
defaultValue,
|
|
||||||
display,
|
|
||||||
fieldStyle,
|
|
||||||
collapse,
|
|
||||||
collapsed,
|
|
||||||
fieldCollapsed,
|
|
||||||
hidden,
|
|
||||||
disabled,
|
|
||||||
items,
|
|
||||||
ignore,
|
|
||||||
initial,
|
|
||||||
sync,
|
|
||||||
accessor,
|
|
||||||
mutator,
|
|
||||||
setter,
|
|
||||||
useVariableChange,
|
|
||||||
supportVariable,
|
|
||||||
liveTextEditing,
|
|
||||||
} = config;
|
|
||||||
|
|
||||||
const extraProps: any = {
|
|
||||||
display: DISPLAY_TYPE.BLOCK,
|
|
||||||
};
|
|
||||||
const newConfig: any = {
|
|
||||||
type: type === 'group' ? 'group' : 'field',
|
|
||||||
name: type === 'group' && !name ? uniqueId('group') : name,
|
|
||||||
title,
|
|
||||||
extraProps,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (tip) {
|
|
||||||
if (typeof title !== 'object' || isI18nData(title) || isValidElement(title)) {
|
|
||||||
newConfig.title = {
|
|
||||||
label: title,
|
|
||||||
tip: getTipContent(tip, name),
|
|
||||||
docUrl: getTipAttr(tip, 'url'),
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
newConfig.title = {
|
|
||||||
...(title as any),
|
|
||||||
tip: getTipContent(tip, name),
|
|
||||||
docUrl: getTipAttr(tip, 'url'),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (display || fieldStyle) {
|
|
||||||
extraProps.display = display || fieldStyle;
|
|
||||||
if (extraProps.display === DISPLAY_TYPE.TAB) {
|
|
||||||
extraProps.display = DISPLAY_TYPE.ACCORDION;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (collapse || collapsed || fieldCollapsed || extraProps.display === DISPLAY_TYPE.ENTRY) {
|
|
||||||
extraProps.defaultCollapsed = true;
|
|
||||||
}
|
|
||||||
function isDisabled(field: Field) {
|
|
||||||
if (typeof disabled === 'function') {
|
|
||||||
return disabled.call(field, field.getValue()) === true;
|
|
||||||
}
|
|
||||||
return disabled === true;
|
|
||||||
}
|
|
||||||
function isHidden(field: Field) {
|
|
||||||
if (typeof hidden === 'function') {
|
|
||||||
return hidden.call(field, field.getValue()) === true;
|
|
||||||
}
|
|
||||||
return hidden === true;
|
|
||||||
}
|
|
||||||
if (extraProps.display === DISPLAY_TYPE.NONE) {
|
|
||||||
extraProps.display = undefined;
|
|
||||||
extraProps.condition = () => false;
|
|
||||||
} else if (hidden != null || disabled != null) {
|
|
||||||
extraProps.condition = (field: Field) => !(isHidden(field) || isDisabled(field));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type === 'group') {
|
|
||||||
newConfig.items = items ? upgradeConfigure(items, collector) : [];
|
|
||||||
return newConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (defaultValue !== undefined) {
|
|
||||||
extraProps.defaultValue = defaultValue;
|
|
||||||
} else if (typeof initialValue !== 'function') {
|
|
||||||
extraProps.defaultValue = initialValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let initialFn = (slotName ? null : initial) || initialValue;
|
|
||||||
if (slotName && initialValue === true) {
|
|
||||||
initialFn = (value: any, defaultValue: any) => {
|
|
||||||
// initialValue 为 true,但 value 为 false / '' 等值,说明被关闭了
|
|
||||||
if (value === false || value === '') return value;
|
|
||||||
if (isJSBlock(value) || isJSSlot(value)) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
type: 'JSSlot',
|
|
||||||
title: slotTitle || title,
|
|
||||||
name: slotName,
|
|
||||||
value: initialChildren,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!slotName) {
|
|
||||||
if (accessor) {
|
|
||||||
extraProps.getValue = (field: Field, fieldValue: any) => {
|
|
||||||
return accessor.call(field, fieldValue);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sync || accessor) {
|
|
||||||
collector.addAutorun({
|
|
||||||
name,
|
|
||||||
autorun: (field: Field) => {
|
|
||||||
let fieldValue = untracked(() => field.getValue());
|
|
||||||
if (accessor) {
|
|
||||||
fieldValue = accessor.call(field, fieldValue);
|
|
||||||
}
|
|
||||||
if (sync) {
|
|
||||||
fieldValue = sync.call(field, fieldValue);
|
|
||||||
if (fieldValue !== undefined) {
|
|
||||||
field.setValue(fieldValue);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
field.setValue(fieldValue);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mutator) {
|
|
||||||
extraProps.setValue = (field: Field, value: any) => {
|
|
||||||
// TODO: 兼容代码,不触发查询组件的 Mutator
|
|
||||||
if (field instanceof SettingField && field.componentMeta?.componentName === 'Filter') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mutator.call(field, value, value);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const setterInitial = getInitialFromSetter(setter);
|
|
||||||
|
|
||||||
if (type !== 'composite') {
|
|
||||||
collector.addInitial({
|
|
||||||
// FIXME! name could be "xxx.xxx"
|
|
||||||
name: slotName || name,
|
|
||||||
initial: (field: Field, currentValue: any) => {
|
|
||||||
// FIXME! read from prototype.defaultProps
|
|
||||||
const defaults = extraProps.defaultValue;
|
|
||||||
|
|
||||||
if (typeof initialFn !== 'function') {
|
|
||||||
initialFn = defaultInitial;
|
|
||||||
}
|
|
||||||
|
|
||||||
const rawValue = getRawValue(currentValue);
|
|
||||||
const v = initialFn.call(field, rawValue, defaults);
|
|
||||||
|
|
||||||
if (setterInitial) {
|
|
||||||
return formatPropValue(currentValue, setterInitial.call(field, v, defaults));
|
|
||||||
}
|
|
||||||
|
|
||||||
return formatPropValue(currentValue, v);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ignore != null || disabled != null) {
|
|
||||||
collector.addFilter({
|
|
||||||
// FIXME! name should be "xxx.xxx"
|
|
||||||
name: slotName || name,
|
|
||||||
filter: (field: Field, currentValue: any) => {
|
|
||||||
let disabledValue: boolean;
|
|
||||||
if (typeof disabled === 'function') {
|
|
||||||
disabledValue = disabled.call(field, currentValue) === true;
|
|
||||||
} else {
|
|
||||||
disabledValue = disabled === true;
|
|
||||||
}
|
|
||||||
if (disabledValue) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (typeof ignore === 'function') {
|
|
||||||
return ignore.call(field, currentValue) !== true;
|
|
||||||
}
|
|
||||||
return ignore !== true;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (slotName) {
|
|
||||||
newConfig.name = slotName;
|
|
||||||
if (!newConfig.title && slotTitle) {
|
|
||||||
newConfig.title = slotTitle;
|
|
||||||
}
|
|
||||||
const setters: any[] = [
|
|
||||||
{
|
|
||||||
componentName: 'SlotSetter',
|
|
||||||
initialValue: (field: any, value: any) => {
|
|
||||||
if (isJSSlot(value)) {
|
|
||||||
return {
|
|
||||||
title: slotTitle || title,
|
|
||||||
...value,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
type: 'JSSlot',
|
|
||||||
title: slotTitle || title,
|
|
||||||
name: slotName,
|
|
||||||
value: value == null ? initialChildren : value,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
if (allowTextInput) {
|
|
||||||
setters.unshift('I18nSetter');
|
|
||||||
}
|
|
||||||
if (supportVariable) {
|
|
||||||
setters.push('VariableSetter');
|
|
||||||
}
|
|
||||||
newConfig.setter = setters.length > 1 ? setters : setters[0];
|
|
||||||
|
|
||||||
return newConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
let primarySetter: any;
|
|
||||||
if (type === 'composite') {
|
|
||||||
const initials: InitialItem[] = [];
|
|
||||||
const objItems = items
|
|
||||||
? upgradeConfigure(items, {
|
|
||||||
addInitial: (item) => {
|
|
||||||
initials.push(item);
|
|
||||||
},
|
|
||||||
addFilter: (item) => {
|
|
||||||
collector.addFilter({
|
|
||||||
name: `${name}.${item.name}`,
|
|
||||||
filter: item.filter,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
addAutorun: (item) => {
|
|
||||||
collector.addAutorun({
|
|
||||||
name: `${name}.${item.name}`,
|
|
||||||
autorun: item.autorun,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
})
|
|
||||||
: [];
|
|
||||||
newConfig.items = objItems;
|
|
||||||
|
|
||||||
const initial = (target: SettingTarget, value?: any) => {
|
|
||||||
// TODO:
|
|
||||||
const defaults = extraProps.defaultValue;
|
|
||||||
const data: any = {};
|
|
||||||
initials.forEach((item) => {
|
|
||||||
// FIXME! Target may be a wrong
|
|
||||||
data[item.name] = item.initial(target, isPlainObject(value) ? value[item.name] : null);
|
|
||||||
});
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
collector.addInitial({
|
|
||||||
name,
|
|
||||||
initial,
|
|
||||||
});
|
|
||||||
primarySetter = {
|
|
||||||
componentName: 'ObjectSetter',
|
|
||||||
props: {
|
|
||||||
config: {
|
|
||||||
items: objItems,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
initialValue: (field: Field) => {
|
|
||||||
return initial(field, field.getValue());
|
|
||||||
},
|
|
||||||
};
|
|
||||||
} else if (setter) {
|
|
||||||
if (Array.isArray(setter)) {
|
|
||||||
// FIXME! read initial from setter
|
|
||||||
primarySetter = setter.map(({ setter, condition }) => {
|
|
||||||
return {
|
|
||||||
componentName: setter,
|
|
||||||
condition: condition
|
|
||||||
? (field: Field) => {
|
|
||||||
return condition.call(field, field.getValue());
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
primarySetter = setter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!primarySetter) {
|
|
||||||
primarySetter = 'I18nSetter';
|
|
||||||
}
|
|
||||||
if (supportVariable) {
|
|
||||||
const setters = Array.isArray(primarySetter)
|
|
||||||
? primarySetter.concat('VariableSetter')
|
|
||||||
: [primarySetter, 'VariableSetter'];
|
|
||||||
primarySetter = {
|
|
||||||
componentName: 'MixedSetter',
|
|
||||||
props: {
|
|
||||||
setters,
|
|
||||||
onSetterChange: (field: Field, name: string) => {
|
|
||||||
if (useVariableChange) {
|
|
||||||
useVariableChange.call(field, { isUseVariable: name === 'VariableSetter' });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
newConfig.setter = primarySetter;
|
|
||||||
|
|
||||||
if (liveTextEditing) {
|
|
||||||
extraProps.liveTextEditing = liveTextEditing;
|
|
||||||
}
|
|
||||||
|
|
||||||
return newConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
type AddInitial = (initialItem: InitialItem) => void;
|
|
||||||
type AddFilter = (filterItem: FilterItem) => void;
|
|
||||||
type AddAutorun = (autorunItem: AutorunItem) => void;
|
|
||||||
|
|
||||||
type ConfigCollector = {
|
|
||||||
addInitial: AddInitial;
|
|
||||||
addFilter: AddFilter;
|
|
||||||
addAutorun: AddAutorun;
|
|
||||||
};
|
|
||||||
|
|
||||||
function getInitialFromSetter(setter: any) {
|
|
||||||
return (
|
|
||||||
(setter &&
|
|
||||||
(setter.initial ||
|
|
||||||
setter.Initial ||
|
|
||||||
(setter.type && (setter.type.initial || setter.type.Initial)))) ||
|
|
||||||
null
|
|
||||||
); // eslint-disable-line
|
|
||||||
}
|
|
||||||
|
|
||||||
function defaultInitial(value: any, defaultValue: any) {
|
|
||||||
return value == null ? defaultValue : value;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function upgradeConfigure(items: OldPropConfig[], collector: ConfigCollector) {
|
|
||||||
const configure: any[] = [];
|
|
||||||
let ignoreSlotName: any = null;
|
|
||||||
items.forEach((config) => {
|
|
||||||
if (config.slotName) {
|
|
||||||
ignoreSlotName = config.slotName;
|
|
||||||
} else if (ignoreSlotName) {
|
|
||||||
if (config.name === ignoreSlotName) {
|
|
||||||
ignoreSlotName = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ignoreSlotName = null;
|
|
||||||
}
|
|
||||||
configure.push(upgradePropConfig(config, collector));
|
|
||||||
});
|
|
||||||
return configure;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function upgradeActions(
|
|
||||||
actions?: Array<ComponentType<any> | ReactElement> | (() => ReactElement),
|
|
||||||
) {
|
|
||||||
if (!actions) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (!Array.isArray(actions)) {
|
|
||||||
actions = [actions];
|
|
||||||
}
|
|
||||||
return actions.map((content) => {
|
|
||||||
const type: any = isValidElement(content) ? content.type : content;
|
|
||||||
if (typeof content === 'function') {
|
|
||||||
const fn = content as () => ReactElement;
|
|
||||||
content = (({ node }: any) => {
|
|
||||||
return fn.call(node);
|
|
||||||
}) as any;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
name: type.displayName || type.name || 'anonymous',
|
|
||||||
content,
|
|
||||||
important: true,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 升级
|
|
||||||
*/
|
|
||||||
export function upgradeMetadata(oldConfig: OldPrototypeConfig) {
|
|
||||||
const {
|
|
||||||
componentName,
|
|
||||||
docUrl,
|
|
||||||
title,
|
|
||||||
icon,
|
|
||||||
packageName,
|
|
||||||
category,
|
|
||||||
extraActions,
|
|
||||||
defaultProps,
|
|
||||||
initialChildren,
|
|
||||||
snippets,
|
|
||||||
view,
|
|
||||||
configure,
|
|
||||||
transducers,
|
|
||||||
isContainer,
|
|
||||||
isAbsoluteLayoutContainer,
|
|
||||||
hideSelectTools,
|
|
||||||
rectSelector,
|
|
||||||
isModal,
|
|
||||||
isFloating,
|
|
||||||
descriptor,
|
|
||||||
context,
|
|
||||||
canOperating,
|
|
||||||
canContain,
|
|
||||||
canDropTo,
|
|
||||||
canDropto,
|
|
||||||
canDropIn,
|
|
||||||
canDroping,
|
|
||||||
canUseCondition,
|
|
||||||
canLoop,
|
|
||||||
|
|
||||||
// hooks
|
|
||||||
canDraging,
|
|
||||||
canDragging, // handleDragging
|
|
||||||
canSelecting, // onClickHook
|
|
||||||
canHovering,
|
|
||||||
// events
|
|
||||||
didDropOut, // onNodeRemove
|
|
||||||
didDropIn, // onNodeAdd
|
|
||||||
subtreeModified, // onSubtreeModified
|
|
||||||
|
|
||||||
onResizeStart, // onResizeStart
|
|
||||||
onResize, // onResize
|
|
||||||
onResizeEnd, // onResizeEnd
|
|
||||||
devMode,
|
|
||||||
schema,
|
|
||||||
isTopFixed,
|
|
||||||
|
|
||||||
// render
|
|
||||||
isMinimalRenderUnit,
|
|
||||||
} = oldConfig;
|
|
||||||
let {
|
|
||||||
canResizing, // resizing
|
|
||||||
} = oldConfig;
|
|
||||||
|
|
||||||
const meta: any = {
|
|
||||||
componentName,
|
|
||||||
title,
|
|
||||||
icon,
|
|
||||||
docUrl,
|
|
||||||
devMode: devMode || 'procode',
|
|
||||||
schema: schema?.componentsTree[0],
|
|
||||||
};
|
|
||||||
|
|
||||||
if (category) {
|
|
||||||
meta.tags = [category];
|
|
||||||
}
|
|
||||||
if (packageName) {
|
|
||||||
meta.npm = {
|
|
||||||
componentName,
|
|
||||||
package: packageName,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const component: any = {
|
|
||||||
isContainer,
|
|
||||||
rootSelector: rectSelector,
|
|
||||||
isModal,
|
|
||||||
isFloating,
|
|
||||||
descriptor,
|
|
||||||
isMinimalRenderUnit,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (canOperating === false) {
|
|
||||||
component.disableBehaviors = '*';
|
|
||||||
}
|
|
||||||
if (extraActions) {
|
|
||||||
component.actions = upgradeActions(extraActions);
|
|
||||||
}
|
|
||||||
const nestingRule: any = {};
|
|
||||||
if (canContain) {
|
|
||||||
nestingRule.descendantWhitelist = canContain;
|
|
||||||
}
|
|
||||||
if (canDropTo != null || canDropto != null) {
|
|
||||||
if (canDropTo === false || canDropto === false) {
|
|
||||||
nestingRule.parentWhitelist = () => false;
|
|
||||||
} else if (canDropTo !== true && canDropto !== true) {
|
|
||||||
nestingRule.parentWhitelist = canDropTo || canDropto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (canDropIn != null || canDroping != null) {
|
|
||||||
if (canDropIn === false || canDroping === false) {
|
|
||||||
nestingRule.childWhitelist = () => false;
|
|
||||||
} else if (canDropIn !== true && canDroping !== true) {
|
|
||||||
nestingRule.childWhitelist = canDropIn || canDroping;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
component.nestingRule = nestingRule;
|
|
||||||
|
|
||||||
// 未考虑清楚的,放在实验性段落
|
|
||||||
const experimental: any = {
|
|
||||||
isAbsoluteLayoutContainer,
|
|
||||||
hideSelectTools,
|
|
||||||
};
|
|
||||||
if (context) {
|
|
||||||
// for prototype.getContextInfo
|
|
||||||
experimental.context = context;
|
|
||||||
}
|
|
||||||
if (snippets) {
|
|
||||||
experimental.snippets = snippets.map((data) => {
|
|
||||||
const { schema = {} } = data;
|
|
||||||
if (!schema.children && initialChildren && typeof initialChildren !== 'function') {
|
|
||||||
schema.children = initialChildren;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
...data,
|
|
||||||
schema,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// FIXME! defaultProps for initial input
|
|
||||||
// initialChildren maybe a function
|
|
||||||
else if (defaultProps || initialChildren) {
|
|
||||||
const snippet = {
|
|
||||||
screenshot: icon,
|
|
||||||
label: title,
|
|
||||||
schema: {
|
|
||||||
componentName,
|
|
||||||
props: defaultProps,
|
|
||||||
children: initialChildren,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
if (experimental.snippets) {
|
|
||||||
experimental.snippets.push(snippet);
|
|
||||||
} else {
|
|
||||||
experimental.snippets = [snippet];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (initialChildren) {
|
|
||||||
experimental.initialChildren =
|
|
||||||
typeof initialChildren === 'function'
|
|
||||||
? (node: any) => {
|
|
||||||
return initialChildren.call(node, node.settingEntry);
|
|
||||||
}
|
|
||||||
: initialChildren;
|
|
||||||
}
|
|
||||||
if (view) {
|
|
||||||
experimental.view = view;
|
|
||||||
}
|
|
||||||
if (isTopFixed) {
|
|
||||||
experimental.isTopFixed = isTopFixed;
|
|
||||||
}
|
|
||||||
if (transducers) {
|
|
||||||
// Array<{ toStatic, toNative }>
|
|
||||||
// ? only twice
|
|
||||||
experimental.transducers = transducers;
|
|
||||||
}
|
|
||||||
if (canResizing) {
|
|
||||||
let availableDirects = ['n', 'e', 's', 'w'];
|
|
||||||
if (isResizeCompositeHandler(canResizing)) {
|
|
||||||
availableDirects = canResizing.availableDirects || availableDirects;
|
|
||||||
canResizing = canResizing.handle;
|
|
||||||
}
|
|
||||||
experimental.getResizingHandlers = (currentNode: any) => {
|
|
||||||
if (canResizing === true) {
|
|
||||||
return availableDirects;
|
|
||||||
}
|
|
||||||
return availableDirects.filter((d) => (canResizing as ResizeHandler)(currentNode, d));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const callbacks: any = {};
|
|
||||||
if (canDragging != null || canDraging != null) {
|
|
||||||
let v = true;
|
|
||||||
if (canDragging === false || canDraging === false) {
|
|
||||||
v = false;
|
|
||||||
}
|
|
||||||
callbacks.onMoveHook = () => v;
|
|
||||||
}
|
|
||||||
if (canSelecting != null) {
|
|
||||||
let v = true;
|
|
||||||
if (canSelecting === false) {
|
|
||||||
v = false;
|
|
||||||
}
|
|
||||||
callbacks.onClickHook = () => v;
|
|
||||||
}
|
|
||||||
if (canHovering != null) {
|
|
||||||
callbacks.onHoverHook = typeof canHovering === 'boolean' ? () => canHovering : canHovering;
|
|
||||||
}
|
|
||||||
if (didDropIn) {
|
|
||||||
callbacks.onNodeAdd = didDropIn;
|
|
||||||
}
|
|
||||||
if (didDropOut) {
|
|
||||||
callbacks.onNodeRemove = didDropOut;
|
|
||||||
}
|
|
||||||
if (subtreeModified) {
|
|
||||||
callbacks.onSubtreeModified = subtreeModified;
|
|
||||||
}
|
|
||||||
if (onResize) {
|
|
||||||
callbacks.onResize = (e: any, currentNode: any) => {
|
|
||||||
// todo: what is trigger?
|
|
||||||
const { trigger, deltaX, deltaY } = e;
|
|
||||||
onResize(e, trigger, currentNode, deltaX, deltaY);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (onResizeStart) {
|
|
||||||
callbacks.onResizeStart = (e: any, currentNode: any) => {
|
|
||||||
// todo: what is trigger?
|
|
||||||
const { trigger } = e;
|
|
||||||
onResizeStart(e, trigger, currentNode);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (onResizeEnd) {
|
|
||||||
callbacks.onResizeEnd = (e: any, currentNode: any) => {
|
|
||||||
// todo: what is trigger?
|
|
||||||
const { trigger } = e;
|
|
||||||
onResizeEnd(e, trigger, currentNode);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
experimental.callbacks = callbacks;
|
|
||||||
|
|
||||||
const initials: InitialItem[] = [];
|
|
||||||
const filters: FilterItem[] = [];
|
|
||||||
const autoruns: AutorunItem[] = [];
|
|
||||||
const props = upgradeConfigure(configure || [], {
|
|
||||||
addInitial: (item) => {
|
|
||||||
initials.push(item);
|
|
||||||
},
|
|
||||||
addFilter: (item) => {
|
|
||||||
filters.push(item);
|
|
||||||
},
|
|
||||||
addAutorun: (item) => {
|
|
||||||
autoruns.push(item);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
experimental.initials = initials;
|
|
||||||
experimental.filters = filters;
|
|
||||||
experimental.autoruns = autoruns;
|
|
||||||
|
|
||||||
const supports: any = {};
|
|
||||||
if (canUseCondition != null) {
|
|
||||||
supports.condition = canUseCondition;
|
|
||||||
}
|
|
||||||
if (canLoop != null) {
|
|
||||||
supports.loop = canLoop;
|
|
||||||
}
|
|
||||||
meta.configure = { props, component, supports };
|
|
||||||
meta.experimental = experimental;
|
|
||||||
return meta;
|
|
||||||
}
|
|
||||||
@ -1,104 +0,0 @@
|
|||||||
import logger from '@ali/vu-logger';
|
|
||||||
import { EventEmitter } from 'events';
|
|
||||||
import { editor, designer } from '@ali/lowcode-engine';
|
|
||||||
import { GlobalEvent, isJSExpression } from '@ali/lowcode-types';
|
|
||||||
import env from './env';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bus class as an EventEmitter
|
|
||||||
*/
|
|
||||||
export class Bus {
|
|
||||||
private emitter = new EventEmitter();
|
|
||||||
|
|
||||||
getEmitter() {
|
|
||||||
return this.emitter;
|
|
||||||
}
|
|
||||||
|
|
||||||
// alias to sub
|
|
||||||
on(event: string | symbol, func: (...args: any[]) => any): any {
|
|
||||||
return this.sub(event, func);
|
|
||||||
}
|
|
||||||
|
|
||||||
// alias to unsub
|
|
||||||
off(event: string, func: (...args: any[]) => any) {
|
|
||||||
this.unsub(event, func);
|
|
||||||
}
|
|
||||||
|
|
||||||
// alias to pub
|
|
||||||
emit(event: string, ...args: any[]): boolean {
|
|
||||||
return this.pub(event, ...args);
|
|
||||||
}
|
|
||||||
|
|
||||||
sub(event: string | symbol, func: (...args: any[]) => any) {
|
|
||||||
this.emitter.on(event, func);
|
|
||||||
return () => {
|
|
||||||
this.emitter.removeListener(event, func);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
once(event: string, func: (...args: any[]) => any) {
|
|
||||||
this.emitter.once(event, func);
|
|
||||||
return () => {
|
|
||||||
this.emitter.removeListener(event, func);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
unsub(event: string, func: (...args: any[]) => any) {
|
|
||||||
if (func) {
|
|
||||||
this.emitter.removeListener(event, func);
|
|
||||||
} else {
|
|
||||||
this.emitter.removeAllListeners(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Release & Publish Events
|
|
||||||
*/
|
|
||||||
pub(event: string, ...args: any[]): boolean {
|
|
||||||
logger.info('INFO:', 'eventData:', event, ...args);
|
|
||||||
return this.emitter.emit(event, ...args);
|
|
||||||
}
|
|
||||||
|
|
||||||
removeListener(eventName: string | symbol, callback: () => any) {
|
|
||||||
return this.emitter.removeListener(eventName, callback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const bus = new Bus();
|
|
||||||
|
|
||||||
editor?.on('hotkey.callback.call', (data) => {
|
|
||||||
bus.emit('ve.hotkey.callback.call', data);
|
|
||||||
});
|
|
||||||
|
|
||||||
editor?.on('history.back', (data) => {
|
|
||||||
bus.emit('ve.history.back', data);
|
|
||||||
});
|
|
||||||
|
|
||||||
editor?.on('history.forward', (data) => {
|
|
||||||
bus.emit('ve.history.forward', data);
|
|
||||||
});
|
|
||||||
|
|
||||||
env.onEnvChange((_envs, name, value) => {
|
|
||||||
if (name !== 'locale') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
designer.project.simulator?.set(name, value.replace('_', '-'));
|
|
||||||
});
|
|
||||||
|
|
||||||
function triggerUseVariableChange(data: any) {
|
|
||||||
const { node, prop, oldValue, newValue } = data;
|
|
||||||
const propConfig = node.componentMeta.prototype?.options.configure.find((o: any) => o.name === prop.getKey());
|
|
||||||
if (!propConfig?.useVariableChange) return;
|
|
||||||
if (isJSExpression(oldValue) && !isJSExpression(newValue)) {
|
|
||||||
propConfig.useVariableChange.call(prop, { isUseVariable: false });
|
|
||||||
} else if (isJSExpression(newValue) && !isJSExpression(oldValue)) {
|
|
||||||
propConfig.useVariableChange.call(prop, { isUseVariable: true });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
editor?.on(GlobalEvent.Node.Prop.Change, (data) => {
|
|
||||||
bus.emit('node.prop.change', data);
|
|
||||||
|
|
||||||
triggerUseVariableChange(data);
|
|
||||||
});
|
|
||||||
|
|
||||||
export default bus;
|
|
||||||
@ -1,82 +0,0 @@
|
|||||||
@import '~@ali/ve-less-variables/index.less';
|
|
||||||
|
|
||||||
// 样式直接沿用之前的样式,优化了下命名
|
|
||||||
.instance-node-selector {
|
|
||||||
position: relative;
|
|
||||||
margin-right: 2px;
|
|
||||||
color: var(--color-icon-white, @title-bgcolor);
|
|
||||||
border-radius: @global-border-radius;
|
|
||||||
margin-right: 2px;
|
|
||||||
pointer-events: auto;
|
|
||||||
flex-grow: 0;
|
|
||||||
flex-shrink: 0;
|
|
||||||
|
|
||||||
svg {
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
margin-right: 5px;
|
|
||||||
flex-grow: 0;
|
|
||||||
flex-shrink: 0;
|
|
||||||
max-width: inherit;
|
|
||||||
path {
|
|
||||||
fill: var(--color-icon-white, @title-bgcolor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&-current {
|
|
||||||
background: var(--color-brand, @brand-color-1);
|
|
||||||
padding: 0 6px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
height: 20px;
|
|
||||||
cursor: pointer;
|
|
||||||
color: var(--color-icon-white, @title-bgcolor);
|
|
||||||
border-radius: 3px;
|
|
||||||
|
|
||||||
&-title {
|
|
||||||
padding-right: 6px;
|
|
||||||
color: var(--color-icon-white, @title-bgcolor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&-list {
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
opacity: 0;
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
&-node {
|
|
||||||
margin: 2px 0;
|
|
||||||
&-content {
|
|
||||||
padding-left: 6px;
|
|
||||||
background: #78869a;
|
|
||||||
display: inline-flex;
|
|
||||||
border-radius: 3px;
|
|
||||||
align-items: center;
|
|
||||||
height: 20px;
|
|
||||||
color: var(--color-icon-white, @title-bgcolor);
|
|
||||||
cursor: pointer;
|
|
||||||
overflow: visible;
|
|
||||||
}
|
|
||||||
&-title {
|
|
||||||
padding-right: 6px;
|
|
||||||
// margin-left: 5px;
|
|
||||||
color: var(--color-icon-white, @title-bgcolor);
|
|
||||||
cursor: pointer;
|
|
||||||
overflow: visible;
|
|
||||||
}
|
|
||||||
&:hover {
|
|
||||||
opacity: 0.8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
.instance-node-selector-current {
|
|
||||||
color: ar(--color-text-reverse, @white-alpha-2);
|
|
||||||
}
|
|
||||||
.instance-node-selector-popup {
|
|
||||||
visibility: visible;
|
|
||||||
opacity: 1;
|
|
||||||
transition: 0.2s all ease-in;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,113 +0,0 @@
|
|||||||
import { Overlay } from '@alifd/next';
|
|
||||||
import React from 'react';
|
|
||||||
import { Node, ParentalNode } from '@ali/lowcode-designer';
|
|
||||||
import { editorCabin } from '@ali/lowcode-engine';
|
|
||||||
import './index.less';
|
|
||||||
|
|
||||||
const { Popup } = Overlay;
|
|
||||||
const { Title } = editorCabin;
|
|
||||||
|
|
||||||
export interface IProps {
|
|
||||||
node: Node;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IState {
|
|
||||||
parentNodes: Node[];
|
|
||||||
}
|
|
||||||
|
|
||||||
type UnionNode = Node | ParentalNode | null;
|
|
||||||
|
|
||||||
export class InstanceNodeSelector extends React.Component<IProps, IState> {
|
|
||||||
state: IState = {
|
|
||||||
parentNodes: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
const parentNodes = this.getParentNodes(this.props.node);
|
|
||||||
this.setState({
|
|
||||||
parentNodes,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取节点的父级节点(最多获取5层)
|
|
||||||
getParentNodes = (node: Node) => {
|
|
||||||
const parentNodes = [];
|
|
||||||
let currentNode: UnionNode = node;
|
|
||||||
|
|
||||||
while (currentNode && parentNodes.length < 5) {
|
|
||||||
currentNode = currentNode.getParent();
|
|
||||||
if (currentNode) {
|
|
||||||
parentNodes.push(currentNode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return parentNodes;
|
|
||||||
};
|
|
||||||
|
|
||||||
onSelect = (node: Node) => () => {
|
|
||||||
if (node && typeof node.select === 'function') {
|
|
||||||
node.select();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
onMouseOver = (node: Node) => (_: any, flag = true) => {
|
|
||||||
if (node && typeof node.hover === 'function') {
|
|
||||||
node.hover(flag);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
onMouseOut = (node: Node) => (_: any, flag = false) => {
|
|
||||||
if (node && typeof node.hover === 'function') {
|
|
||||||
node.hover(flag);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
renderNodes = (node: Node) => {
|
|
||||||
const nodes = this.state.parentNodes || [];
|
|
||||||
const children = nodes.map((node, key) => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
key={key}
|
|
||||||
onClick={this.onSelect(node)}
|
|
||||||
onMouseEnter={this.onMouseOver(node)}
|
|
||||||
onMouseLeave={this.onMouseOut(node)}
|
|
||||||
className="instance-node-selector-node"
|
|
||||||
>
|
|
||||||
<div className="instance-node-selector-node-content">
|
|
||||||
<Title
|
|
||||||
className="instance-node-selector-node-title"
|
|
||||||
title={{
|
|
||||||
label: node.title,
|
|
||||||
icon: node.icon,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
return children;
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { node } = this.props;
|
|
||||||
return (
|
|
||||||
<div className="instance-node-selector">
|
|
||||||
<Popup
|
|
||||||
trigger={
|
|
||||||
<div className="instance-node-selector-current">
|
|
||||||
<Title
|
|
||||||
className="instance-node-selector-node-title"
|
|
||||||
title={{
|
|
||||||
label: node.title,
|
|
||||||
icon: node.icon,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
triggerType="hover"
|
|
||||||
>
|
|
||||||
<div className="instance-node-selector">{this.renderNodes(node)}</div>
|
|
||||||
</Popup>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,113 +0,0 @@
|
|||||||
import { assign } from 'lodash';
|
|
||||||
|
|
||||||
import { Component, ReactElement } from 'react';
|
|
||||||
import VisualManager from './base/visualManager';
|
|
||||||
import Prototype from './bundle/prototype';
|
|
||||||
import { VE_HOOKS } from './base/const';
|
|
||||||
import { setters } from '@ali/lowcode-engine';
|
|
||||||
|
|
||||||
// TODO: Env 本地引入后需要兼容方法 getDesignerLocale
|
|
||||||
// import Env from './env';
|
|
||||||
|
|
||||||
const { registerSetter } = setters;
|
|
||||||
// prop is Prop object in Designer
|
|
||||||
export type SetterProvider = (prop: any, componentPrototype: Prototype) => Component | ReactElement<any>;
|
|
||||||
|
|
||||||
export class VisualEngineContext {
|
|
||||||
private managerMap: { [name: string]: VisualManager } = {};
|
|
||||||
|
|
||||||
private moduleMap: { [name: string]: any } = {};
|
|
||||||
|
|
||||||
private pluginsMap: { [name: string]: any } = {};
|
|
||||||
|
|
||||||
use(pluginName: string, plugin: any) {
|
|
||||||
this.pluginsMap[pluginName || 'unknown'] = plugin;
|
|
||||||
if (pluginName === VE_HOOKS.VE_SETTING_FIELD_VARIABLE_SETTER) {
|
|
||||||
registerSetter('VariableSetter', {
|
|
||||||
component: plugin,
|
|
||||||
title: { type: 'i18n', 'zh-CN': '变量绑定', 'en-US': 'Variable Binding' },
|
|
||||||
// TODO: add logic below
|
|
||||||
// initialValue?: any | ((field: any) => any);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getPlugin(name: string) {
|
|
||||||
if (!name) {
|
|
||||||
name = 'default';
|
|
||||||
}
|
|
||||||
if (this.pluginsMap[name]) {
|
|
||||||
return this.pluginsMap[name];
|
|
||||||
} else if (this.moduleMap[name]) {
|
|
||||||
return this.moduleMap[name];
|
|
||||||
}
|
|
||||||
return this.getManager(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
registerManager(managerMap?: { [name: string]: VisualManager }): this;
|
|
||||||
|
|
||||||
registerManager(name: string, manager: VisualManager): this;
|
|
||||||
|
|
||||||
registerManager(name?: any, manager?: VisualManager): this {
|
|
||||||
if (name && typeof name === 'object') {
|
|
||||||
this.managerMap = assign(this.managerMap, name);
|
|
||||||
} else {
|
|
||||||
this.managerMap[name] = manager as VisualManager;
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
registerModule(moduleMap: { [name: string]: any }): this;
|
|
||||||
|
|
||||||
registerModule(name: string, module: any): this;
|
|
||||||
|
|
||||||
registerModule(name?: any, module?: any): this {
|
|
||||||
if (typeof name === 'object') {
|
|
||||||
this.moduleMap = Object.assign({}, this.moduleMap, name);
|
|
||||||
} else {
|
|
||||||
this.moduleMap[name] = module;
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
getManager(name: string): VisualManager {
|
|
||||||
return this.managerMap[name];
|
|
||||||
}
|
|
||||||
|
|
||||||
getModule(name: string): any {
|
|
||||||
return this.moduleMap[name];
|
|
||||||
}
|
|
||||||
|
|
||||||
// getDesignerLocale(): string {
|
|
||||||
// return Env.getLocale();
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builtin APIs
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* support dynamic setter replacement
|
|
||||||
*/
|
|
||||||
registerDynamicSetterProvider(setterProvider: SetterProvider) {
|
|
||||||
if (!setterProvider) {
|
|
||||||
console.error('ERROR: ', 'please set provider function.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.use('ve.plugin.setterProvider', setterProvider);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* support add treePane on the setting pane
|
|
||||||
* @param treePane see @ali/ve-tree-pane
|
|
||||||
* @param treeCore see @ali/ve-tree-pane
|
|
||||||
*/
|
|
||||||
registerTreePane(TreePane: Component, TreeCore: Component) {
|
|
||||||
if (TreePane && TreeCore) {
|
|
||||||
this.registerModule('TreePane', TreePane);
|
|
||||||
this.registerModule('TreeCore', TreeCore);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default new VisualEngineContext();
|
|
||||||
@ -1,59 +0,0 @@
|
|||||||
import { designer, designerCabin } from '@ali/lowcode-engine';
|
|
||||||
import { isPrototype } from './bundle/prototype';
|
|
||||||
|
|
||||||
const { DragObjectType, isNode, isDragNodeDataObject } = designerCabin;
|
|
||||||
const { dragon } = designer;
|
|
||||||
const DragEngine = {
|
|
||||||
from(shell: Element, boost: (e: MouseEvent) => any): any {
|
|
||||||
return dragon.from(shell, (e) => {
|
|
||||||
const r = boost(e);
|
|
||||||
if (!r) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (isPrototype(r)) {
|
|
||||||
return {
|
|
||||||
type: DragObjectType.NodeData,
|
|
||||||
data: {
|
|
||||||
componentName: r.getComponentName(),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
} else if (isNode(r)) {
|
|
||||||
return {
|
|
||||||
type: DragObjectType.Node,
|
|
||||||
nodes: [r],
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
type: DragObjectType.NodeData,
|
|
||||||
data: r,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onDragstart(func: (e: any, dragment: any) => any) {
|
|
||||||
return dragon.onDragstart((evt) => {
|
|
||||||
func(evt.originalEvent, evt.dragObject.nodes[0]);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onDrag(func: (e: any, dragment: any, location: any) => any) {
|
|
||||||
return dragon.onDrag((evt) => {
|
|
||||||
const loc = designer.currentDocument?.dropLocation;
|
|
||||||
func(evt.originalEvent, evt.dragObject.nodes[0], loc);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onDragend(func: (dragment: any, location: any, copy: any) => any) {
|
|
||||||
return dragon.onDragend(({ dragObject, copy }) => {
|
|
||||||
const loc = designer.currentDocument?.dropLocation;
|
|
||||||
if (isDragNodeDataObject(dragObject)) {
|
|
||||||
func(dragObject.data, loc, copy);
|
|
||||||
} else {
|
|
||||||
func(dragObject.nodes[0], loc, copy);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
inDragging() {
|
|
||||||
return dragon.dragging;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default DragEngine;
|
|
||||||
@ -1,95 +0,0 @@
|
|||||||
import { EventEmitter } from 'events';
|
|
||||||
import { ALI_SCHEMA_VERSION } from './base/const';
|
|
||||||
import { editorCabin } from '@ali/lowcode-engine';
|
|
||||||
|
|
||||||
const { obx } = editorCabin;
|
|
||||||
|
|
||||||
interface ILiteralObject {
|
|
||||||
[key: string]: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Env {
|
|
||||||
@obx.shallow envs: ILiteralObject = {};
|
|
||||||
|
|
||||||
private emitter: EventEmitter;
|
|
||||||
|
|
||||||
private featureMap: ILiteralObject;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.emitter = new EventEmitter();
|
|
||||||
this.emitter.setMaxListeners(0);
|
|
||||||
this.featureMap = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
get(name: string): any {
|
|
||||||
return this.getEnv(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
getEnv(name: string): any {
|
|
||||||
return this.envs[name];
|
|
||||||
}
|
|
||||||
|
|
||||||
set(name: string, value: any) {
|
|
||||||
return this.setEnv(name, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
setEnv(name: string, value: any) {
|
|
||||||
const orig = this.envs[name];
|
|
||||||
if (JSON.stringify(orig) === JSON.stringify(value)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.envs[name] = value;
|
|
||||||
this.emitter.emit('envchange', this.envs, name, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
setEnvMap(envs: ILiteralObject): void {
|
|
||||||
this.envs = Object.assign(this.envs, envs);
|
|
||||||
this.emitter.emit('envchange', this.envs);
|
|
||||||
}
|
|
||||||
|
|
||||||
getLocale(): string {
|
|
||||||
return this.getEnv('locale') || 'zh_CN';
|
|
||||||
}
|
|
||||||
|
|
||||||
setLocale(locale: string) {
|
|
||||||
this.setEnv('locale', locale);
|
|
||||||
}
|
|
||||||
|
|
||||||
setExpertMode(flag: string) {
|
|
||||||
this.setEnv('expertMode', !!flag);
|
|
||||||
}
|
|
||||||
|
|
||||||
isExpertMode() {
|
|
||||||
return !!this.getEnv('expertMode');
|
|
||||||
}
|
|
||||||
|
|
||||||
getSupportFeatures() {
|
|
||||||
return Object.assign({}, this.featureMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
setSupportFeatures(features: ILiteralObject) {
|
|
||||||
this.featureMap = Object.assign({}, this.featureMap, features);
|
|
||||||
}
|
|
||||||
|
|
||||||
supports(name = 'supports') {
|
|
||||||
return !!this.featureMap[name];
|
|
||||||
}
|
|
||||||
|
|
||||||
onEnvChange(func: (envs: ILiteralObject, name: string, value: any) => any) {
|
|
||||||
this.emitter.on('envchange', func);
|
|
||||||
return () => {
|
|
||||||
this.emitter.removeListener('envchange', func);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
clear() {
|
|
||||||
this.envs = {};
|
|
||||||
this.featureMap = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
getAliSchemaVersion() {
|
|
||||||
return ALI_SCHEMA_VERSION;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default new Env();
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
import { Node } from '@ali/lowcode-designer';
|
|
||||||
import { designer } from '@ali/lowcode-engine';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
select: (node: Node) => {
|
|
||||||
if (!node) {
|
|
||||||
return designer.currentSelection?.clear();
|
|
||||||
}
|
|
||||||
designer.currentSelection?.select(node.id);
|
|
||||||
},
|
|
||||||
getSelected: () => {
|
|
||||||
const nodes = designer.currentSelection?.getNodes();
|
|
||||||
return nodes?.[0];
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* TODO dirty fix
|
|
||||||
*/
|
|
||||||
onIntoView(func: (node: any, insertion: any) => any) {
|
|
||||||
// this.emitter.on('intoview', func);
|
|
||||||
return () => {
|
|
||||||
// this.emitter.removeListener('intoview', func);
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@ -1,151 +0,0 @@
|
|||||||
import classnames from 'classnames';
|
|
||||||
import * as React from 'react';
|
|
||||||
import { Component } from 'react';
|
|
||||||
import InlineTip from './inlinetip';
|
|
||||||
import { isPlainObject } from '@ali/lowcode-utils';
|
|
||||||
|
|
||||||
interface IHelpTip {
|
|
||||||
url?: string;
|
|
||||||
content?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
function splitWord(title: string): JSX.Element[] {
|
|
||||||
return (title || '').split('').map((w, i) => <b key={`word${i}`} className="engine-word">{w}</b>);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getFieldTitle(title: string, tip: IHelpTip, compact?: boolean, propName?: string): JSX.Element {
|
|
||||||
const className = classnames('engine-field-title', { 've-compact': compact });
|
|
||||||
let titleContent = null;
|
|
||||||
|
|
||||||
if (!compact && typeof title === 'string') {
|
|
||||||
titleContent = splitWord(title);
|
|
||||||
}
|
|
||||||
|
|
||||||
let tipUrl = null;
|
|
||||||
let tipContent = null;
|
|
||||||
|
|
||||||
tipContent = (
|
|
||||||
<div>
|
|
||||||
<div>属性:{propName}</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
if (isPlainObject(tip)) {
|
|
||||||
tipUrl = tip.url;
|
|
||||||
tipContent = (
|
|
||||||
<div>
|
|
||||||
<div>属性:{propName}</div>
|
|
||||||
<div>说明:{tip.content}</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
} else if (tip) {
|
|
||||||
tipContent = (
|
|
||||||
<div>
|
|
||||||
<div>属性:{propName}</div>
|
|
||||||
<div>说明:{tip}</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<a
|
|
||||||
className={className}
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
href={tipUrl!}
|
|
||||||
>
|
|
||||||
{titleContent || (typeof title === 'object' ? '' : title)}
|
|
||||||
<InlineTip position="top">{tipContent}</InlineTip>
|
|
||||||
</a>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IVEFieldProps {
|
|
||||||
prop: any;
|
|
||||||
children: JSX.Element | string;
|
|
||||||
title?: string;
|
|
||||||
tip?: any;
|
|
||||||
propName?: string;
|
|
||||||
className?: string;
|
|
||||||
compact?: boolean;
|
|
||||||
stageName?: string;
|
|
||||||
/**
|
|
||||||
* render the top-header by jsx
|
|
||||||
*/
|
|
||||||
headDIY?: boolean;
|
|
||||||
|
|
||||||
isSupportVariable?: boolean;
|
|
||||||
isSupportMultiSetter?: boolean;
|
|
||||||
isUseVariable?: boolean;
|
|
||||||
|
|
||||||
isGroup?: boolean;
|
|
||||||
isExpand?: boolean;
|
|
||||||
|
|
||||||
toggleExpand?: () => any;
|
|
||||||
onExpandChange?: (fn: () => any) => any;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IVEFieldState {
|
|
||||||
hasError?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class VEField extends Component<IVEFieldProps, IVEFieldState> {
|
|
||||||
public static displayName = 'VEField';
|
|
||||||
|
|
||||||
public readonly props: IVEFieldProps;
|
|
||||||
|
|
||||||
public classNames: string[] = [];
|
|
||||||
|
|
||||||
public state: IVEFieldState = {
|
|
||||||
hasError: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
public componentDidCatch(error: Error, info: React.ErrorInfo) {
|
|
||||||
console.error(error);
|
|
||||||
console.warn(info.componentStack);
|
|
||||||
}
|
|
||||||
|
|
||||||
public renderHead(): JSX.Element | JSX.Element[] | null {
|
|
||||||
const { title, tip, compact, propName } = this.props;
|
|
||||||
return getFieldTitle(title!, tip, compact, propName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public renderBody(): JSX.Element | string {
|
|
||||||
return this.props.children;
|
|
||||||
}
|
|
||||||
|
|
||||||
public renderFoot(): any {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public render(): JSX.Element {
|
|
||||||
const { stageName, headDIY } = this.props;
|
|
||||||
const classNameList = classnames(...this.classNames, this.props.className);
|
|
||||||
const fieldProps: any = {};
|
|
||||||
|
|
||||||
if (stageName) {
|
|
||||||
// 为 stage 切换奠定基础
|
|
||||||
fieldProps['data-stage-target'] = this.props.stageName;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.state.hasError) {
|
|
||||||
return (
|
|
||||||
<div>Field render error, please open console to find out.</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const headContent = headDIY ? this.renderHead()
|
|
||||||
: <div className="engine-field-head">{this.renderHead()}</div>;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={classNameList} {...fieldProps}>
|
|
||||||
{headContent}
|
|
||||||
<div className="engine-field-body">
|
|
||||||
{this.renderBody()}
|
|
||||||
</div>
|
|
||||||
<div className="engine-field-foot">
|
|
||||||
{this.renderFoot()}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,272 +0,0 @@
|
|||||||
@import '~@ali/ve-less-variables/index.less';
|
|
||||||
|
|
||||||
.engine-setting-field {
|
|
||||||
white-space: nowrap;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
&:after, &:before {
|
|
||||||
content: " ";
|
|
||||||
display: table;
|
|
||||||
}
|
|
||||||
&:after {
|
|
||||||
clear: both;
|
|
||||||
}
|
|
||||||
|
|
||||||
.engine-field-title {
|
|
||||||
font-size: 12px;
|
|
||||||
font-family: @font-family;
|
|
||||||
line-height: 1em;
|
|
||||||
user-select: none;
|
|
||||||
color: var(--color-text, @dark-alpha-3);
|
|
||||||
width: fit-content;
|
|
||||||
white-space: initial;
|
|
||||||
word-break: break-word;
|
|
||||||
&::first-letter {
|
|
||||||
text-transform: capitalize;
|
|
||||||
}
|
|
||||||
|
|
||||||
.engine-word {
|
|
||||||
flex: 1;
|
|
||||||
text-align: center;
|
|
||||||
font-weight: normal;
|
|
||||||
&:first-child {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
&:last-of-type {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
&:only-of-type {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
a.engine-field-title {
|
|
||||||
border-bottom: 1px dashed var(--color-line-normal, @normal-alpha-7);
|
|
||||||
text-decoration: none;
|
|
||||||
padding-bottom: 2px;
|
|
||||||
&:hover {
|
|
||||||
cursor: help;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.engine-field-variable-wrapper {
|
|
||||||
margin-left: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.engine-field-variable {
|
|
||||||
cursor: pointer;
|
|
||||||
opacity: 0.6;
|
|
||||||
&.engine-active {
|
|
||||||
opacity: 1;
|
|
||||||
color: var(--color-brand, @brand-color-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.engine-field-head {
|
|
||||||
padding-left: 10px;
|
|
||||||
height: 32px;
|
|
||||||
background: var(--color-block-background-shallow, @normal-alpha-8);
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
font-weight: 500;
|
|
||||||
border-top: 1px solid var(--color-line-normal, @normal-alpha-7);
|
|
||||||
border-bottom: 1px solid var(--color-line-normal, @normal-alpha-7);
|
|
||||||
color: var(--color-title, @dark-alpha-2);
|
|
||||||
>.engine-icontip {
|
|
||||||
margin-left: 2px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.engine-field-body {
|
|
||||||
min-height: 20px;
|
|
||||||
margin: 6px 0;
|
|
||||||
|
|
||||||
&:after, &:before {
|
|
||||||
content: " ";
|
|
||||||
display: table;
|
|
||||||
}
|
|
||||||
&:after {
|
|
||||||
clear: both;
|
|
||||||
}
|
|
||||||
|
|
||||||
.engine-field-head {
|
|
||||||
height: 28px;
|
|
||||||
border: none;
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.engine-plain-field {
|
|
||||||
>.engine-field-variable {
|
|
||||||
position: absolute;
|
|
||||||
right: 5px;
|
|
||||||
top: 8px;
|
|
||||||
}
|
|
||||||
&:hover {
|
|
||||||
>.engine-field-variable {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.engine-entry-field {
|
|
||||||
cursor: pointer;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
height: 32px;
|
|
||||||
padding-left: 10px;
|
|
||||||
font-weight: 500;
|
|
||||||
border-top: 1px solid var(--color-line-normal, @normal-alpha-7);
|
|
||||||
border-bottom: 1px solid var(--color-line-normal, @normal-alpha-7);
|
|
||||||
background: var(--color-block-background-shallow, @normal-alpha-8);
|
|
||||||
margin-bottom: 6px;
|
|
||||||
|
|
||||||
>.engine-field-title {
|
|
||||||
letter-spacing: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
>.engine-icontip {
|
|
||||||
margin-left: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
>.engine-field-arrow {
|
|
||||||
position: absolute;
|
|
||||||
right: 5px;
|
|
||||||
top: 50%;
|
|
||||||
transform: translateY(-50%) rotate(-90deg);
|
|
||||||
opacity: 0.4;
|
|
||||||
}
|
|
||||||
&:hover {
|
|
||||||
>.engine-field-arrow {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.engine-popup-field {
|
|
||||||
cursor: pointer;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
height: 32px;
|
|
||||||
padding-left: 10px;
|
|
||||||
background: var(--color-block-background-shallow, @normal-alpha-8);
|
|
||||||
margin-bottom: 1px;
|
|
||||||
|
|
||||||
>.engine-field-title {
|
|
||||||
letter-spacing: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
>.engine-icontip {
|
|
||||||
margin-left: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
>.engine-field-icon {
|
|
||||||
position: absolute;
|
|
||||||
right: 5px;
|
|
||||||
top: 50%;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
opacity: 0.6;
|
|
||||||
}
|
|
||||||
&:hover {
|
|
||||||
>.engine-field-icon {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.engine-block-field {
|
|
||||||
>.engine-field-head {
|
|
||||||
> .engine-field-title {
|
|
||||||
letter-spacing: 1px;
|
|
||||||
}
|
|
||||||
>.engine-field-variable {
|
|
||||||
margin-left: 2px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
>.engine-field-body {
|
|
||||||
margin: 6px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.engine-inline-field {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
margin: 10px;
|
|
||||||
>.engine-field-head {
|
|
||||||
display: inline-flex;
|
|
||||||
background: none;
|
|
||||||
padding: 0;
|
|
||||||
border: none;
|
|
||||||
|
|
||||||
>.engine-field-title {
|
|
||||||
display: inline-flex;
|
|
||||||
width: 50px;
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
>.engine-field-body {
|
|
||||||
width: 100%;
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: flex-start;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
flex: 1;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
>.engine-field-variable {
|
|
||||||
margin-left: 2px;
|
|
||||||
}
|
|
||||||
&:hover {
|
|
||||||
>.engine-field-variable {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.engine-accordion-field {
|
|
||||||
>.engine-field-head {
|
|
||||||
position: relative;
|
|
||||||
cursor: pointer;
|
|
||||||
>.engine-field-title {
|
|
||||||
letter-spacing: 1px;
|
|
||||||
}
|
|
||||||
>.engine-field-arrow {
|
|
||||||
transform: rotate(180deg);
|
|
||||||
position: absolute;
|
|
||||||
right: 7px;
|
|
||||||
top: 7px;
|
|
||||||
transition: transform 0.1s ease;
|
|
||||||
opacity: 0.6;
|
|
||||||
}
|
|
||||||
>.engine-field-variable {
|
|
||||||
margin-left: 2px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&.engine-collapsed {
|
|
||||||
>.engine-field-head {
|
|
||||||
margin-bottom: 6px;
|
|
||||||
}
|
|
||||||
>.engine-field-head > .engine-field-arrow {
|
|
||||||
transform: rotate(0);
|
|
||||||
}
|
|
||||||
>.engine-field-body {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
>.engine-field-body {
|
|
||||||
margin: 6px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.engine-block-field,.engine-accordion-field,.engine-entry-field {
|
|
||||||
.engine-input-control {
|
|
||||||
margin: 10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.engine-field-tip-icon {
|
|
||||||
margin-left: 2px;
|
|
||||||
}
|
|
||||||
@ -1,379 +0,0 @@
|
|||||||
import Icons from '@ali/ve-icons';
|
|
||||||
import classNames from 'classnames';
|
|
||||||
import { Component } from 'react';
|
|
||||||
import { testType } from '@ali/ve-utils';
|
|
||||||
import VEField, { IVEFieldProps } from './field';
|
|
||||||
import { SettingField } from './setting-field';
|
|
||||||
import VariableSwitcher from './variable-switcher';
|
|
||||||
import popups from '@ali/ve-popups';
|
|
||||||
|
|
||||||
import './fields.less';
|
|
||||||
|
|
||||||
interface IHelpTip {
|
|
||||||
url?: string;
|
|
||||||
content?: string | JSX.Element;
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderTip(tip: IHelpTip, prop?: { propName?: string }) {
|
|
||||||
const propName = prop && prop.propName;
|
|
||||||
if (!tip) {
|
|
||||||
return (
|
|
||||||
<Icons.Tip position="top" key="icon" className="engine-field-tip-icon">
|
|
||||||
<div>
|
|
||||||
<div>{propName}</div>
|
|
||||||
</div>
|
|
||||||
</Icons.Tip>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (testType(tip) === 'object') {
|
|
||||||
return (
|
|
||||||
<Icons.Tip position="top" url={tip.url} key="icon-tip" className="engine-field-tip-icon">
|
|
||||||
<div>
|
|
||||||
<div>属性:{propName}</div>
|
|
||||||
<div>说明:{tip.content}</div>
|
|
||||||
</div>
|
|
||||||
</Icons.Tip>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<Icons.Tip position="top" key="icon" className="engine-field-tip-icon">
|
|
||||||
<div>
|
|
||||||
<div>属性:{propName}</div>
|
|
||||||
<div>说明:{tip}</div>
|
|
||||||
</div>
|
|
||||||
</Icons.Tip>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export class PlainField extends VEField {
|
|
||||||
public static defaultProps = {
|
|
||||||
headDIY: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
public static displayName = 'PlainField';
|
|
||||||
|
|
||||||
public renderHead(): null {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class InlineField extends VEField {
|
|
||||||
public static displayName = 'InlineField';
|
|
||||||
|
|
||||||
constructor(props: any) {
|
|
||||||
super(props);
|
|
||||||
this.classNames = ['engine-setting-field', 'engine-inline-field'];
|
|
||||||
}
|
|
||||||
|
|
||||||
public renderFoot() {
|
|
||||||
return (
|
|
||||||
<div className="engine-field-variable-wrapper">
|
|
||||||
<VariableSwitcher {...this.props} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class BlockField extends VEField {
|
|
||||||
public static displayName = 'BlockField';
|
|
||||||
|
|
||||||
constructor(props: IVEFieldProps) {
|
|
||||||
super(props);
|
|
||||||
this.classNames = ['engine-setting-field', 'engine-block-field', props.isGroup ? 'engine-group-field' : ''];
|
|
||||||
}
|
|
||||||
|
|
||||||
public renderHead() {
|
|
||||||
const { title, tip, propName } = this.props;
|
|
||||||
return [
|
|
||||||
<span className="engine-field-title" key={title}>
|
|
||||||
{title}
|
|
||||||
</span>,
|
|
||||||
renderTip(tip, { propName }),
|
|
||||||
<VariableSwitcher {...this.props} />,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class AccordionField extends VEField {
|
|
||||||
public readonly props: IVEFieldProps;
|
|
||||||
|
|
||||||
private willDetach?: () => any;
|
|
||||||
|
|
||||||
constructor(props: IVEFieldProps) {
|
|
||||||
super(props);
|
|
||||||
this._generateClassNames(props);
|
|
||||||
if (props.onExpandChange) {
|
|
||||||
this.willDetach = props.onExpandChange(() => this.forceUpdate());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public componentWillReceiveProps(nextProps: IVEFieldProps) {
|
|
||||||
this.classNames = this._generateClassNames(nextProps);
|
|
||||||
}
|
|
||||||
|
|
||||||
public componentWillUnmount() {
|
|
||||||
if (this.willDetach) {
|
|
||||||
this.willDetach();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public renderHead() {
|
|
||||||
const { title, tip, toggleExpand, propName } = this.props;
|
|
||||||
return (
|
|
||||||
<div className="engine-field-head" onClick={() => toggleExpand && toggleExpand()}>
|
|
||||||
<Icons name="arrow" className="engine-field-arrow" size="12px" />
|
|
||||||
<span className="engine-field-title">{title}</span>
|
|
||||||
{renderTip(tip, { propName })}
|
|
||||||
{<VariableSwitcher {...this.props} />}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _generateClassNames(props: IVEFieldProps) {
|
|
||||||
this.classNames = [
|
|
||||||
'engine-setting-field',
|
|
||||||
'engine-accordion-field',
|
|
||||||
props.isGroup ? 'engine-group-field' : '',
|
|
||||||
!props.isExpand ? 'engine-collapsed' : '',
|
|
||||||
];
|
|
||||||
return this.classNames;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class EntryField extends VEField {
|
|
||||||
constructor(props: any) {
|
|
||||||
super(props);
|
|
||||||
this.classNames = ['engine-setting-field', 'engine-entry-field'];
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
const { propName, stageName, tip, title } = this.props;
|
|
||||||
const classNameList = classNames(...this.classNames, this.props.className);
|
|
||||||
const fieldProps: any = {};
|
|
||||||
|
|
||||||
if (stageName) {
|
|
||||||
// 为 stage 切换奠定基础
|
|
||||||
fieldProps['data-stage-target'] = this.props.stageName;
|
|
||||||
}
|
|
||||||
|
|
||||||
const innerElements = [
|
|
||||||
<span className="engine-field-title" key="field-title">
|
|
||||||
{title}
|
|
||||||
</span>,
|
|
||||||
renderTip(tip, { propName }),
|
|
||||||
<Icons name="arrow" className="engine-field-arrow" size="12px" key="engine-field-arrow-icon" />,
|
|
||||||
];
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={classNameList} {...fieldProps}>
|
|
||||||
{innerElements}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class PopupField extends VEField {
|
|
||||||
constructor(props: any) {
|
|
||||||
super(props);
|
|
||||||
this.classNames = ['engine-setting-field', 'engine-popup-field'];
|
|
||||||
}
|
|
||||||
|
|
||||||
public renderBody() {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
const { propName, stageName, tip, title } = this.props;
|
|
||||||
const classNameList = classNames(...this.classNames, this.props.className);
|
|
||||||
const fieldProps: any = {};
|
|
||||||
|
|
||||||
if (stageName) {
|
|
||||||
// 为 stage 切换奠定基础
|
|
||||||
fieldProps['data-stage-target'] = this.props.stageName;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={classNameList}
|
|
||||||
onClick={(e) => popups.popup({
|
|
||||||
cancelOnBlur: true,
|
|
||||||
content: this.props.children,
|
|
||||||
position: 'left bottom',
|
|
||||||
showClose: true,
|
|
||||||
sizeFixed: true,
|
|
||||||
target: e.currentTarget,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<span className="engine-field-title">{title}</span>
|
|
||||||
{renderTip(tip, { propName })}
|
|
||||||
<VariableSwitcher {...this.props} />
|
|
||||||
<Icons name="popup" className="engine-field-icon" size="medium" />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class CaptionField extends VEField {
|
|
||||||
constructor(props: IVEFieldProps) {
|
|
||||||
super(props);
|
|
||||||
this.classNames = ['engine-setting-field', 'engine-caption-field'];
|
|
||||||
}
|
|
||||||
|
|
||||||
public renderHead() {
|
|
||||||
const { title, tip, propName } = this.props;
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<span className="engine-field-title">{title}</span>
|
|
||||||
{renderTip(tip, { propName })}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Stage extends Component {
|
|
||||||
public readonly props: {
|
|
||||||
key: any;
|
|
||||||
stage: any;
|
|
||||||
current?: boolean;
|
|
||||||
direction?: any;
|
|
||||||
};
|
|
||||||
|
|
||||||
public stage: any;
|
|
||||||
|
|
||||||
public additionClassName: string;
|
|
||||||
|
|
||||||
public shell: Element | null = null;
|
|
||||||
|
|
||||||
private willDetach: () => any;
|
|
||||||
|
|
||||||
public componentWillMount() {
|
|
||||||
this.stage = this.props.stage;
|
|
||||||
if (this.stage.onCurrentTabChange) {
|
|
||||||
this.willDetach = this.stage.onCurrentTabChange(() => this.forceUpdate());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public componentDidMount() {
|
|
||||||
this.doSkate();
|
|
||||||
}
|
|
||||||
|
|
||||||
public componentWillReceiveProps(props: any) {
|
|
||||||
if (props.stage !== this.stage) {
|
|
||||||
this.stage = props.stage;
|
|
||||||
if (this.willDetach) {
|
|
||||||
this.willDetach();
|
|
||||||
}
|
|
||||||
if (this.stage.onCurrentTabChange) {
|
|
||||||
this.willDetach = this.stage.onCurrentTabChange(() => this.forceUpdate());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public componentDidUpdate() {
|
|
||||||
this.doSkate();
|
|
||||||
}
|
|
||||||
|
|
||||||
public componentWillUnmount() {
|
|
||||||
if (this.willDetach) {
|
|
||||||
this.willDetach();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public doSkate() {
|
|
||||||
if (this.additionClassName) {
|
|
||||||
setTimeout(() => {
|
|
||||||
const elem = this.shell;
|
|
||||||
if (elem && elem.classList) {
|
|
||||||
if (this.props.current) {
|
|
||||||
elem.classList.remove(this.additionClassName);
|
|
||||||
} else {
|
|
||||||
elem.classList.add(this.additionClassName);
|
|
||||||
}
|
|
||||||
this.additionClassName = '';
|
|
||||||
}
|
|
||||||
}, 10);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
const { stage } = this;
|
|
||||||
let content = null;
|
|
||||||
let tabs = null;
|
|
||||||
|
|
||||||
let className = 'engine-settings-stage';
|
|
||||||
|
|
||||||
if (stage.getTabs) {
|
|
||||||
const selected = stage.getNode();
|
|
||||||
// stat for cache
|
|
||||||
stage.stat();
|
|
||||||
const currentTab = stage.getCurrentTab();
|
|
||||||
|
|
||||||
if (stage.hasTabs()) {
|
|
||||||
className += ' engine-has-tabs';
|
|
||||||
tabs = (
|
|
||||||
<div className="engine-settings-tabs">
|
|
||||||
{stage.getTabs().map((tab: any) => (
|
|
||||||
<div
|
|
||||||
key={tab.getId()}
|
|
||||||
className={`engine-settings-tab${tab === currentTab ? ' engine-active' : ''}`}
|
|
||||||
onClick={() => stage.setCurrentTab(tab)}
|
|
||||||
>
|
|
||||||
{tab.getTitle()}
|
|
||||||
{renderTip(tab.getTip())}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentTab) {
|
|
||||||
if (currentTab.getVisibleItems) {
|
|
||||||
content = currentTab
|
|
||||||
.getVisibleItems()
|
|
||||||
.map((item: any) => <SettingField key={item.getId()} selected={selected} prop={item} />);
|
|
||||||
} else if (currentTab.getSetter) {
|
|
||||||
content = (
|
|
||||||
<SettingField key={currentTab.getId()} selected={selected} prop={currentTab} forceDisplay="plain" />
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
content = stage.getContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.props.current) {
|
|
||||||
if (this.props.direction) {
|
|
||||||
this.additionClassName = `engine-stagein-${this.props.direction}`;
|
|
||||||
className += ` ${this.additionClassName}`;
|
|
||||||
}
|
|
||||||
} else if (this.props.direction) {
|
|
||||||
this.additionClassName = `engine-stageout-${this.props.direction}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
let stageBacker = null;
|
|
||||||
if (stage.hasBack()) {
|
|
||||||
className += ' engine-has-backer';
|
|
||||||
stageBacker = (
|
|
||||||
<div className="engine-settings-stagebacker" data-stage-target="stageback">
|
|
||||||
<Icons name="arrow" className="engine-field-arrow" size="12px" />
|
|
||||||
<span className="engine-field-title">{stage.getTitle()}</span>
|
|
||||||
{renderTip(stage.getTip())}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
ref={(ref) => {
|
|
||||||
this.shell = ref;
|
|
||||||
}}
|
|
||||||
className={className}
|
|
||||||
>
|
|
||||||
{stageBacker}
|
|
||||||
{tabs}
|
|
||||||
<div className="engine-stage-content">{content}</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
export * from './setting-field';
|
|
||||||
export * from './fields';
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
import { Component } from 'react';
|
|
||||||
|
|
||||||
export interface InlineTipProps {
|
|
||||||
position: string;
|
|
||||||
theme?: 'green' | 'black';
|
|
||||||
children: React.ReactNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class InlineTip extends Component<InlineTipProps> {
|
|
||||||
public static displayName = 'InlineTip';
|
|
||||||
|
|
||||||
public static defaultProps = {
|
|
||||||
position: 'auto',
|
|
||||||
theme: 'black',
|
|
||||||
};
|
|
||||||
|
|
||||||
public render(): React.ReactNode {
|
|
||||||
const { position, theme, children } = this.props;
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
style={{ display: 'none' }}
|
|
||||||
data-role="tip"
|
|
||||||
data-position={position}
|
|
||||||
data-theme={theme}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,189 +0,0 @@
|
|||||||
import VariableSetter from './variable-setter';
|
|
||||||
import context from '../context';
|
|
||||||
import { VE_HOOKS } from '../base/const';
|
|
||||||
import {
|
|
||||||
AccordionField,
|
|
||||||
BlockField,
|
|
||||||
EntryField,
|
|
||||||
InlineField,
|
|
||||||
PlainField,
|
|
||||||
PopupField,
|
|
||||||
} from './fields';
|
|
||||||
|
|
||||||
import { ComponentClass, Component, isValidElement, createElement } from 'react';
|
|
||||||
import { editorCabin, setters } from '@ali/lowcode-engine';
|
|
||||||
|
|
||||||
const { getSetter } = setters;
|
|
||||||
const { createSetterContent } = editorCabin;
|
|
||||||
|
|
||||||
function isReactClass(obj: any): obj is ComponentClass<any> {
|
|
||||||
return (
|
|
||||||
obj &&
|
|
||||||
obj.prototype &&
|
|
||||||
(obj.prototype.isReactComponent || obj.prototype instanceof Component)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IExtraProps {
|
|
||||||
stageName?: string;
|
|
||||||
isGroup?: boolean;
|
|
||||||
isExpand?: boolean;
|
|
||||||
propName?: string;
|
|
||||||
toggleExpand?: () => any;
|
|
||||||
onExpandChange?: () => any;
|
|
||||||
}
|
|
||||||
|
|
||||||
const FIELD_TYPE_MAP: any = {
|
|
||||||
accordion: AccordionField,
|
|
||||||
block: BlockField,
|
|
||||||
entry: EntryField,
|
|
||||||
inline: InlineField,
|
|
||||||
plain: PlainField,
|
|
||||||
popup: PopupField,
|
|
||||||
tab: AccordionField,
|
|
||||||
};
|
|
||||||
|
|
||||||
export class SettingField extends Component {
|
|
||||||
public readonly props: {
|
|
||||||
prop: any;
|
|
||||||
selected?: boolean;
|
|
||||||
forceDisplay?: string;
|
|
||||||
className?: string;
|
|
||||||
children?: JSX.Element | string;
|
|
||||||
compact?: boolean;
|
|
||||||
key?: string;
|
|
||||||
addonProps?: object;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* VariableSetter placeholder
|
|
||||||
*/
|
|
||||||
public variableSetter: any;
|
|
||||||
|
|
||||||
constructor(props: any) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.variableSetter = getSetter('VariableSetter')?.component || VariableSetter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
const { prop, selected, addonProps } = this.props;
|
|
||||||
const display = this.props.forceDisplay || prop.getDisplay();
|
|
||||||
|
|
||||||
if (display === 'none') {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 标准的属性,即每一个 Field 在 VE 下都拥有的属性
|
|
||||||
const standardProps = {
|
|
||||||
className: this.props.className,
|
|
||||||
compact: this.props.compact,
|
|
||||||
|
|
||||||
isSupportMultiSetter: this.supportMultiSetter(),
|
|
||||||
isSupportVariable: prop.isSupportVariable(),
|
|
||||||
isUseVariable: prop.isUseVariable(),
|
|
||||||
prop,
|
|
||||||
setUseVariable: () => prop.setUseVariable(!prop.isUseVariable()),
|
|
||||||
tip: prop.getTip(),
|
|
||||||
title: prop.getTitle(),
|
|
||||||
};
|
|
||||||
|
|
||||||
// 部分 Field 所需要的额外 fieldProps
|
|
||||||
const extraProps = {};
|
|
||||||
const ctx = context;
|
|
||||||
const plugin = ctx.getPlugin(VE_HOOKS.VE_SETTING_FIELD_PROVIDER);
|
|
||||||
let Field;
|
|
||||||
if (typeof plugin === 'function') {
|
|
||||||
Field = plugin(display, FIELD_TYPE_MAP, prop);
|
|
||||||
}
|
|
||||||
if (!Field) {
|
|
||||||
Field = FIELD_TYPE_MAP[display] || PlainField;
|
|
||||||
}
|
|
||||||
this._prepareProps(display, extraProps);
|
|
||||||
|
|
||||||
if (display === 'entry') {
|
|
||||||
return <Field {...{ ...standardProps, ...extraProps }} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
let setter;
|
|
||||||
const props: any = {
|
|
||||||
prop,
|
|
||||||
selected,
|
|
||||||
};
|
|
||||||
const fieldProps = { ...standardProps, ...extraProps };
|
|
||||||
|
|
||||||
if (prop.isUseVariable() && !this.variableSetter.isPopup) {
|
|
||||||
props.placeholder = '请输入表达式: ${var}';
|
|
||||||
props.key = `${prop.getId()}-variable`;
|
|
||||||
setter = createElement(this.variableSetter, props);
|
|
||||||
return <Field {...fieldProps}>{setter}</Field>;
|
|
||||||
}
|
|
||||||
|
|
||||||
// for composited prop
|
|
||||||
if (prop.getVisibleItems) {
|
|
||||||
setter = prop
|
|
||||||
.getVisibleItems()
|
|
||||||
.map((item: any) => (
|
|
||||||
<SettingField {...{ key: item.getId(), prop: item, selected }} />
|
|
||||||
));
|
|
||||||
return <Field {...fieldProps}>{setter}</Field>;
|
|
||||||
}
|
|
||||||
|
|
||||||
setter = prop.getSetter();
|
|
||||||
if (
|
|
||||||
typeof setter === 'object' &&
|
|
||||||
'componentName' in setter &&
|
|
||||||
!(isValidElement(setter) || isReactClass(setter))
|
|
||||||
) {
|
|
||||||
const { componentName: setterType, props: setterProps } = setter as any;
|
|
||||||
setter = createSetterContent(setterType, {
|
|
||||||
...addonProps,
|
|
||||||
...setterProps,
|
|
||||||
...props,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
setter = createSetterContent(setter, {
|
|
||||||
...addonProps,
|
|
||||||
...props,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return <Field {...fieldProps}>{setter}</Field>;
|
|
||||||
}
|
|
||||||
|
|
||||||
private supportMultiSetter() {
|
|
||||||
const { prop } = this.props;
|
|
||||||
const setter = prop && prop.getConfig && prop.getConfig('setter');
|
|
||||||
return prop.isSupportVariable() || Array.isArray(setter);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _prepareProps(displayType: string, extraProps: IExtraProps): void {
|
|
||||||
const { prop } = this.props;
|
|
||||||
extraProps.propName = prop.isGroup()
|
|
||||||
? '组合属性,无属性名称'
|
|
||||||
: prop.getName();
|
|
||||||
switch (displayType) {
|
|
||||||
case 'title':
|
|
||||||
break;
|
|
||||||
case 'block':
|
|
||||||
Object.assign(extraProps, { isGroup: prop.isGroup() });
|
|
||||||
break;
|
|
||||||
case 'accordion':
|
|
||||||
Object.assign(extraProps, {
|
|
||||||
headDIY: true,
|
|
||||||
isExpand: prop.isExpand(),
|
|
||||||
isGroup: prop.isGroup(),
|
|
||||||
onExpandChange: () => prop.onExpandChange(() => this.forceUpdate()),
|
|
||||||
toggleExpand: () => {
|
|
||||||
prop.toggleExpand();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case 'entry':
|
|
||||||
Object.assign(extraProps, { stageName: prop.getName() });
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,43 +0,0 @@
|
|||||||
@import '~@ali/ve-less-variables/index.less';
|
|
||||||
|
|
||||||
.engine-input-control {
|
|
||||||
box-sizing: border-box;
|
|
||||||
font-size: 12px;
|
|
||||||
font-family: Consolas, "Courier New", Courier, FreeMono, monospace;
|
|
||||||
color: var(--color-text, @dark-alpha-3);
|
|
||||||
background: var(--color-field-background, @white-alpha-1);
|
|
||||||
border: 1px solid var(--color-field-border, @normal-alpha-5);
|
|
||||||
flex: 1;
|
|
||||||
border-radius: @global-border-radius;
|
|
||||||
max-height: 200px;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
border-color: var(--color-field-border-hover, @normal-alpha-4);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.engine-focused {
|
|
||||||
border-color: var(--color-field-border-active, @normal-alpha-3);
|
|
||||||
}
|
|
||||||
|
|
||||||
textarea {
|
|
||||||
resize: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
>.engine-input {
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding: 6px;
|
|
||||||
display: block;
|
|
||||||
font-size: 12px;
|
|
||||||
line-height: 16px;
|
|
||||||
color: var(--color-text, @dark-alpha-3);
|
|
||||||
width: 100%;
|
|
||||||
border: 0;
|
|
||||||
margin: 0;
|
|
||||||
background: transparent;
|
|
||||||
outline: none;
|
|
||||||
|
|
||||||
&::-webkit-input-placeholder {
|
|
||||||
color: var(--color-field-placeholder, @normal-alpha-5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,86 +0,0 @@
|
|||||||
import './variable-setter.less';
|
|
||||||
import { Component } from 'react';
|
|
||||||
|
|
||||||
class Input extends Component {
|
|
||||||
public props: {
|
|
||||||
value: string;
|
|
||||||
placeholder: string;
|
|
||||||
onChange: (val: any) => any;
|
|
||||||
};
|
|
||||||
|
|
||||||
public state: { focused: boolean };
|
|
||||||
|
|
||||||
constructor(props: object) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
focused: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public componentDidMount() {
|
|
||||||
this.adjustTextAreaHeight();
|
|
||||||
}
|
|
||||||
|
|
||||||
private domRef: HTMLTextAreaElement | null = null;
|
|
||||||
|
|
||||||
public adjustTextAreaHeight() {
|
|
||||||
if (!this.domRef) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.domRef.style.height = '1px';
|
|
||||||
const calculatedHeight = this.domRef.scrollHeight;
|
|
||||||
this.domRef.style.height = calculatedHeight >= 200 ? '200px' : `${calculatedHeight }px`;
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
const { value, placeholder, onChange } = this.props;
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={`engine-variable-setter-input engine-input-control${this.state.focused ? ' engine-focused' : ''}`}
|
|
||||||
>
|
|
||||||
<textarea
|
|
||||||
ref={(r) => {
|
|
||||||
this.domRef = r;
|
|
||||||
}}
|
|
||||||
className="engine-input"
|
|
||||||
value={value || ''}
|
|
||||||
placeholder={placeholder || ''}
|
|
||||||
onChange={(e) => {
|
|
||||||
onChange(e.target.value || '');
|
|
||||||
}}
|
|
||||||
onBlur={() => this.setState({ focused: false })}
|
|
||||||
onFocus={() => this.setState({ focused: true })}
|
|
||||||
onKeyUp={this.adjustTextAreaHeight.bind(this)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class VariableSetter extends Component<{
|
|
||||||
prop: any;
|
|
||||||
placeholder: string;
|
|
||||||
}> {
|
|
||||||
public willDetach: () => any;
|
|
||||||
|
|
||||||
public componentWillMount() {
|
|
||||||
this.willDetach = this.props.prop.onValueChange(() => this.forceUpdate());
|
|
||||||
}
|
|
||||||
|
|
||||||
public componentWillUnmount() {
|
|
||||||
if (this.willDetach) {
|
|
||||||
this.willDetach();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
const { prop } = this.props;
|
|
||||||
return (
|
|
||||||
<Input
|
|
||||||
value={prop.getVariableValue()}
|
|
||||||
placeholder={this.props.placeholder}
|
|
||||||
onChange={(val: string) => prop.setVariableValue(val)}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
@import '~@ali/ve-less-variables/index.less';
|
|
||||||
|
|
||||||
.engine-field-variable-switcher {
|
|
||||||
cursor: pointer;
|
|
||||||
opacity: 0.6;
|
|
||||||
margin-left: 2px;
|
|
||||||
|
|
||||||
&.engine-active {
|
|
||||||
opacity: 1;
|
|
||||||
background: var(--color-brand, @brand-color-1);
|
|
||||||
color: #fff !important;
|
|
||||||
border-radius: 3px;
|
|
||||||
margin-left: 4px;
|
|
||||||
|
|
||||||
svg {
|
|
||||||
height: 22px !important;
|
|
||||||
width: 22px !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,61 +0,0 @@
|
|||||||
import VariableSetter from './variable-setter';
|
|
||||||
import Icons from '@ali/ve-icons';
|
|
||||||
import { IVEFieldProps } from './field';
|
|
||||||
import './variable-switcher.less';
|
|
||||||
import { Component } from 'react';
|
|
||||||
import { setters } from '@ali/lowcode-engine';
|
|
||||||
|
|
||||||
const { getSetter } = setters;
|
|
||||||
|
|
||||||
interface IState {
|
|
||||||
visible: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class VariableSwitcher extends Component<IVEFieldProps, IState> {
|
|
||||||
private ref: HTMLElement | null = null;
|
|
||||||
|
|
||||||
private VariableSetter: any;
|
|
||||||
|
|
||||||
constructor(props: IVEFieldProps) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.VariableSetter = getSetter('VariableSetter')?.component || VariableSetter;
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
visible: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
const { isUseVariable, prop } = this.props;
|
|
||||||
const { visible } = this.state;
|
|
||||||
const isSupportVariable = prop.isSupportVariable();
|
|
||||||
const tip = !isUseVariable ? '绑定变量' : prop.getVariableValue();
|
|
||||||
if (!isSupportVariable) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Icons.Tip
|
|
||||||
name="var"
|
|
||||||
size="24px"
|
|
||||||
position="bottom center"
|
|
||||||
className={`engine-field-variable-switcher ${isUseVariable ? 'engine-active' : ''}`}
|
|
||||||
data-tip={tip}
|
|
||||||
onClick={(e: Event) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
if (this.VariableSetter.isPopup) {
|
|
||||||
this.VariableSetter.show({
|
|
||||||
prop,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
prop.setUseVariable(!isUseVariable);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
绑定变量
|
|
||||||
</Icons.Tip>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,152 +0,0 @@
|
|||||||
import domReady from 'domready';
|
|
||||||
|
|
||||||
import { EventEmitter } from 'events';
|
|
||||||
|
|
||||||
const Shells = ['iphone6'];
|
|
||||||
|
|
||||||
export class Flags {
|
|
||||||
public emitter: EventEmitter;
|
|
||||||
|
|
||||||
public flags: string[];
|
|
||||||
|
|
||||||
public ready: boolean;
|
|
||||||
|
|
||||||
public lastFlags: string[];
|
|
||||||
|
|
||||||
public lastShell: string;
|
|
||||||
|
|
||||||
private lastSimulatorDevice: string;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.emitter = new EventEmitter();
|
|
||||||
this.flags = [];
|
|
||||||
|
|
||||||
domReady(() => {
|
|
||||||
this.ready = true;
|
|
||||||
this.applyFlags();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public setDragMode(flag: boolean) {
|
|
||||||
if (flag) {
|
|
||||||
this.add('drag-mode');
|
|
||||||
} else {
|
|
||||||
this.remove('drag-mode');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public setPreviewMode(flag: boolean) {
|
|
||||||
if (flag) {
|
|
||||||
this.add('preview-mode');
|
|
||||||
this.remove('design-mode');
|
|
||||||
} else {
|
|
||||||
this.add('design-mode');
|
|
||||||
this.remove('preview-mode');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public setWithShell(shell: string) {
|
|
||||||
if (shell === this.lastShell) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this.lastShell) {
|
|
||||||
this.remove(`with-${this.lastShell}shell`);
|
|
||||||
}
|
|
||||||
if (shell) {
|
|
||||||
if (Shells.indexOf(shell) < 0) {
|
|
||||||
shell = Shells[0];
|
|
||||||
}
|
|
||||||
this.add(`with-${shell}shell`);
|
|
||||||
this.lastShell = shell;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public setSimulator(device: string) {
|
|
||||||
if (this.lastSimulatorDevice) {
|
|
||||||
this.remove(`simulator-${this.lastSimulatorDevice}`);
|
|
||||||
}
|
|
||||||
if (device !== '' && device !== 'pc') {
|
|
||||||
this.add(`simulator-${device}`);
|
|
||||||
}
|
|
||||||
this.lastSimulatorDevice = device;
|
|
||||||
}
|
|
||||||
|
|
||||||
public setHideSlate(flag: boolean) {
|
|
||||||
if (this.has('slate-fixed')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (flag) {
|
|
||||||
this.add('hide-slate');
|
|
||||||
} else {
|
|
||||||
this.remove('hide-slate');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public setSlateFixedMode(flag: boolean) {
|
|
||||||
if (flag) {
|
|
||||||
this.remove('hide-slate');
|
|
||||||
this.add('slate-fixed');
|
|
||||||
} else {
|
|
||||||
this.remove('slate-fixed');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public setSlateFullMode(flag: boolean) {
|
|
||||||
if (flag) {
|
|
||||||
this.add('slate-full-screen');
|
|
||||||
} else {
|
|
||||||
this.remove('slate-full-screen');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public getFlags() {
|
|
||||||
return this.flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
public applyFlags(modifiedFlag?: string) {
|
|
||||||
if (!this.ready) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const doc = document.documentElement;
|
|
||||||
if (this.lastFlags) {
|
|
||||||
this.lastFlags.filter((flag: string) => this.flags.indexOf(flag) < 0).forEach((flag) => {
|
|
||||||
doc.classList.remove(`engine-${flag}`);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.flags.forEach((flag) => {
|
|
||||||
doc.classList.add(`engine-${flag}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.lastFlags = this.flags.slice(0);
|
|
||||||
this.emitter.emit('flagschange', this.flags, modifiedFlag);
|
|
||||||
}
|
|
||||||
|
|
||||||
public has(flag: string) {
|
|
||||||
return this.flags.indexOf(flag) > -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public add(flag: string) {
|
|
||||||
if (!this.has(flag)) {
|
|
||||||
this.flags.push(flag);
|
|
||||||
this.applyFlags(flag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public remove(flag: string) {
|
|
||||||
const i = this.flags.indexOf(flag);
|
|
||||||
if (i > -1) {
|
|
||||||
this.flags.splice(i, 1);
|
|
||||||
this.applyFlags(flag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public onFlagsChange(func: () => any) {
|
|
||||||
this.emitter.on('flagschange', func);
|
|
||||||
return () => {
|
|
||||||
this.emitter.removeListener('flagschange', func);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default new Flags();
|
|
||||||
@ -1,84 +0,0 @@
|
|||||||
import { Node } from '@ali/lowcode-designer';
|
|
||||||
|
|
||||||
declare enum LANGUAGES {
|
|
||||||
zh_CN = 'zh_CN',
|
|
||||||
en_US = 'en_US'
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface I18nRecord {
|
|
||||||
type?: 'i18n';
|
|
||||||
[key: string]: string;
|
|
||||||
/**
|
|
||||||
* i18n unique key
|
|
||||||
*/
|
|
||||||
key?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface I18nRecordData {
|
|
||||||
gmtCreate: Date;
|
|
||||||
gmtModified: Date;
|
|
||||||
i18nKey: string;
|
|
||||||
i18nText: I18nRecord;
|
|
||||||
id: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface II18nUtilConfigs {
|
|
||||||
items?: {};
|
|
||||||
/**
|
|
||||||
* 是否禁用初始化加载
|
|
||||||
*/
|
|
||||||
disableInstantLoad?: boolean;
|
|
||||||
/**
|
|
||||||
* 初始化的时候是否全量加载
|
|
||||||
*/
|
|
||||||
disableFullLoad?: boolean;
|
|
||||||
loader?: (configs: ILoaderConfigs) => Promise<I18nRecordData[]>;
|
|
||||||
remover?: (key: string, dic: I18nRecord) => Promise<void>;
|
|
||||||
saver?: (key: string, dic: I18nRecord) => Promise<void>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ILoaderConfigs {
|
|
||||||
/**
|
|
||||||
* search keywords
|
|
||||||
*/
|
|
||||||
keyword?: string;
|
|
||||||
/**
|
|
||||||
* should load all i18n items
|
|
||||||
*/
|
|
||||||
isFull?: boolean;
|
|
||||||
/**
|
|
||||||
* search i18n item based on uniqueKey
|
|
||||||
*/
|
|
||||||
key?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface II18nUtil {
|
|
||||||
init(config: II18nUtilConfigs): void;
|
|
||||||
isInitialized(): boolean;
|
|
||||||
isReady(): boolean;
|
|
||||||
attach(prop: object, value: I18nRecord, updator: () => any);
|
|
||||||
search(keyword: string, silent?: boolean);
|
|
||||||
load(configs: ILoaderConfigs): Promise<I18nRecord[]>;
|
|
||||||
/**
|
|
||||||
* Get local i18n Record
|
|
||||||
* @param key
|
|
||||||
* @param lang
|
|
||||||
*/
|
|
||||||
get(key: string, lang: string, info?: {
|
|
||||||
node?: Node,
|
|
||||||
path?: string,
|
|
||||||
}): string | I18nRecord;
|
|
||||||
getFromRemote(key: string): Promise<I18nRecord>;
|
|
||||||
getItem(key: string, forceData?: boolean): any;
|
|
||||||
getItems(): I18nRecord[];
|
|
||||||
update(key: string, doc: I18nRecord, lang: LANGUAGES);
|
|
||||||
create(doc: I18nRecord, lang: LANGUAGES): string;
|
|
||||||
remove(key: string): Promise<void>;
|
|
||||||
|
|
||||||
onReady(func: () => any);
|
|
||||||
onRowsChange(func: () => any);
|
|
||||||
onChange(func: (dic: I18nRecord) => any);
|
|
||||||
}
|
|
||||||
|
|
||||||
declare const i18nUtil: II18nUtil;
|
|
||||||
export default i18nUtil;
|
|
||||||
@ -1,357 +0,0 @@
|
|||||||
import { EventEmitter } from 'events';
|
|
||||||
import { editorCabin, editor } from '@ali/lowcode-engine';
|
|
||||||
import lodashGet from 'lodash.get';
|
|
||||||
import { GlobalEvent } from '@ali/lowcode-types';
|
|
||||||
|
|
||||||
const { obx } = editorCabin;
|
|
||||||
|
|
||||||
let keybase = Date.now();
|
|
||||||
function keygen(maps) {
|
|
||||||
let key;
|
|
||||||
do {
|
|
||||||
key = `i18n-${(keybase).toString(36)}`;
|
|
||||||
keybase += 1;
|
|
||||||
} while (key in maps);
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
class DocItem {
|
|
||||||
constructor(parent, doc, unInitial) {
|
|
||||||
this.parent = parent;
|
|
||||||
const { use, ...strings } = doc;
|
|
||||||
this.doc = obx({
|
|
||||||
type: 'i18n',
|
|
||||||
...strings,
|
|
||||||
});
|
|
||||||
this.emitter = new EventEmitter();
|
|
||||||
this.nodeList = new Map();
|
|
||||||
this.onChange((doc, oldDoc) => {
|
|
||||||
if (this.nodeList.size <= 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.nodeList.forEach(({
|
|
||||||
node,
|
|
||||||
path,
|
|
||||||
}) => {
|
|
||||||
const prop = node.settingEntry.getProp(path);
|
|
||||||
const changeInfo = {
|
|
||||||
key: prop?.key,
|
|
||||||
prop,
|
|
||||||
newValue: doc,
|
|
||||||
oldValue: oldDoc,
|
|
||||||
};
|
|
||||||
node.emitPropChange(changeInfo);
|
|
||||||
editor.emit(GlobalEvent.Node.Prop.Change, {
|
|
||||||
node,
|
|
||||||
...changeInfo,
|
|
||||||
});
|
|
||||||
editor.emit(GlobalEvent.Node.Prop.InnerChange, {
|
|
||||||
node,
|
|
||||||
...changeInfo,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
this.inited = unInitial !== true;
|
|
||||||
}
|
|
||||||
|
|
||||||
getKey() {
|
|
||||||
return this.doc.key;
|
|
||||||
}
|
|
||||||
|
|
||||||
getDoc(lang) {
|
|
||||||
if (lang) {
|
|
||||||
return this.doc[lang];
|
|
||||||
}
|
|
||||||
return Object.assign({}, this.doc);
|
|
||||||
}
|
|
||||||
|
|
||||||
setDoc(doc, lang, initial) {
|
|
||||||
const oldValue = Object.assign({}, this.doc);
|
|
||||||
if (lang) {
|
|
||||||
this.doc[lang] = doc;
|
|
||||||
} else {
|
|
||||||
const { use, strings } = doc || {};
|
|
||||||
Object.assign(this.doc, doc, strings);
|
|
||||||
}
|
|
||||||
this.emitter.emit('change', this.doc, oldValue);
|
|
||||||
|
|
||||||
if (initial) {
|
|
||||||
this.inited = true;
|
|
||||||
} else if (this.inited) {
|
|
||||||
this.parent._saveChange(this.doc.key, this.doc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
collectNode = (nodeInfo) => {
|
|
||||||
const key = lodashGet(nodeInfo, 'node.id');
|
|
||||||
if (!key) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.nodeList.set(key, nodeInfo);
|
|
||||||
};
|
|
||||||
|
|
||||||
remove() {
|
|
||||||
if (!this.inited) return Promise.reject('not initialized');
|
|
||||||
|
|
||||||
const { key, ...doc } = this.doc; // eslint-disable-line
|
|
||||||
this.emitter.emit('change', doc);
|
|
||||||
return this.parent.remove(this.getKey());
|
|
||||||
}
|
|
||||||
|
|
||||||
onChange(func) {
|
|
||||||
this.emitter.on('change', func);
|
|
||||||
return () => {
|
|
||||||
this.emitter.removeListener('change', func);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class I18nUtil {
|
|
||||||
constructor() {
|
|
||||||
this.emitter = new EventEmitter();
|
|
||||||
// original data source from remote
|
|
||||||
this.i18nData = {};
|
|
||||||
// current i18n records on the left pane
|
|
||||||
this.items = [];
|
|
||||||
this.maps = {};
|
|
||||||
// full list of i18n records for synchronized call
|
|
||||||
this.fullList = [];
|
|
||||||
this.fullMap = {};
|
|
||||||
|
|
||||||
this.config = {};
|
|
||||||
this.ready = false;
|
|
||||||
this.isInited = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
_prepareItems(items, isFull = false, isSilent = false) {
|
|
||||||
this[isFull ? 'fullList' : 'items'] = items.map((dict) => {
|
|
||||||
let item = this[isFull ? 'fullMap' : 'maps'][dict.key];
|
|
||||||
if (item) {
|
|
||||||
item.setDoc(dict, null, true);
|
|
||||||
} else {
|
|
||||||
item = new DocItem(this, dict);
|
|
||||||
this[isFull ? 'fullMap' : 'maps'][dict.key] = item;
|
|
||||||
}
|
|
||||||
return item;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this.ready && !isSilent) {
|
|
||||||
this.emitter.emit('rowschange');
|
|
||||||
this.emitter.emit('change');
|
|
||||||
} else {
|
|
||||||
this.ready = true;
|
|
||||||
this.emitter.emit('ready');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_load(configs = {}, silent) {
|
|
||||||
if (!this.config.loader) {
|
|
||||||
console.error(new Error('Please load loader while init I18nUtil.'));
|
|
||||||
return Promise.reject();
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.config.loader(configs).then((data) => {
|
|
||||||
if (configs.i18nKey) {
|
|
||||||
return Promise.resolve(data.i18nText);
|
|
||||||
}
|
|
||||||
this._prepareItems(data.data, configs.isFull, silent);
|
|
||||||
// set pagination data to i18nData
|
|
||||||
this.i18nData = data;
|
|
||||||
if (!silent) {
|
|
||||||
this.emitter.emit('rowschange');
|
|
||||||
this.emitter.emit('change');
|
|
||||||
}
|
|
||||||
return Promise.resolve(this.items.map(i => i.getDoc()));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
_saveToItems(key, dict) {
|
|
||||||
let item = null;
|
|
||||||
item = this.items.find(doc => doc.getKey() === key);
|
|
||||||
if (!item) {
|
|
||||||
item = this.fullList.find(doc => doc.getKey() === key);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!item && (this.maps[key] || this.fullMap[key])) {
|
|
||||||
// 如果从 items 和 fullList 里面找到 DocItem,就从 maps/fullMap 里面取
|
|
||||||
item = this.maps[key] || this.fullMap[key];
|
|
||||||
this.items.unshift(item);
|
|
||||||
this.fullList.unshift(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item) {
|
|
||||||
item.setDoc(dict);
|
|
||||||
} else {
|
|
||||||
item = new DocItem(this, {
|
|
||||||
key,
|
|
||||||
...dict,
|
|
||||||
});
|
|
||||||
this.items.unshift(item);
|
|
||||||
this.fullList.unshift(item);
|
|
||||||
this.maps[key] = item;
|
|
||||||
this.fullMap[key] = item;
|
|
||||||
this._saveChange(key, dict, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_saveChange(key, dict, rowschange) {
|
|
||||||
if (rowschange) {
|
|
||||||
this.emitter.emit('rowschange');
|
|
||||||
}
|
|
||||||
this.emitter.emit('change');
|
|
||||||
if (dict === null) {
|
|
||||||
delete this.maps[key];
|
|
||||||
delete this.fullMap[key];
|
|
||||||
}
|
|
||||||
return this._save(key, dict);
|
|
||||||
}
|
|
||||||
|
|
||||||
_save(key, dict) {
|
|
||||||
const saver = dict === null ? this.config.remover : this.config.saver;
|
|
||||||
if (!saver) return Promise.reject('Saver function is not set');
|
|
||||||
return saver(key, dict);
|
|
||||||
}
|
|
||||||
|
|
||||||
init(config) {
|
|
||||||
if (this.isInited) return;
|
|
||||||
this.config = config || {};
|
|
||||||
if (this.config.items) {
|
|
||||||
// inject to current page
|
|
||||||
this._prepareItems(this.config.items);
|
|
||||||
}
|
|
||||||
if (!this.config.disableInstantLoad) {
|
|
||||||
this._load({ isFull: !this.config.disableFullLoad });
|
|
||||||
}
|
|
||||||
this.isInited = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
isInitialized() {
|
|
||||||
return this.isInited;
|
|
||||||
}
|
|
||||||
|
|
||||||
isReady() {
|
|
||||||
return this.ready;
|
|
||||||
}
|
|
||||||
|
|
||||||
// add events updater when i18n record change
|
|
||||||
// we should notify engine's view to change
|
|
||||||
attach(prop, value, updator) {
|
|
||||||
const isI18nValue = value && value.type === 'i18n' && value.key;
|
|
||||||
const key = isI18nValue ? value.key : null;
|
|
||||||
if (prop.i18nLink) {
|
|
||||||
if (isI18nValue && (key === prop.i18nLink.key)) {
|
|
||||||
return prop.i18nLink;
|
|
||||||
}
|
|
||||||
prop.i18nLink.detach();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isI18nValue) {
|
|
||||||
return {
|
|
||||||
key,
|
|
||||||
detach: this.getItem(key, value).onChange(updator),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 搜索 i18n 词条
|
|
||||||
*
|
|
||||||
* @param {any} keyword 搜索关键字
|
|
||||||
* @param {boolean} [silent=false] 是否刷新左侧的 i18n 数据
|
|
||||||
* @returns
|
|
||||||
*
|
|
||||||
* @memberof I18nUtil
|
|
||||||
*/
|
|
||||||
search(keyword, silent = false) {
|
|
||||||
return this._load({ keyword }, silent);
|
|
||||||
}
|
|
||||||
|
|
||||||
load(configs = {}) {
|
|
||||||
return this._load(configs);
|
|
||||||
}
|
|
||||||
|
|
||||||
get(key, lang, nodeInfo) {
|
|
||||||
const item = this.getItem(key);
|
|
||||||
if (item) {
|
|
||||||
item.collectNode(nodeInfo);
|
|
||||||
return item.getDoc(lang);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
getFromRemote(key) {
|
|
||||||
return this._load({ i18nKey: key });
|
|
||||||
}
|
|
||||||
|
|
||||||
getItem(key, forceData) {
|
|
||||||
if (forceData && !this.maps[key] && !this.fullList[key]) {
|
|
||||||
const item = new DocItem(this, {
|
|
||||||
key,
|
|
||||||
...forceData,
|
|
||||||
}, true);
|
|
||||||
this.maps[key] = item;
|
|
||||||
this.fullMap[key] = item;
|
|
||||||
this.fullList.push(item);
|
|
||||||
this.items.push(item);
|
|
||||||
}
|
|
||||||
return this.maps[key] || this.fullMap[key];
|
|
||||||
}
|
|
||||||
|
|
||||||
getItems() {
|
|
||||||
return this.items;
|
|
||||||
}
|
|
||||||
|
|
||||||
update(key, doc, lang) {
|
|
||||||
let dict = this.get(key) || {};
|
|
||||||
if (!lang) {
|
|
||||||
dict = doc;
|
|
||||||
} else {
|
|
||||||
dict[lang] = doc;
|
|
||||||
}
|
|
||||||
this._saveToItems(key, dict);
|
|
||||||
}
|
|
||||||
|
|
||||||
create(doc, lang) {
|
|
||||||
const dict = lang ? { [lang]: doc } : doc;
|
|
||||||
const key = keygen(this.fullMap);
|
|
||||||
this._saveToItems(key, dict);
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
remove(key) {
|
|
||||||
const index = this.items.findIndex(item => item.getKey() === key);
|
|
||||||
const indexG = this.fullList.findIndex(item => item.getKey() === key);
|
|
||||||
if (index > -1) {
|
|
||||||
this.items.splice(index, 1);
|
|
||||||
}
|
|
||||||
if (indexG > -1) {
|
|
||||||
this.fullList.splice(index, 1);
|
|
||||||
}
|
|
||||||
return this._saveChange(key, null, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
onReady(func) {
|
|
||||||
this.emitter.on('ready', func);
|
|
||||||
return () => {
|
|
||||||
this.emitter.removeListener('ready', func);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
onRowsChange(func) {
|
|
||||||
this.emitter.on('rowschange', func);
|
|
||||||
return () => {
|
|
||||||
this.emitter.removeListener('rowschange', func);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
onChange(func) {
|
|
||||||
this.emitter.on('change', func);
|
|
||||||
return () => {
|
|
||||||
this.emitter.removeListener('change', func);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default new I18nUtil();
|
|
||||||
@ -1,155 +0,0 @@
|
|||||||
import { createElement } from 'react';
|
|
||||||
import { render } from 'react-dom';
|
|
||||||
import * as utils from '@ali/ve-utils';
|
|
||||||
import Popup from '@ali/ve-popups';
|
|
||||||
import Icons from '@ali/ve-icons';
|
|
||||||
import logger from '@ali/vu-logger';
|
|
||||||
import I18nUtil from './i18n-util';
|
|
||||||
import { VE_EVENTS as EVENTS, VE_HOOKS as HOOKS, VERSION as Version } from './base/const';
|
|
||||||
import Bus from './bus';
|
|
||||||
import { skeleton, designer, editor, plugins, init, hotkey as Hotkey, monitor, designerCabin } from '@ali/lowcode-engine';
|
|
||||||
import Panes from './panes';
|
|
||||||
import Exchange from './exchange';
|
|
||||||
import context from './context';
|
|
||||||
import VisualManager from './base/visualManager';
|
|
||||||
import VisualDesigner from './base/visualDesigner';
|
|
||||||
import Trunk from './bundle/trunk';
|
|
||||||
import Prototype from './bundle/prototype';
|
|
||||||
import Bundle from './bundle/bundle';
|
|
||||||
import Pages from './pages';
|
|
||||||
import * as Field from './fields';
|
|
||||||
import Prop from './prop';
|
|
||||||
import Env from './env';
|
|
||||||
import DragEngine from './drag-engine';
|
|
||||||
// import Flags from './base/flags';
|
|
||||||
import Viewport from './viewport';
|
|
||||||
import Project from './project';
|
|
||||||
import Symbols from './symbols';
|
|
||||||
import { invariant } from './utils';
|
|
||||||
import './reducers';
|
|
||||||
|
|
||||||
import './vision.less';
|
|
||||||
|
|
||||||
invariant((window as any).AliLowCodeEngine, 'AliLowCodeEngine is required, since vision polyfill is totally based on AliLowCodeEngine');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* VE.ui.xxx
|
|
||||||
*
|
|
||||||
* Core UI Components
|
|
||||||
*/
|
|
||||||
const ui = {
|
|
||||||
Field,
|
|
||||||
Icon: Icons,
|
|
||||||
Icons,
|
|
||||||
Popup,
|
|
||||||
};
|
|
||||||
|
|
||||||
const modules = {
|
|
||||||
VisualManager,
|
|
||||||
VisualDesigner,
|
|
||||||
I18nUtil,
|
|
||||||
Prop,
|
|
||||||
};
|
|
||||||
|
|
||||||
const { registerMetadataTransducer } = designerCabin;
|
|
||||||
|
|
||||||
const VisualEngine = {
|
|
||||||
designer,
|
|
||||||
designerCabin,
|
|
||||||
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,
|
|
||||||
registerMetadataTransducer,
|
|
||||||
plugins,
|
|
||||||
// Flags,
|
|
||||||
};
|
|
||||||
|
|
||||||
(window as any).VisualEngine = VisualEngine;
|
|
||||||
|
|
||||||
export default VisualEngine;
|
|
||||||
|
|
||||||
export {
|
|
||||||
designer,
|
|
||||||
designerCabin,
|
|
||||||
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,
|
|
||||||
registerMetadataTransducer,
|
|
||||||
plugins,
|
|
||||||
};
|
|
||||||
1
packages/vision-polyfill/src/module.d.ts
vendored
1
packages/vision-polyfill/src/module.d.ts
vendored
@ -1 +0,0 @@
|
|||||||
declare module '@ali/vu-css-style';
|
|
||||||
@ -1,147 +0,0 @@
|
|||||||
import { RootSchema } from '@ali/lowcode-types';
|
|
||||||
import { DocumentModel } from '@ali/lowcode-designer';
|
|
||||||
import { designer } from '@ali/lowcode-engine';
|
|
||||||
import NodeCacheVisitor from './root-node-visitor';
|
|
||||||
|
|
||||||
const { project } = designer;
|
|
||||||
|
|
||||||
export interface PageDataV1 {
|
|
||||||
id: string;
|
|
||||||
componentsTree: RootSchema[];
|
|
||||||
layout: RootSchema;
|
|
||||||
[dataAddon: string]: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PageDataV2 {
|
|
||||||
id: string;
|
|
||||||
componentsTree: RootSchema[];
|
|
||||||
[dataAddon: string]: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isPageDataV1(obj: any): obj is PageDataV1 {
|
|
||||||
return obj && obj.layout;
|
|
||||||
}
|
|
||||||
function isPageDataV2(obj: any): obj is PageDataV2 {
|
|
||||||
return obj && obj.componentsTree && Array.isArray(obj.componentsTree);
|
|
||||||
}
|
|
||||||
|
|
||||||
type OldPageData = PageDataV1 | PageDataV2;
|
|
||||||
|
|
||||||
const pages = Object.assign(project, {
|
|
||||||
setPages(pages: OldPageData[]) {
|
|
||||||
if (!pages || !Array.isArray(pages) || pages.length === 0) {
|
|
||||||
throw new Error('pages schema 不合法');
|
|
||||||
}
|
|
||||||
// todo: miniapp
|
|
||||||
let componentsTree: any = [];
|
|
||||||
if (window.pageConfig?.isNoCodeMiniApp) {
|
|
||||||
// 小程序多页面
|
|
||||||
pages.forEach((item: any) => {
|
|
||||||
if (isPageDataV1(item)) {
|
|
||||||
componentsTree.push(item.layout);
|
|
||||||
} else {
|
|
||||||
componentsTree.push(item.componentsTree[0]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else if (isPageDataV1(pages[0])) {
|
|
||||||
componentsTree = [pages[0].layout];
|
|
||||||
} else {
|
|
||||||
// if (!pages[0].componentsTree) return;
|
|
||||||
componentsTree = pages[0].componentsTree;
|
|
||||||
if (componentsTree[0]) {
|
|
||||||
componentsTree[0].componentName = componentsTree[0].componentName || 'Page';
|
|
||||||
// FIXME
|
|
||||||
if (componentsTree[0].componentName === 'Page' || componentsTree[0].componentName === 'Component') {
|
|
||||||
componentsTree[0].methods = {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentsTree.forEach((item: any) => {
|
|
||||||
item.componentName = item.componentName || 'Page';
|
|
||||||
if (item.componentName === 'Page' || item.componentName === 'Component') {
|
|
||||||
item.methods = {};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
project.load(
|
|
||||||
{
|
|
||||||
version: '1.0.0',
|
|
||||||
componentsMap: [],
|
|
||||||
componentsTree,
|
|
||||||
id: pages[0].id,
|
|
||||||
config: {
|
|
||||||
...project.config,
|
|
||||||
...pages[0].config,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
// FIXME: 在页面节点初始化结束后,还有响应式变量变化导致了多次变化
|
|
||||||
// 这样可以避免页面加载之后就被标记为 isModified
|
|
||||||
setTimeout(() => {
|
|
||||||
project.currentDocument?.history.savePoint();
|
|
||||||
}, 1000);
|
|
||||||
},
|
|
||||||
addPage(data: OldPageData | RootSchema) {
|
|
||||||
if (isPageDataV1(data)) {
|
|
||||||
data = data.layout;
|
|
||||||
} else if (isPageDataV2(data)) {
|
|
||||||
data = data.componentsTree[0];
|
|
||||||
}
|
|
||||||
return project.open(data);
|
|
||||||
},
|
|
||||||
getPage(fnOrIndex: ((page: DocumentModel) => boolean) | number) {
|
|
||||||
if (typeof fnOrIndex === 'number') {
|
|
||||||
return project.documents[fnOrIndex];
|
|
||||||
} else if (typeof fnOrIndex === 'function') {
|
|
||||||
return project.documents.find(fnOrIndex);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
removePage(page: DocumentModel) {
|
|
||||||
page.remove();
|
|
||||||
},
|
|
||||||
getPages() {
|
|
||||||
return project.documents;
|
|
||||||
},
|
|
||||||
setCurrentPage(page: DocumentModel) {
|
|
||||||
page.activate();
|
|
||||||
},
|
|
||||||
getCurrentPage() {
|
|
||||||
return project.currentDocument;
|
|
||||||
},
|
|
||||||
onPagesChange() {
|
|
||||||
// noop
|
|
||||||
},
|
|
||||||
onCurrentPageChange(fn: (page: DocumentModel) => void) {
|
|
||||||
return project.onCurrentDocumentChange(fn);
|
|
||||||
},
|
|
||||||
toData() {
|
|
||||||
return project.documents.map((doc) => doc.toData());
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
Object.defineProperty(pages, 'currentPage', {
|
|
||||||
get() {
|
|
||||||
return project.currentDocument;
|
|
||||||
},
|
|
||||||
set(_currentPage) {
|
|
||||||
// do nothing
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
pages.onCurrentPageChange((page: DocumentModel) => {
|
|
||||||
if (!page) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
page.acceptRootNodeVisitor('NodeCache', (rootNode) => {
|
|
||||||
const visitor: NodeCacheVisitor = page.getRootNodeVisitor('NodeCache');
|
|
||||||
if (visitor) {
|
|
||||||
visitor.destroy();
|
|
||||||
}
|
|
||||||
return new NodeCacheVisitor(page, rootNode);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
export default pages;
|
|
||||||
@ -1,286 +0,0 @@
|
|||||||
import { skeleton, editor } from '@ali/lowcode-engine';
|
|
||||||
import { ReactElement } from 'react';
|
|
||||||
import { IWidgetBaseConfig } from '@ali/lowcode-editor-skeleton';
|
|
||||||
import { IconType } from '@ali/lowcode-types';
|
|
||||||
import { uniqueId } from '@ali/lowcode-utils';
|
|
||||||
import bus from './bus';
|
|
||||||
|
|
||||||
export interface IContentItemConfig {
|
|
||||||
title: string;
|
|
||||||
content: JSX.Element;
|
|
||||||
tip?: {
|
|
||||||
content: string;
|
|
||||||
url?: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface OldPaneConfig {
|
|
||||||
// 'dock' | 'action' | 'tab' | 'widget' | 'stage'
|
|
||||||
type?: string; // where
|
|
||||||
|
|
||||||
id?: string;
|
|
||||||
name: string;
|
|
||||||
title?: string;
|
|
||||||
content?: any;
|
|
||||||
|
|
||||||
place?: string; // align: left|right|top|center|bottom
|
|
||||||
description?: string; // tip?
|
|
||||||
tip?:
|
|
||||||
| string
|
|
||||||
| {
|
|
||||||
// as help tip
|
|
||||||
url?: string;
|
|
||||||
content?: string | JSX.Element;
|
|
||||||
}; // help
|
|
||||||
|
|
||||||
init?: () => any;
|
|
||||||
destroy?: () => any;
|
|
||||||
props?: any;
|
|
||||||
|
|
||||||
contents?: IContentItemConfig[];
|
|
||||||
hideTitleBar?: boolean;
|
|
||||||
width?: number;
|
|
||||||
maxWidth?: number;
|
|
||||||
height?: number;
|
|
||||||
maxHeight?: number;
|
|
||||||
position?: string | string[]; // todo
|
|
||||||
menu?: JSX.Element; // as title
|
|
||||||
index?: number; // todo
|
|
||||||
isAction?: boolean; // as normal dock
|
|
||||||
fullScreen?: boolean; // todo
|
|
||||||
canSetFixed?: boolean; // 是否可以设置固定模式
|
|
||||||
defaultFixed?: boolean; // 是否默认固定
|
|
||||||
enableDrag?: boolean;
|
|
||||||
icon?: IconType; // 支持旧vision pane传icon (menu是title, 并非icon)
|
|
||||||
}
|
|
||||||
|
|
||||||
function upgradeConfig(config: OldPaneConfig): IWidgetBaseConfig & { area: string } {
|
|
||||||
const { type, id, name, title, content, place, description, init, destroy, props, index } = config;
|
|
||||||
|
|
||||||
const newConfig: any = {
|
|
||||||
id,
|
|
||||||
name,
|
|
||||||
content,
|
|
||||||
props: {
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
align: place,
|
|
||||||
},
|
|
||||||
contentProps: props,
|
|
||||||
index: index || props?.index,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (type === 'dock') {
|
|
||||||
newConfig.type = 'PanelDock';
|
|
||||||
newConfig.area = 'left';
|
|
||||||
newConfig.props.description = description || title;
|
|
||||||
const {
|
|
||||||
contents,
|
|
||||||
hideTitleBar,
|
|
||||||
tip,
|
|
||||||
width,
|
|
||||||
maxWidth,
|
|
||||||
height,
|
|
||||||
maxHeight,
|
|
||||||
menu,
|
|
||||||
icon,
|
|
||||||
isAction,
|
|
||||||
canSetFixed,
|
|
||||||
defaultFixed,
|
|
||||||
enableDrag,
|
|
||||||
} = config;
|
|
||||||
if (menu) {
|
|
||||||
newConfig.props.title = menu;
|
|
||||||
}
|
|
||||||
if (icon) {
|
|
||||||
newConfig.props.icon = icon;
|
|
||||||
}
|
|
||||||
if (isAction) {
|
|
||||||
newConfig.type = 'Dock';
|
|
||||||
} else {
|
|
||||||
newConfig.panelProps = {
|
|
||||||
title,
|
|
||||||
hideTitleBar,
|
|
||||||
help: tip,
|
|
||||||
width,
|
|
||||||
maxWidth,
|
|
||||||
height,
|
|
||||||
maxHeight,
|
|
||||||
canSetFixed,
|
|
||||||
enableDrag,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (defaultFixed) {
|
|
||||||
newConfig.panelProps.area = 'leftFixedArea';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (contents && Array.isArray(contents)) {
|
|
||||||
newConfig.content = contents.map(({ title, content, tip }, index) => {
|
|
||||||
return {
|
|
||||||
type: 'Panel',
|
|
||||||
name: typeof title === 'string' ? title : `${name}:${index}`,
|
|
||||||
content,
|
|
||||||
contentProps: props,
|
|
||||||
props: {
|
|
||||||
title,
|
|
||||||
help: tip,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (type === 'action') {
|
|
||||||
newConfig.area = 'top';
|
|
||||||
newConfig.type = 'Dock';
|
|
||||||
} else if (type === 'tab') {
|
|
||||||
newConfig.area = 'right';
|
|
||||||
newConfig.type = 'Panel';
|
|
||||||
} else if (type === 'stage') {
|
|
||||||
newConfig.area = 'stages';
|
|
||||||
newConfig.type = 'Widget';
|
|
||||||
} else {
|
|
||||||
newConfig.area = 'main';
|
|
||||||
newConfig.type = 'Widget';
|
|
||||||
}
|
|
||||||
newConfig.props.onInit = init;
|
|
||||||
newConfig.props.onDestroy = destroy;
|
|
||||||
return newConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
function add(config: (() => OldPaneConfig) | OldPaneConfig, extraConfig?: any) {
|
|
||||||
if (typeof config === 'function') {
|
|
||||||
config = config.call(null);
|
|
||||||
}
|
|
||||||
if (!config || !config.type) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (extraConfig) {
|
|
||||||
config = { ...config, ...extraConfig };
|
|
||||||
}
|
|
||||||
|
|
||||||
const upgraded = upgradeConfig(config);
|
|
||||||
if (upgraded.area === 'stages') {
|
|
||||||
if (upgraded.id) {
|
|
||||||
upgraded.name = upgraded.id;
|
|
||||||
} else if (!upgraded.name) {
|
|
||||||
upgraded.name = uniqueId('stage');
|
|
||||||
}
|
|
||||||
const stage = skeleton.add(upgraded);
|
|
||||||
return stage?.getName();
|
|
||||||
} else {
|
|
||||||
return skeleton.add(upgraded);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const actionPane = Object.assign(skeleton.topArea, {
|
|
||||||
/**
|
|
||||||
* compatible *VE.actionPane.getActions*
|
|
||||||
*/
|
|
||||||
getActions(): any {
|
|
||||||
return skeleton.topArea.container.items;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* compatible *VE.actionPane.activeDock*
|
|
||||||
*/
|
|
||||||
setActions() {
|
|
||||||
// empty
|
|
||||||
},
|
|
||||||
get actions() {
|
|
||||||
return skeleton.topArea.container.items;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const dockPane = Object.assign(skeleton.leftArea, {
|
|
||||||
/**
|
|
||||||
* compatible *VE.dockPane.activeDock*
|
|
||||||
*/
|
|
||||||
activeDock(item: any) {
|
|
||||||
if (!item) {
|
|
||||||
skeleton.leftFloatArea?.current?.hide();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const name = item.name || item;
|
|
||||||
const pane = skeleton.getPanel(name);
|
|
||||||
if (!pane) {
|
|
||||||
console.warn(`Could not find pane with name ${name}`);
|
|
||||||
}
|
|
||||||
pane?.active();
|
|
||||||
bus.emit('ve.dock_pane.active_doc', pane);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* compatible *VE.dockPane.onDockShow*
|
|
||||||
*/
|
|
||||||
onDockShow(fn: (dock: any) => void): () => void {
|
|
||||||
const f = (_: any, dock: any) => {
|
|
||||||
fn(dock);
|
|
||||||
};
|
|
||||||
editor.on('skeleton.panel-dock.active', f);
|
|
||||||
return () => {
|
|
||||||
editor.removeListener('skeleton.panel-dock.active', f);
|
|
||||||
};
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* compatible *VE.dockPane.onDockHide*
|
|
||||||
*/
|
|
||||||
onDockHide(fn: (dock: any) => void): () => void {
|
|
||||||
const f = (_: any, dock: any) => {
|
|
||||||
fn(dock);
|
|
||||||
};
|
|
||||||
editor.on('skeleton.panel-dock.unactive', f);
|
|
||||||
return () => {
|
|
||||||
editor.removeListener('skeleton.panel-dock.unactive', f);
|
|
||||||
};
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* compatible *VE.dockPane.setFixed*
|
|
||||||
*/
|
|
||||||
setFixed(flag: boolean) {
|
|
||||||
// todo:
|
|
||||||
},
|
|
||||||
getDocks() {
|
|
||||||
return skeleton.leftFloatArea?.container.items;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const tabPane = Object.assign(skeleton.rightArea, {
|
|
||||||
setFloat(flag: boolean) {
|
|
||||||
// todo:
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const toolbar = Object.assign(skeleton.toolbar, {
|
|
||||||
setContents(contents: ReactElement) {
|
|
||||||
// todo:
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const widgets = skeleton.mainArea;
|
|
||||||
|
|
||||||
const stages = Object.assign(skeleton.stages, {
|
|
||||||
getStage(name: string) {
|
|
||||||
return skeleton.stages.container.get(name);
|
|
||||||
},
|
|
||||||
|
|
||||||
createStage(config: any) {
|
|
||||||
config = upgradeConfig(config);
|
|
||||||
if (config.id) {
|
|
||||||
config.name = config.id;
|
|
||||||
} else if (!config.name) {
|
|
||||||
config.name = uniqueId('stage');
|
|
||||||
}
|
|
||||||
|
|
||||||
const stage = skeleton.stages.add(config);
|
|
||||||
return stage.getName();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default {
|
|
||||||
ActionPane: actionPane, // topArea
|
|
||||||
actionPane, //
|
|
||||||
DockPane: dockPane, // leftArea
|
|
||||||
dockPane,
|
|
||||||
TabPane: tabPane, // rightArea
|
|
||||||
tabPane,
|
|
||||||
add,
|
|
||||||
toolbar, // toolbar
|
|
||||||
Stages: stages,
|
|
||||||
Widgets: widgets, // centerArea
|
|
||||||
widgets,
|
|
||||||
};
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
import { designer } from '@ali/lowcode-engine';
|
|
||||||
|
|
||||||
const { project } = designer;
|
|
||||||
|
|
||||||
const visionProject = {};
|
|
||||||
Object.assign(visionProject, project, {
|
|
||||||
getSchema(): any {
|
|
||||||
return this.schema || {};
|
|
||||||
},
|
|
||||||
|
|
||||||
setSchema(schema: any) {
|
|
||||||
this.schema = schema;
|
|
||||||
},
|
|
||||||
|
|
||||||
setConfig(config: any) {
|
|
||||||
this.set('config', config);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default visionProject;
|
|
||||||
@ -1,630 +0,0 @@
|
|||||||
import { Component } from 'react';
|
|
||||||
import { EventEmitter } from 'events';
|
|
||||||
import { fromJS, Iterable, Map as IMMap } from 'immutable';
|
|
||||||
import logger from '@ali/vu-logger';
|
|
||||||
import { cloneDeep, isDataEqual, combineInitial, Transducer } from '@ali/ve-utils';
|
|
||||||
import I18nUtil from '@ali/ve-i18n-util';
|
|
||||||
import { editor, setters } from '@ali/lowcode-engine';
|
|
||||||
import { OldPropConfig, DISPLAY_TYPE } from './bundle/upgrade-metadata';
|
|
||||||
import { uniqueId } from '@ali/lowcode-utils';
|
|
||||||
|
|
||||||
const { getSetter } = setters;
|
|
||||||
|
|
||||||
type IPropConfig = OldPropConfig;
|
|
||||||
|
|
||||||
// 1: chain -1: start 0: discard
|
|
||||||
const CHAIN_START = -1;
|
|
||||||
const CHAIN_HAS_REACH = 0;
|
|
||||||
|
|
||||||
export enum PROP_VALUE_CHANGED_TYPE {
|
|
||||||
/**
|
|
||||||
* normal set value
|
|
||||||
*/
|
|
||||||
SET_VALUE = 'SET_VALUE',
|
|
||||||
/**
|
|
||||||
* value changed caused by sub-prop value change
|
|
||||||
*/
|
|
||||||
SUB_VALUE_CHANGE = 'SUB_VALUE_CHANGE',
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dynamic setter will use 've.plugin.setterProvider' to
|
|
||||||
* calculate setter type in runtime
|
|
||||||
*/
|
|
||||||
let dynamicSetterProvider: any;
|
|
||||||
|
|
||||||
export interface IHotDataMap extends IMMap<string, any> {
|
|
||||||
value: any;
|
|
||||||
hotValue: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ISetValueOptions {
|
|
||||||
disableMutator?: boolean;
|
|
||||||
type?: PROP_VALUE_CHANGED_TYPE;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IVariableSettable {
|
|
||||||
useVariable?: boolean;
|
|
||||||
variableValue: string;
|
|
||||||
isUseVariable: () => boolean;
|
|
||||||
isSupportVariable: () => boolean;
|
|
||||||
setVariableValue: (value: string) => void;
|
|
||||||
setUseVariable: (flag?: boolean) => void;
|
|
||||||
getVariableValue: () => string;
|
|
||||||
onUseVariableChange: (func: (data: { isUseVariable: boolean }) => any) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class Prop implements IVariableSettable {
|
|
||||||
/**
|
|
||||||
* Setters predefined as default options
|
|
||||||
* can by selected by user for every prop
|
|
||||||
*
|
|
||||||
* @static
|
|
||||||
* @memberof Prop
|
|
||||||
*/
|
|
||||||
public static INSET_SETTER = {};
|
|
||||||
|
|
||||||
public id: string;
|
|
||||||
|
|
||||||
public emitter: EventEmitter;
|
|
||||||
|
|
||||||
public inited: boolean;
|
|
||||||
|
|
||||||
public i18nLink: any;
|
|
||||||
|
|
||||||
public loopLock: boolean;
|
|
||||||
|
|
||||||
public props: any;
|
|
||||||
|
|
||||||
public parent: any;
|
|
||||||
|
|
||||||
public config: IPropConfig;
|
|
||||||
|
|
||||||
public initial: any;
|
|
||||||
|
|
||||||
public initialData: any;
|
|
||||||
|
|
||||||
public expanded: boolean;
|
|
||||||
|
|
||||||
public useVariable?: boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* value to be saved in schema it is usually JSON serialized
|
|
||||||
* prototype.js can config Transducer.toNative to generate value
|
|
||||||
*/
|
|
||||||
public value: any;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* value to be used in VisualDesigner more flexible
|
|
||||||
* prototype.js can config Transducer.toHot to generate hotValue
|
|
||||||
*/
|
|
||||||
public hotValue: any;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 启用变量之后,变量表达式字符串值
|
|
||||||
*/
|
|
||||||
public variableValue: string;
|
|
||||||
|
|
||||||
public hotData: IMMap<string, IHotDataMap>;
|
|
||||||
|
|
||||||
public defaultValue: any;
|
|
||||||
|
|
||||||
public transducer: any;
|
|
||||||
|
|
||||||
public inGroup: boolean;
|
|
||||||
|
|
||||||
constructor(parent: any, config: IPropConfig, data?: any) {
|
|
||||||
if (parent.isProps) {
|
|
||||||
this.props = parent;
|
|
||||||
this.parent = null;
|
|
||||||
} else {
|
|
||||||
this.props = parent.getProps();
|
|
||||||
this.parent = parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.id = uniqueId('prop');
|
|
||||||
|
|
||||||
if (typeof config.setter === 'string') {
|
|
||||||
config.setter = getSetter(config.setter)?.component as any;
|
|
||||||
}
|
|
||||||
this.config = config;
|
|
||||||
this.emitter = new EventEmitter();
|
|
||||||
this.emitter.setMaxListeners(100);
|
|
||||||
this.initialData = data;
|
|
||||||
this.useVariable = false;
|
|
||||||
|
|
||||||
dynamicSetterProvider = editor.get('ve.plugin.setterProvider');
|
|
||||||
|
|
||||||
this.beforeInit();
|
|
||||||
}
|
|
||||||
|
|
||||||
public getId() {
|
|
||||||
return this.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public isTab() {
|
|
||||||
return this.getDisplay() === 'tab';
|
|
||||||
}
|
|
||||||
|
|
||||||
public isGroup() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public beforeInit() {
|
|
||||||
if (IMMap.isMap(this.initialData)) {
|
|
||||||
this.value = this.initialData.get('value');
|
|
||||||
if (this.value && typeof this.value.toJS === 'function') {
|
|
||||||
this.value = this.value.toJS();
|
|
||||||
}
|
|
||||||
this.hotData = this.initialData;
|
|
||||||
} else {
|
|
||||||
this.value = this.initialData;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.resolveValue();
|
|
||||||
|
|
||||||
let defaultValue = null;
|
|
||||||
if (this.config.defaultValue !== undefined) {
|
|
||||||
defaultValue = this.config.defaultValue;
|
|
||||||
} else if (typeof this.config.initialValue !== 'function') {
|
|
||||||
defaultValue = this.config.initialValue;
|
|
||||||
}
|
|
||||||
this.defaultValue = defaultValue;
|
|
||||||
this.transducer = new Transducer(this, this.config);
|
|
||||||
this.initial = combineInitial(this, this.config);
|
|
||||||
}
|
|
||||||
|
|
||||||
public resolveValue() {
|
|
||||||
if (this.value && this.value.type === 'variable') {
|
|
||||||
const { value, variable } = this.value;
|
|
||||||
this.value = value;
|
|
||||||
this.variableValue = variable;
|
|
||||||
this.useVariable = this.isSupportVariable();
|
|
||||||
} else {
|
|
||||||
this.useVariable = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public init(defaultValue?: any) {
|
|
||||||
if (this.inited) { return; }
|
|
||||||
|
|
||||||
this.value = this.initial(this.value,
|
|
||||||
this.defaultValue != null ? this.defaultValue : defaultValue);
|
|
||||||
|
|
||||||
if (this.hotData) {
|
|
||||||
const tempVal = this.hotData.get('value');
|
|
||||||
// if we create a prop from runtime data, we don't need initial() or set with defaultValue process
|
|
||||||
// but if we got an empty value, we fill with the initial() process and default value
|
|
||||||
if (Iterable.isIterable(tempVal)) {
|
|
||||||
this.value = tempVal.toJS() || this.value;
|
|
||||||
} else {
|
|
||||||
this.value = tempVal || this.value;
|
|
||||||
}
|
|
||||||
this.resolveValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.i18nLink = I18nUtil.attach(this, this.value,
|
|
||||||
((val: any) => { this.setValue(val, false, true); }) as any);
|
|
||||||
|
|
||||||
// call config.accessor
|
|
||||||
const value = this.getValue();
|
|
||||||
|
|
||||||
if (this.hotData) {
|
|
||||||
this.hotValue = this.hotData.get('hotValue');
|
|
||||||
if (this.hotValue && Iterable.isIterable(this.hotValue)) {
|
|
||||||
this.hotValue = this.hotValue.toJS();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
this.hotValue = this.transducer.toHot(value);
|
|
||||||
} catch (e) {
|
|
||||||
logger.log('ERROR_PROP_VALUE');
|
|
||||||
logger.warn('属性初始化错误:', this);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.hotData = fromJS({
|
|
||||||
hotValue: this.hotValue,
|
|
||||||
value: this.getMixValue(value),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.inited = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public isInited() {
|
|
||||||
return this.inited;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getHotData() {
|
|
||||||
return this.hotData;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getProps() {
|
|
||||||
return this.props;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getNode(): any {
|
|
||||||
return this.getProps().getNode();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得属性名称
|
|
||||||
*
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
public getName(): string {
|
|
||||||
const ns = this.parent ? `${this.parent.getName()}.` : '';
|
|
||||||
return ns + this.config.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getKey() {
|
|
||||||
return this.config.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得属性标题
|
|
||||||
*
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
public getTitle() {
|
|
||||||
return this.config.title || this.getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
public getTip() {
|
|
||||||
return this.config.tip || null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getValue(disableCache?: boolean, options?: {
|
|
||||||
disableAccessor?: boolean;
|
|
||||||
}) {
|
|
||||||
const { accessor } = this.config;
|
|
||||||
if (accessor && (!options || !options.disableAccessor)) {
|
|
||||||
const value = accessor.call(this as any, this.value);
|
|
||||||
if (!disableCache) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
return this.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getMixValue(value?: any) {
|
|
||||||
if (value == null) {
|
|
||||||
value = this.getValue();
|
|
||||||
}
|
|
||||||
if (this.isUseVariable()) {
|
|
||||||
value = {
|
|
||||||
type: 'variable',
|
|
||||||
value,
|
|
||||||
variable: this.getVariableValue(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public toData() {
|
|
||||||
return cloneDeep(this.getMixValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
public getDefaultValue() {
|
|
||||||
return this.defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getHotValue() {
|
|
||||||
return this.hotValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getConfig<K extends keyof IPropConfig>(configName?: K): IPropConfig[K] | IPropConfig {
|
|
||||||
if (configName) {
|
|
||||||
return this.config[configName];
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.config;
|
|
||||||
}
|
|
||||||
|
|
||||||
public sync() {
|
|
||||||
if (this.props.hasReach(this)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { sync } = this.config;
|
|
||||||
if (sync) {
|
|
||||||
const value = sync.call(this as any, this.getValue(true));
|
|
||||||
if (value !== undefined) {
|
|
||||||
this.setValue(value);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// sync 的时候不再需要调用经过 accessor 处理之后的值了
|
|
||||||
// 这里之所以需要 setValue 是为了过 getValue() 中的 accessor 修饰函数
|
|
||||||
this.setValue(this.getValue(true), false, false, {
|
|
||||||
disableMutator: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public isUseVariable() {
|
|
||||||
return this.useVariable || false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public isSupportVariable() {
|
|
||||||
return this.config.supportVariable || false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public setVariableValue(value: string) {
|
|
||||||
if (!this.isUseVariable()) { return; }
|
|
||||||
|
|
||||||
const state = this.props.chainReach(this);
|
|
||||||
if (state === CHAIN_HAS_REACH) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.variableValue = value;
|
|
||||||
|
|
||||||
if (this.modify()) {
|
|
||||||
this.valueChange();
|
|
||||||
this.props.syncPass(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state === CHAIN_START) {
|
|
||||||
this.props.endChain();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public setUseVariable(flag = false) {
|
|
||||||
if (this.useVariable === flag) { return; }
|
|
||||||
|
|
||||||
const state = this.props.chainReach(this);
|
|
||||||
if (state === CHAIN_HAS_REACH) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.useVariable = flag;
|
|
||||||
this.expanded = true;
|
|
||||||
|
|
||||||
if (this.modify()) {
|
|
||||||
this.valueChange();
|
|
||||||
this.props.syncPass(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state === CHAIN_START) {
|
|
||||||
this.props.endChain();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.emitter.emit('ve.prop.useVariableChange', { isUseVariable: flag });
|
|
||||||
if (this.config.useVariableChange) {
|
|
||||||
this.config.useVariableChange.call(this as any, { isUseVariable: flag });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public getVariableValue() {
|
|
||||||
return this.variableValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param value
|
|
||||||
* @param isHotValue 是否为设计器热状态值
|
|
||||||
* @param force 是否强制触发更新
|
|
||||||
*/
|
|
||||||
public setValue(value: any, isHotValue?: boolean, force?: boolean, extraOptions?: ISetValueOptions) {
|
|
||||||
const state = this.props.chainReach(this);
|
|
||||||
if (state === CHAIN_HAS_REACH) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const preValue = this.value;
|
|
||||||
const preHotValue = this.hotValue;
|
|
||||||
|
|
||||||
if (isHotValue) {
|
|
||||||
this.hotValue = value;
|
|
||||||
this.value = this.transducer.toNative(this.hotValue);
|
|
||||||
} else {
|
|
||||||
if (!isDataEqual(value, this.value)) {
|
|
||||||
this.hotValue = this.transducer.toHot(value);
|
|
||||||
}
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.i18nLink = I18nUtil.attach(this, this.value, ((val: any) => this.setValue(val, false, true)) as any);
|
|
||||||
|
|
||||||
const { mutator } = this.config;
|
|
||||||
|
|
||||||
if (!extraOptions) {
|
|
||||||
extraOptions = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mutator && !extraOptions.disableMutator) {
|
|
||||||
mutator.call(this as any, this.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.modify(force)) {
|
|
||||||
this.valueChange(extraOptions);
|
|
||||||
this.props.syncPass(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state === CHAIN_START) {
|
|
||||||
this.props.endChain();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public setHotValue(hotValue: any, options?: ISetValueOptions) {
|
|
||||||
try {
|
|
||||||
this.setValue(hotValue, true, false, options);
|
|
||||||
} catch (e) {
|
|
||||||
logger.log('ERROR_PROP_VALUE');
|
|
||||||
logger.warn('属性值设置错误:', e, hotValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 验证是否存在变更
|
|
||||||
* @param force 是否强制返回已变更
|
|
||||||
*/
|
|
||||||
public modify(force?: boolean) {
|
|
||||||
const hotData = this.hotData.merge(fromJS({
|
|
||||||
hotValue: this.getHotValue(),
|
|
||||||
value: this.getMixValue(),
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (!force && hotData.equals(this.hotData)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.hotData = hotData;
|
|
||||||
|
|
||||||
(this.parent || this.props).modify(this.getName());
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public setHotData(hotData: IMMap<string, IHotDataMap>, options?: ISetValueOptions) {
|
|
||||||
if (!IMMap.isMap(hotData)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.hotData = hotData;
|
|
||||||
let value = hotData.get('value');
|
|
||||||
if (value && typeof value.toJS === 'function') {
|
|
||||||
value = value.toJS();
|
|
||||||
}
|
|
||||||
let hotValue = hotData.get('hotValue');
|
|
||||||
if (hotValue && typeof hotValue.toJS === 'function') {
|
|
||||||
hotValue = hotValue.toJS();
|
|
||||||
}
|
|
||||||
|
|
||||||
const preValue = value;
|
|
||||||
const preHotValue = hotValue;
|
|
||||||
|
|
||||||
this.value = value;
|
|
||||||
this.hotValue = hotValue;
|
|
||||||
this.resolveValue();
|
|
||||||
|
|
||||||
if (!options || !options.disableMutator) {
|
|
||||||
const { mutator } = this.config;
|
|
||||||
if (mutator) {
|
|
||||||
mutator.call(this as any, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.valueChange();
|
|
||||||
}
|
|
||||||
|
|
||||||
public valueChange(options?: ISetValueOptions) {
|
|
||||||
if (this.loopLock) { return; }
|
|
||||||
|
|
||||||
this.emitter.emit('valuechange', options);
|
|
||||||
if (this.parent) {
|
|
||||||
this.parent.valueChange(options);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public getDisplay() {
|
|
||||||
return this.config.display || this.config.fieldStyle || 'block';
|
|
||||||
}
|
|
||||||
|
|
||||||
public isHidden() {
|
|
||||||
if (!this.isInited() || this.getDisplay() === DISPLAY_TYPE.NONE || this.isDisabled()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
let { hidden } = this.config;
|
|
||||||
if (typeof hidden === 'function') {
|
|
||||||
hidden = hidden.call(this as any, this.getValue());
|
|
||||||
}
|
|
||||||
return hidden === true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public isDisabled() {
|
|
||||||
let { disabled } = this.config;
|
|
||||||
if (typeof disabled === 'function') {
|
|
||||||
disabled = disabled.call(this as any, this.getValue());
|
|
||||||
}
|
|
||||||
return disabled === true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public isIgnore() {
|
|
||||||
if (this.isDisabled()) { return true; }
|
|
||||||
|
|
||||||
let { ignore } = this.config;
|
|
||||||
if (typeof ignore === 'function') {
|
|
||||||
ignore = ignore.call(this as any, this.getValue());
|
|
||||||
}
|
|
||||||
return ignore === true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public isExpand() {
|
|
||||||
if (this.expanded == null) {
|
|
||||||
this.expanded = !(this.config.collapsed || this.config.fieldCollapsed);
|
|
||||||
}
|
|
||||||
return this.expanded;
|
|
||||||
}
|
|
||||||
|
|
||||||
public toggleExpand() {
|
|
||||||
if (this.expanded) {
|
|
||||||
this.expanded = false;
|
|
||||||
} else {
|
|
||||||
this.expanded = true;
|
|
||||||
}
|
|
||||||
this.emitter.emit('expandchange', this.expanded);
|
|
||||||
}
|
|
||||||
|
|
||||||
public getSetter() {
|
|
||||||
if (dynamicSetterProvider) {
|
|
||||||
const setter = dynamicSetterProvider.call(this, this, this.getNode().getPrototype());
|
|
||||||
if (setter) {
|
|
||||||
return setter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const setterConfig = this.config.setter;
|
|
||||||
if (typeof setterConfig === 'function' && !(setterConfig.prototype instanceof Component)) {
|
|
||||||
return (setterConfig as any).call(this, this.getValue());
|
|
||||||
}
|
|
||||||
if (Array.isArray(setterConfig)) {
|
|
||||||
let item;
|
|
||||||
for (item of setterConfig) {
|
|
||||||
if (item.condition?.call(this, this.getValue())) {
|
|
||||||
return item.setter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return setterConfig[0].setter;
|
|
||||||
}
|
|
||||||
return setterConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getSetterData(): any {
|
|
||||||
if (Array.isArray(this.config.setter)) {
|
|
||||||
let item;
|
|
||||||
for (item of this.config.setter) {
|
|
||||||
if (item.condition?.call(this, this.getValue())) {
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return this.config.setter[0];
|
|
||||||
}
|
|
||||||
return { };
|
|
||||||
}
|
|
||||||
|
|
||||||
public destroy() {
|
|
||||||
if (this.i18nLink) {
|
|
||||||
this.i18nLink.detach();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public onValueChange(func: () => any) {
|
|
||||||
this.emitter.on('valuechange', func);
|
|
||||||
return () => {
|
|
||||||
this.emitter.removeListener('valuechange', func);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public onExpandChange(func: () => any) {
|
|
||||||
this.emitter.on('expandchange', func);
|
|
||||||
return () => {
|
|
||||||
this.emitter.removeListener('expandchange', func);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public onUseVariableChange(func: (data: { isUseVariable: boolean }) => any) {
|
|
||||||
this.emitter.on('ve.prop.useVariableChange', func);
|
|
||||||
return () => {
|
|
||||||
this.emitter.removeListener('ve.prop.useVariableChange', func);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,52 +0,0 @@
|
|||||||
import {
|
|
||||||
isPlainObject,
|
|
||||||
} from '@ali/lowcode-utils';
|
|
||||||
import { isJSExpression, isJSSlot } from '@ali/lowcode-types';
|
|
||||||
import { Node } from '@ali/lowcode-designer';
|
|
||||||
import { engineConfig } from '@ali/lowcode-engine';
|
|
||||||
|
|
||||||
export function compatibleReducer(props: any, node: Node): any {
|
|
||||||
// 如果禁用了降级reducer,则不做处理
|
|
||||||
if (engineConfig.get('visionSettings.disableCompatibleReducer')) {
|
|
||||||
return props;
|
|
||||||
}
|
|
||||||
// 如果不是 vc 体系,不做这个兼容处理
|
|
||||||
if (!node.componentMeta.prototype) {
|
|
||||||
return props;
|
|
||||||
}
|
|
||||||
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,
|
|
||||||
slotParams: props.params,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (!props.events && isJSExpression(props)) {
|
|
||||||
return {
|
|
||||||
type: 'variable',
|
|
||||||
value: props.mock,
|
|
||||||
variable: props.value,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
const newProps: any = {};
|
|
||||||
Object.entries<any>(props).forEach(([key, val]) => {
|
|
||||||
// // TODO: 目前 dataSource 面板里既用到了 JSExpression,又用到了 variable,这里先都不处理,后面再重构
|
|
||||||
// if (key === 'dataSource') {
|
|
||||||
// newProps[key] = props[key];
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
newProps[key] = compatibleReducer(val, node);
|
|
||||||
});
|
|
||||||
return newProps;
|
|
||||||
}
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
import { Node } from '@ali/lowcode-engine';
|
|
||||||
import { hasOwnProperty, isPlainObject } from '@ali/lowcode-utils';
|
|
||||||
|
|
||||||
function isEmptyEvent(event: any) {
|
|
||||||
return event?.ignored === true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 在使用老版的 vu-events-property,会有空的事件描述,比如 onClick: { ignored: true } 的情况
|
|
||||||
*/
|
|
||||||
export function filterEmptyEventReducer(props: any, node: Node): any {
|
|
||||||
if (!props || !isPlainObject(props)) return props;
|
|
||||||
// 基于性能考虑,只过滤第一层
|
|
||||||
Object.keys(props).forEach(name => {
|
|
||||||
if (name.startsWith('on') && isEmptyEvent(props[name])) {
|
|
||||||
delete props[name];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return props;
|
|
||||||
}
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
import logger from '@ali/vu-logger';
|
|
||||||
import { Node, PropsReducerContext, designerCabin, engineConfig } from '@ali/lowcode-engine';
|
|
||||||
import { hasOwnProperty } from '@ali/lowcode-utils';
|
|
||||||
const { TransformStage } = designerCabin;
|
|
||||||
|
|
||||||
export function filterReducer(props: any, node: Node, ctx?: PropsReducerContext): any {
|
|
||||||
// 老的 vision 逻辑是 render 阶段不走 filter 逻辑
|
|
||||||
if (ctx?.stage === TransformStage.Render && !engineConfig.get('visionSettings.enableFilterReducerInRenderStage', false)) {
|
|
||||||
return props;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
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';
|
|
||||||
export * from './node-top-fixed-reducer';
|
|
||||||
export * from './reset-loop-default-value-reducer';
|
|
||||||
export * from './filter-empty-event';
|
|
||||||
@ -1,52 +0,0 @@
|
|||||||
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) {
|
|
||||||
// run initials
|
|
||||||
const newProps: any = {
|
|
||||||
...props,
|
|
||||||
};
|
|
||||||
if (newProps.fieldId) {
|
|
||||||
const { doc, fieldIds } = getCurrentFieldIds();
|
|
||||||
|
|
||||||
// 全局的关闭 uniqueIdChecker 信号,在 ve-utils 中实现
|
|
||||||
if (doc === node.document && fieldIds.indexOf(props.fieldId) >= 0 && !(window as any).__disable_unique_id_checker__) {
|
|
||||||
newProps.fieldId = undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const initials = node.componentMeta.getMetadata().experimental?.initials;
|
|
||||||
|
|
||||||
if (initials) {
|
|
||||||
initials.forEach(item => {
|
|
||||||
try {
|
|
||||||
// FIXME! item.name could be 'xxx.xxx'
|
|
||||||
const value = newProps[item.name];
|
|
||||||
// 几种不再进行 initial 计算的情况
|
|
||||||
// 1. name === 'fieldId' 并且已经有值
|
|
||||||
// 2. 结构为 JSExpression 并且带有 events 字段
|
|
||||||
if ((item.name === 'fieldId' && value) || (isJSExpression(value) && value.events)) {
|
|
||||||
if (newProps[item.name] && !node.props.has(item.name)) {
|
|
||||||
node.props.add(value, item.name, false);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
newProps[item.name] = item.initial(node as any, newProps[item.name]);
|
|
||||||
if (newProps[item.name] && !node.props.has(item.name)) {
|
|
||||||
node.props.add(value, item.name, false);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
if (hasOwnProperty(props, item.name)) {
|
|
||||||
newProps[item.name] = props[item.name];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return newProps;
|
|
||||||
}
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
import { editor } from '@ali/lowcode-engine';
|
|
||||||
import { Node } from '@ali/lowcode-designer';
|
|
||||||
|
|
||||||
export function liveLifecycleReducer(props: any, node: Node) {
|
|
||||||
// 如果不是 vc 体系,不做这个兼容处理
|
|
||||||
if (!node.componentMeta.prototype) {
|
|
||||||
return props;
|
|
||||||
}
|
|
||||||
// live 模式下解析 lifeCycles
|
|
||||||
if (node.isRoot() && props && props.lifeCycles) {
|
|
||||||
if (editor.get('designMode') === 'live') {
|
|
||||||
const lifeCycleMap = {
|
|
||||||
didMount: 'componentDidMount',
|
|
||||||
willUnmount: 'componentWillUnMount',
|
|
||||||
};
|
|
||||||
const { lifeCycles } = props;
|
|
||||||
Object.keys(lifeCycleMap).forEach(key => {
|
|
||||||
if (lifeCycles[key]) {
|
|
||||||
lifeCycles[lifeCycleMap[key]] = lifeCycles[key];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return props;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
...props,
|
|
||||||
lifeCycles: {},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return props;
|
|
||||||
}
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
import { Node } from '@ali/lowcode-designer';
|
|
||||||
|
|
||||||
export function nodeTopFixedReducer(props: any, node: Node) {
|
|
||||||
if (node.componentMeta.isTopFixed) {
|
|
||||||
return {
|
|
||||||
...props,
|
|
||||||
// experimental prop value
|
|
||||||
__isTopFixed__: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return props;
|
|
||||||
}
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
import {
|
|
||||||
cloneDeep,
|
|
||||||
} from '@ali/lowcode-utils';
|
|
||||||
import { Node } from '@ali/lowcode-designer';
|
|
||||||
|
|
||||||
// 清除空的 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;
|
|
||||||
}
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
// 讲loop=[]的情况处理成loop=false
|
|
||||||
export function resetLoopDefaultValueReducer(props: any) {
|
|
||||||
if (props.loop && Array.isArray(props.loop) && props.loop.length === 0) {
|
|
||||||
return {
|
|
||||||
...props,
|
|
||||||
loop: undefined,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return props;
|
|
||||||
}
|
|
||||||
@ -1,85 +0,0 @@
|
|||||||
import { project } from '@ali/lowcode-engine';
|
|
||||||
import { isPlainObject, css } from '@ali/lowcode-utils';
|
|
||||||
|
|
||||||
const { toCss } = css;
|
|
||||||
|
|
||||||
export function stylePropsReducer(props: any, node: any) {
|
|
||||||
let cssId;
|
|
||||||
let cssClass;
|
|
||||||
let styleProp;
|
|
||||||
if (!props || typeof props !== 'object') return props;
|
|
||||||
if (props.__style__) {
|
|
||||||
cssId = `_style_pseudo_${node.id.replace(/\$/g, '_')}`;
|
|
||||||
cssClass = `_css_pseudo_${node.id.replace(/\$/g, '_')}`;
|
|
||||||
styleProp = props.__style__;
|
|
||||||
appendStyleNode(props, styleProp, cssClass, cssId);
|
|
||||||
props.className = cssClass;
|
|
||||||
}
|
|
||||||
if (props.pageStyle) {
|
|
||||||
cssId = '_style_pseudo_engine-document';
|
|
||||||
cssClass = 'engine-document';
|
|
||||||
styleProp = props.pageStyle;
|
|
||||||
appendStyleNode(props, styleProp, cssClass, cssId);
|
|
||||||
props.className = cssClass;
|
|
||||||
}
|
|
||||||
if (props.containerStyle) {
|
|
||||||
cssId = `_style_pseudo_${node.id}`;
|
|
||||||
cssClass = `_css_pseudo_${node.id.replace(/\$/g, '_')}`;
|
|
||||||
styleProp = props.containerStyle;
|
|
||||||
appendStyleNode(props, styleProp, cssClass, cssId);
|
|
||||||
props.className = cssClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
return props;
|
|
||||||
}
|
|
||||||
|
|
||||||
function appendStyleNode(props: any, styleProp: any, cssClass: string, cssId: string) {
|
|
||||||
const doc = project.simulator?.contentDocument;
|
|
||||||
|
|
||||||
if (!doc) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (isPlainObject(styleProp)) {
|
|
||||||
styleProp = isEmptyObject(styleProp) ? '' : toCss(styleProp);
|
|
||||||
}
|
|
||||||
if (typeof styleProp === 'string' && styleProp) {
|
|
||||||
const dom = doc.getElementById(cssId) as HTMLStyleElement;
|
|
||||||
const newStyleStr = transformStyleStr(styleProp, cssClass);
|
|
||||||
if (!dom) {
|
|
||||||
const s = doc.createElement('style');
|
|
||||||
s.setAttribute('type', 'text/css');
|
|
||||||
s.setAttribute('id', cssId);
|
|
||||||
doc.getElementsByTagName('head')[0].appendChild(s);
|
|
||||||
s.appendChild(doc.createTextNode(newStyleStr));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!stringEquals(dom.innerHTML!, newStyleStr)) {
|
|
||||||
dom.innerHTML = newStyleStr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function isEmptyObject(obj: any) {
|
|
||||||
if (!isPlainObject(obj)) return false;
|
|
||||||
let empty = true;
|
|
||||||
for (let k in obj) {
|
|
||||||
empty = false;
|
|
||||||
}
|
|
||||||
return empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
function stringEquals(str: string, targetStr: string): boolean {
|
|
||||||
return removeWhitespace(str) === removeWhitespace(targetStr);
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeWhitespace(str: string = ''): string {
|
|
||||||
return str.replace(/\s/g, '');
|
|
||||||
}
|
|
||||||
|
|
||||||
function transformStyleStr(styleStr: string = '', cssClass: string): string {
|
|
||||||
return styleStr
|
|
||||||
.replace(/(\d+)rpx/g, (all, num) => {
|
|
||||||
return `${num / 2}px`;
|
|
||||||
})
|
|
||||||
.replace(/:root/g, `.${cssClass}`);
|
|
||||||
}
|
|
||||||
@ -1,54 +0,0 @@
|
|||||||
import { Node } from '@ali/lowcode-designer';
|
|
||||||
import { isPlainObject, isVariable } from '@ali/lowcode-utils';
|
|
||||||
import { isJSBlock } from '@ali/lowcode-types';
|
|
||||||
import { designerCabin } from '@ali/lowcode-engine';
|
|
||||||
|
|
||||||
const { getConvertedExtraKey } = designerCabin;
|
|
||||||
|
|
||||||
export function upgradePropsReducer(props: any): 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function upgradePageLifeCyclesReducer(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;
|
|
||||||
}
|
|
||||||
@ -1,82 +0,0 @@
|
|||||||
import Env from '../env';
|
|
||||||
import { Node } from '@ali/lowcode-designer';
|
|
||||||
import { isJSSlot, isI18nData, isJSExpression } from '@ali/lowcode-types';
|
|
||||||
import { isPlainObject } from '@ali/lowcode-utils';
|
|
||||||
import i18nUtil from '../i18n-util';
|
|
||||||
import { editor } from '@ali/lowcode-engine';
|
|
||||||
import { isVariable } from '../utils';
|
|
||||||
|
|
||||||
// FIXME: 表达式使用 mock 值,未来live 模式直接使用原始值
|
|
||||||
// TODO: designType
|
|
||||||
export function valueParser(obj: any, node: Node): any {
|
|
||||||
return deepValueParser(obj, {
|
|
||||||
node,
|
|
||||||
path: '',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function deepValueParser(obj: any, info: {
|
|
||||||
node: Node;
|
|
||||||
path?: string;
|
|
||||||
}): any {
|
|
||||||
const {
|
|
||||||
path = '',
|
|
||||||
node,
|
|
||||||
} = info;
|
|
||||||
// 如果不是 vc 体系,不做这个兼容处理
|
|
||||||
if (!node.componentMeta.prototype) {
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
if (isJSExpression(obj)) {
|
|
||||||
if (editor.get('designMode') === 'live') {
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
obj = obj.mock;
|
|
||||||
}
|
|
||||||
// 兼容 ListSetter 中的变量结构
|
|
||||||
if (isVariable(obj)) {
|
|
||||||
if (editor.get('designMode') === 'live') {
|
|
||||||
return {
|
|
||||||
type: 'JSExpression',
|
|
||||||
value: obj.variable,
|
|
||||||
mock: obj.value,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
obj = obj.value;
|
|
||||||
}
|
|
||||||
if (!obj) {
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
if (Array.isArray(obj)) {
|
|
||||||
return obj.map((item) => deepValueParser(item, { node }));
|
|
||||||
}
|
|
||||||
if (isPlainObject(obj)) {
|
|
||||||
if (isI18nData(obj)) {
|
|
||||||
// FIXME! use editor.get
|
|
||||||
let locale = Env.getLocale();
|
|
||||||
if (obj.key && i18nUtil.get(obj.key, locale)) {
|
|
||||||
return i18nUtil.get(obj.key, locale, {
|
|
||||||
node,
|
|
||||||
path,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (locale !== 'zh_CN' && locale !== 'zh_TW' && !obj[locale]) {
|
|
||||||
locale = 'en_US';
|
|
||||||
}
|
|
||||||
return obj[obj.use || locale] || obj.zh_CN;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isJSSlot(obj)) {
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
const out: any = {};
|
|
||||||
Object.keys(obj).forEach((key) => {
|
|
||||||
out[key] = deepValueParser(obj[key], {
|
|
||||||
node,
|
|
||||||
path: path ? `${path}.${key}` : key,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
@ -1,67 +0,0 @@
|
|||||||
import { editor, designer, designerCabin } from '@ali/lowcode-engine';
|
|
||||||
import bus from './bus';
|
|
||||||
import { VE_EVENTS } from './base/const';
|
|
||||||
|
|
||||||
import { valueParser } from './props-reducers/value-parser';
|
|
||||||
import { liveEditingRule, liveEditingSaveHander } from './vc-live-editing';
|
|
||||||
import {
|
|
||||||
compatibleReducer,
|
|
||||||
upgradePageLifeCyclesReducer,
|
|
||||||
stylePropsReducer,
|
|
||||||
upgradePropsReducer,
|
|
||||||
filterReducer,
|
|
||||||
removeEmptyPropsReducer,
|
|
||||||
initNodeReducer,
|
|
||||||
liveLifecycleReducer,
|
|
||||||
nodeTopFixedReducer,
|
|
||||||
resetLoopDefaultValueReducer,
|
|
||||||
filterEmptyEventReducer,
|
|
||||||
} from './props-reducers';
|
|
||||||
|
|
||||||
const { LiveEditing, TransformStage } = designerCabin;
|
|
||||||
|
|
||||||
// 清理引擎自带的规则和保存函数,会影响 vc i18n 的保存
|
|
||||||
LiveEditing.clearLiveEditingSpecificRule();
|
|
||||||
LiveEditing.clearLiveEditingSaveHandler();
|
|
||||||
LiveEditing.addLiveEditingSpecificRule(liveEditingRule);
|
|
||||||
LiveEditing.addLiveEditingSaveHandler(liveEditingSaveHander);
|
|
||||||
|
|
||||||
designer.project.onCurrentDocumentChange((doc) => {
|
|
||||||
bus.emit(VE_EVENTS.VE_PAGE_PAGE_READY);
|
|
||||||
editor.set('currentDocument', doc);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 升级 Props
|
|
||||||
designer.addPropsReducer(upgradePropsReducer, TransformStage.Upgrade);
|
|
||||||
|
|
||||||
// 节点 props 初始化
|
|
||||||
designer.addPropsReducer(initNodeReducer, TransformStage.Init);
|
|
||||||
|
|
||||||
designer.addPropsReducer(liveLifecycleReducer, TransformStage.Render);
|
|
||||||
|
|
||||||
designer.addPropsReducer(filterReducer, TransformStage.Save);
|
|
||||||
designer.addPropsReducer(filterReducer, TransformStage.Render);
|
|
||||||
|
|
||||||
designer.addPropsReducer(filterEmptyEventReducer, TransformStage.Save);
|
|
||||||
designer.addPropsReducer(filterEmptyEventReducer, TransformStage.Render);
|
|
||||||
|
|
||||||
// FIXME: Dirty fix, will remove this reducer
|
|
||||||
designer.addPropsReducer(compatibleReducer, TransformStage.Save);
|
|
||||||
// 兼容历史版本的 Page 组件
|
|
||||||
designer.addPropsReducer(upgradePageLifeCyclesReducer, TransformStage.Save);
|
|
||||||
|
|
||||||
// 设计器组件样式处理
|
|
||||||
designer.addPropsReducer(stylePropsReducer, TransformStage.Render);
|
|
||||||
// 国际化 & Expression 渲染时处理
|
|
||||||
designer.addPropsReducer(valueParser, TransformStage.Render);
|
|
||||||
|
|
||||||
// Init 的时候没有拿到 dataSource, 只能在 Render 和 Save 的时候都调用一次,理论上执行时机在 Init
|
|
||||||
// Render 和 Save 都要各调用一次,感觉也是有问题的,是不是应该在 Render 执行一次就行了?见上 filterReducer 也是一样的处理方式。
|
|
||||||
designer.addPropsReducer(removeEmptyPropsReducer, TransformStage.Render);
|
|
||||||
designer.addPropsReducer(removeEmptyPropsReducer, TransformStage.Save);
|
|
||||||
|
|
||||||
designer.addPropsReducer(nodeTopFixedReducer, TransformStage.Render);
|
|
||||||
designer.addPropsReducer(nodeTopFixedReducer, TransformStage.Save);
|
|
||||||
|
|
||||||
// loop的默认值处理
|
|
||||||
designer.addPropsReducer(resetLoopDefaultValueReducer, TransformStage.Save);
|
|
||||||
@ -1,95 +0,0 @@
|
|||||||
import { findIndex } from 'lodash';
|
|
||||||
import { DocumentModel, Node, RootNode } from '@ali/lowcode-designer';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* RootNodeVisitor for VisualEngine Page
|
|
||||||
*
|
|
||||||
* - store / cache node
|
|
||||||
* - quickly find / search or do operations on Node
|
|
||||||
*/
|
|
||||||
export default class RootNodeVisitor {
|
|
||||||
public nodeIdMap: {[id: string]: Node} = {};
|
|
||||||
|
|
||||||
public nodeFieldIdMap: {[fieldId: string]: Node} = {};
|
|
||||||
|
|
||||||
public nodeList: Node[] = [];
|
|
||||||
|
|
||||||
private page: DocumentModel;
|
|
||||||
|
|
||||||
private root: RootNode;
|
|
||||||
|
|
||||||
private cancelers: Function[] = [];
|
|
||||||
|
|
||||||
constructor(page: DocumentModel, rootNode: RootNode) {
|
|
||||||
this.page = page;
|
|
||||||
this.root = rootNode;
|
|
||||||
|
|
||||||
this._findNode(this.root);
|
|
||||||
this._init();
|
|
||||||
}
|
|
||||||
|
|
||||||
public getNodeList() {
|
|
||||||
return this.nodeList;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getNodeIdMap() {
|
|
||||||
return this.nodeIdMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getNodeFieldIdMap() {
|
|
||||||
return this.nodeFieldIdMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getNodeById(id?: string) {
|
|
||||||
if (!id) { return this.nodeIdMap; }
|
|
||||||
return this.nodeIdMap[id];
|
|
||||||
}
|
|
||||||
|
|
||||||
public getNodeByFieldId(fieldId?: string) {
|
|
||||||
if (!fieldId) { return this.nodeFieldIdMap; }
|
|
||||||
return this.nodeFieldIdMap[fieldId];
|
|
||||||
}
|
|
||||||
|
|
||||||
public destroy() {
|
|
||||||
this.cancelers.forEach((canceler) => canceler());
|
|
||||||
}
|
|
||||||
|
|
||||||
private _init() {
|
|
||||||
this.cancelers.push(
|
|
||||||
this.page.onNodeCreate((node) => {
|
|
||||||
this.nodeList.push(node);
|
|
||||||
this.nodeIdMap[node.id] = node;
|
|
||||||
if (node.getPropValue('fieldId')) {
|
|
||||||
this.nodeFieldIdMap[node.getPropValue('fieldId')] = node;
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
this.cancelers.push(
|
|
||||||
this.page.onNodeDestroy((node) => {
|
|
||||||
const idx = findIndex(this.nodeList, (n) => node.id === n.id);
|
|
||||||
this.nodeList.splice(idx, 1);
|
|
||||||
delete this.nodeIdMap[node.id];
|
|
||||||
if (node.getPropValue('fieldId')) {
|
|
||||||
delete this.nodeFieldIdMap[node.getPropValue('fieldId')];
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _findNode(node: Node) {
|
|
||||||
const props = node.getProps();
|
|
||||||
const fieldId = props && props.getPropValue('fieldId');
|
|
||||||
|
|
||||||
this.nodeIdMap[node.getId()] = node;
|
|
||||||
this.nodeList.push(node);
|
|
||||||
if (fieldId) {
|
|
||||||
this.nodeFieldIdMap[fieldId] = node;
|
|
||||||
}
|
|
||||||
|
|
||||||
const children = node.getChildren();
|
|
||||||
if (children) {
|
|
||||||
children.forEach((child) => this._findNode(child));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
export class SymbolManager {
|
|
||||||
private symbolMap: { [symbolName: string]: symbol } = {};
|
|
||||||
|
|
||||||
public create(name: string): symbol {
|
|
||||||
if (this.symbolMap[name]) {
|
|
||||||
return this.symbolMap[name];
|
|
||||||
}
|
|
||||||
this.symbolMap[name] = Symbol(name);
|
|
||||||
return this.symbolMap[name];
|
|
||||||
}
|
|
||||||
|
|
||||||
public get(name: string) {
|
|
||||||
return this.symbolMap[name];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default new SymbolManager();
|
|
||||||
@ -1,21 +0,0 @@
|
|||||||
import { designer } from '@ali/lowcode-engine';
|
|
||||||
export { isVariable } from '@ali/lowcode-utils';
|
|
||||||
|
|
||||||
export 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 { doc: designer?.currentDocument, fieldIds };
|
|
||||||
}
|
|
||||||
|
|
||||||
export function invariant(check: any, message: string, thing?: any) {
|
|
||||||
if (!check) {
|
|
||||||
throw new Error(`Invariant failed: ${ message }${thing ? ` in '${thing}'` : ''}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,116 +0,0 @@
|
|||||||
import { EditingTarget, Node as DocNode, SaveHandler } from '@ali/lowcode-designer';
|
|
||||||
import Env from './env';
|
|
||||||
import { isJSExpression, isI18nData } from '@ali/lowcode-types';
|
|
||||||
import i18nUtil from './i18n-util';
|
|
||||||
|
|
||||||
interface I18nObject {
|
|
||||||
type?: string;
|
|
||||||
use?: string;
|
|
||||||
key?: string;
|
|
||||||
[lang: string]: string | undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getI18nText(obj: I18nObject) {
|
|
||||||
let locale = Env.getLocale();
|
|
||||||
if (obj.key) {
|
|
||||||
return i18nUtil.get(obj.key, locale);
|
|
||||||
}
|
|
||||||
if (locale !== 'zh_CN' && locale !== 'zh_TW' && !obj[locale]) {
|
|
||||||
locale = 'en_US';
|
|
||||||
}
|
|
||||||
return obj[obj.use || locale] || obj.zh_CN;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getText(node: DocNode, prop: string) {
|
|
||||||
const p = node.getProp(prop, false);
|
|
||||||
if (!p || p.isUnset()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
let v = p.getValue();
|
|
||||||
if (isJSExpression(v)) {
|
|
||||||
v = v.mock;
|
|
||||||
}
|
|
||||||
if (v == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (p.type === 'literal') {
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
if ((v as any).type === 'i18n') {
|
|
||||||
return getI18nText(v as any);
|
|
||||||
}
|
|
||||||
return Symbol.for('not-literal');
|
|
||||||
}
|
|
||||||
|
|
||||||
export function liveEditingRule(target: EditingTarget) {
|
|
||||||
// for vision components specific
|
|
||||||
const { node, rootElement, event } = target;
|
|
||||||
|
|
||||||
const targetElement = event.target as HTMLElement;
|
|
||||||
|
|
||||||
if (!Array.from(targetElement.childNodes).every(item => item.nodeType === Node.TEXT_NODE)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { innerText } = targetElement;
|
|
||||||
const propTarget = ['title', 'label', 'text', 'content', 'children'].find(prop => {
|
|
||||||
return equalText(getText(node, prop), innerText);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (propTarget) {
|
|
||||||
return {
|
|
||||||
propElement: targetElement,
|
|
||||||
propTarget,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function equalText(v: any, innerText: string) {
|
|
||||||
// TODO: enhance compare text logic
|
|
||||||
if (typeof v !== 'string') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return v.trim() === innerText;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const liveEditingSaveHander: SaveHandler = {
|
|
||||||
condition: (prop) => {
|
|
||||||
const v = prop.getValue();
|
|
||||||
return prop.type === 'expression' || isI18nData(v);
|
|
||||||
},
|
|
||||||
onSaveContent: (content, prop) => {
|
|
||||||
const v = prop.getValue();
|
|
||||||
const locale = Env.getLocale();
|
|
||||||
let data = v;
|
|
||||||
if (isJSExpression(v)) {
|
|
||||||
data = v.mock;
|
|
||||||
}
|
|
||||||
if (isI18nData(data)) {
|
|
||||||
const i18n = data.key ? i18nUtil.getItem(data.key) : null;
|
|
||||||
if (i18n) {
|
|
||||||
i18n.setDoc(content, locale);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
data = {
|
|
||||||
...(data as any),
|
|
||||||
[locale]: content,
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
data = content;
|
|
||||||
}
|
|
||||||
if (isJSExpression(v)) {
|
|
||||||
prop.setValue({
|
|
||||||
type: 'JSExpression',
|
|
||||||
value: v.value,
|
|
||||||
mock: data,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
prop.setValue(data);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
// TODO:
|
|
||||||
// 非文本编辑
|
|
||||||
// 国际化数据,改变当前
|
|
||||||
// JSExpression, 改变 mock 或 弹出绑定变量
|
|
||||||
@ -1,289 +0,0 @@
|
|||||||
import { EventEmitter } from 'events';
|
|
||||||
import Flags from './flags';
|
|
||||||
import { editor } from '@ali/lowcode-engine';
|
|
||||||
|
|
||||||
const domReady = require('domready');
|
|
||||||
|
|
||||||
function enterFullscreen() {
|
|
||||||
const elem = document.documentElement;
|
|
||||||
if (elem.requestFullscreen) {
|
|
||||||
elem.requestFullscreen();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function exitFullscreen() {
|
|
||||||
if (document.exitFullscreen) {
|
|
||||||
document.exitFullscreen();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function isFullscreen() {
|
|
||||||
return document.fullscreen || false;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IStyleResourceConfig {
|
|
||||||
media?: string;
|
|
||||||
type?: string;
|
|
||||||
content?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
class StyleResource {
|
|
||||||
config: IStyleResourceConfig;
|
|
||||||
|
|
||||||
styleElement: HTMLStyleElement;
|
|
||||||
|
|
||||||
mounted: boolean;
|
|
||||||
|
|
||||||
inited: boolean;
|
|
||||||
|
|
||||||
constructor(config: IStyleResourceConfig) {
|
|
||||||
this.config = config || {};
|
|
||||||
}
|
|
||||||
|
|
||||||
matchDevice(device: string) {
|
|
||||||
const { media } = this.config;
|
|
||||||
|
|
||||||
if (!media || media === 'ALL' || media === '*') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return media.toUpperCase() === device.toUpperCase();
|
|
||||||
}
|
|
||||||
|
|
||||||
init() {
|
|
||||||
if (this.inited) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.inited = true;
|
|
||||||
|
|
||||||
const { type, content } = this.config;
|
|
||||||
let styleElement: any;
|
|
||||||
if (type === 'URL') {
|
|
||||||
styleElement = document.createElement('link');
|
|
||||||
styleElement.href = content || '';
|
|
||||||
styleElement.rel = 'stylesheet';
|
|
||||||
} else {
|
|
||||||
styleElement = document.createElement('style');
|
|
||||||
styleElement.setAttribute('type', 'text/css');
|
|
||||||
if (styleElement.styleSheet) {
|
|
||||||
styleElement.styleSheet.cssText = content;
|
|
||||||
} else {
|
|
||||||
styleElement.appendChild(document.createTextNode(content || ''));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.styleElement = styleElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
apply() {
|
|
||||||
if (this.mounted) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.init();
|
|
||||||
document.head.appendChild(this.styleElement);
|
|
||||||
this.mounted = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
unmount() {
|
|
||||||
if (!this.mounted) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
document.head.removeChild(this.styleElement);
|
|
||||||
this.mounted = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Viewport {
|
|
||||||
preview: boolean;
|
|
||||||
|
|
||||||
focused: boolean;
|
|
||||||
|
|
||||||
slateFixed: boolean;
|
|
||||||
|
|
||||||
emitter: EventEmitter;
|
|
||||||
|
|
||||||
device: string;
|
|
||||||
|
|
||||||
focusTarget: any;
|
|
||||||
|
|
||||||
cssResourceSet: StyleResource[];
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.preview = false;
|
|
||||||
this.emitter = new EventEmitter();
|
|
||||||
document.addEventListener('webkitfullscreenchange', () => {
|
|
||||||
this.emitter.emit('fullscreenchange', this.isFullscreen());
|
|
||||||
});
|
|
||||||
domReady(() => this.applyMediaCSS());
|
|
||||||
}
|
|
||||||
|
|
||||||
setFullscreen(flag: boolean) {
|
|
||||||
const fullscreen = this.isFullscreen();
|
|
||||||
if (fullscreen && !flag) {
|
|
||||||
exitFullscreen();
|
|
||||||
} else if (!fullscreen && flag) {
|
|
||||||
enterFullscreen();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleFullscreen() {
|
|
||||||
if (this.isFullscreen()) {
|
|
||||||
exitFullscreen();
|
|
||||||
} else {
|
|
||||||
enterFullscreen();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
isFullscreen() {
|
|
||||||
return isFullscreen();
|
|
||||||
}
|
|
||||||
|
|
||||||
setFocus(flag: boolean) {
|
|
||||||
if (this.focused && !flag) {
|
|
||||||
this.focused = false;
|
|
||||||
Flags.remove('view-focused');
|
|
||||||
this.emitter.emit('focuschange', false);
|
|
||||||
} else if (!this.focused && flag) {
|
|
||||||
this.focused = true;
|
|
||||||
Flags.add('view-focused');
|
|
||||||
this.emitter.emit('focuschange', true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setFocusTarget(focusTarget: any) {
|
|
||||||
this.focusTarget = focusTarget;
|
|
||||||
}
|
|
||||||
|
|
||||||
returnFocus() {
|
|
||||||
if (this.focusTarget) {
|
|
||||||
this.focusTarget.focus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
isFocus() {
|
|
||||||
return this.focused;
|
|
||||||
}
|
|
||||||
|
|
||||||
setPreview(flag: boolean) {
|
|
||||||
if (this.preview && !flag) {
|
|
||||||
this.preview = false;
|
|
||||||
Flags.setPreviewMode(false);
|
|
||||||
this.emitter.emit('preview', false);
|
|
||||||
this.changeViewport();
|
|
||||||
} else if (!this.preview && flag) {
|
|
||||||
this.preview = true;
|
|
||||||
Flags.setPreviewMode(true);
|
|
||||||
this.emitter.emit('preview', true);
|
|
||||||
this.changeViewport();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
togglePreview() {
|
|
||||||
if (this.isPreview()) {
|
|
||||||
this.setPreview(false);
|
|
||||||
} else {
|
|
||||||
this.setPreview(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
isPreview() {
|
|
||||||
return this.preview;
|
|
||||||
}
|
|
||||||
|
|
||||||
async setDevice(device = 'pc') {
|
|
||||||
if (this.getDevice() !== device) {
|
|
||||||
this.device = device;
|
|
||||||
const simulator = await editor.onceGot('simulator');
|
|
||||||
simulator?.set('device', device === 'mobile' ? 'mobile' : 'default');
|
|
||||||
// Flags.setSimulator(device);
|
|
||||||
// this.applyMediaCSS();
|
|
||||||
this.emitter.emit('devicechange', device);
|
|
||||||
this.changeViewport();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getDevice() {
|
|
||||||
return this.device || 'pc';
|
|
||||||
}
|
|
||||||
|
|
||||||
changeViewport() {
|
|
||||||
this.emitter.emit('viewportchange', this.getViewport());
|
|
||||||
}
|
|
||||||
|
|
||||||
getViewport() {
|
|
||||||
return `${this.isPreview() ? 'preview' : 'design'}-${this.getDevice()}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
applyMediaCSS() {
|
|
||||||
if (!document.head || !this.cssResourceSet) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const device = this.getDevice();
|
|
||||||
this.cssResourceSet.forEach((item) => {
|
|
||||||
if (item.matchDevice(device)) {
|
|
||||||
item.apply();
|
|
||||||
} else {
|
|
||||||
item.unmount();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setGlobalCSS(resourceSet: IStyleResourceConfig[]) {
|
|
||||||
if (this.cssResourceSet) {
|
|
||||||
this.cssResourceSet.forEach((item) => {
|
|
||||||
item.unmount();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.cssResourceSet = resourceSet.map((item: IStyleResourceConfig) => new StyleResource(item)).reverse();
|
|
||||||
this.applyMediaCSS();
|
|
||||||
}
|
|
||||||
|
|
||||||
setWithShell(shell: string) {
|
|
||||||
// Flags.setWithShell(shell);
|
|
||||||
}
|
|
||||||
|
|
||||||
onFullscreenChange(func: () => any) {
|
|
||||||
this.emitter.on('fullscreenchange', func);
|
|
||||||
return () => {
|
|
||||||
this.emitter.removeListener('fullscreenchange', func);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
onPreview(func: () => any) {
|
|
||||||
this.emitter.on('preview', func);
|
|
||||||
return () => {
|
|
||||||
this.emitter.removeListener('preview', func);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
onDeviceChange(func: () => any) {
|
|
||||||
this.emitter.on('devicechange', func);
|
|
||||||
return () => {
|
|
||||||
this.emitter.removeListener('devicechange', func);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
onSlateFixedChange(func: (flag: boolean) => any) {
|
|
||||||
this.emitter.on('slatefixed', func);
|
|
||||||
return () => {
|
|
||||||
this.emitter.removeListener('slatefixed', func);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
onViewportChange(func: () => any) {
|
|
||||||
this.emitter.on('viewportchange', func);
|
|
||||||
return () => {
|
|
||||||
this.emitter.removeListener('viewportchange', func);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
onFocusChange(func: (flag: boolean) => any) {
|
|
||||||
this.emitter.on('focuschange', func);
|
|
||||||
return () => {
|
|
||||||
this.emitter.removeListener('focuschange', func);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default new Viewport();
|
|
||||||
@ -1,128 +0,0 @@
|
|||||||
html.engine-cursor-move, html.engine-cursor-move * {
|
|
||||||
cursor: grabbing !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
html.engine-cursor-copy, html.engine-cursor-copy * {
|
|
||||||
cursor: copy !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
html.engine-cursor-ew-resize, html.engine-cursor-ew-resize * {
|
|
||||||
cursor: ew-resize !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
body, #engine {
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
top: 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
text-rendering: optimizeLegibility;
|
|
||||||
-webkit-user-select: none;
|
|
||||||
-webkit-user-drag: none;
|
|
||||||
-webkit-text-size-adjust: none;
|
|
||||||
-webkit-touch-callout: none;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
}
|
|
||||||
|
|
||||||
html {
|
|
||||||
min-width: 1024px;
|
|
||||||
}
|
|
||||||
|
|
||||||
::-webkit-scrollbar {
|
|
||||||
width: 5px;
|
|
||||||
height: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
::-webkit-scrollbar-thumb {
|
|
||||||
background-color: rgba(0, 0, 0, 0.3);
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
html.engine-blur #engine {
|
|
||||||
filter: blur(4px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.engine-main {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
position: absolute;
|
|
||||||
|
|
||||||
.ve-icon-button {
|
|
||||||
> .ve-icon-contents {
|
|
||||||
color: var(--color-text, rgba(51,51,51,.6));
|
|
||||||
}
|
|
||||||
&:hover, &.active {
|
|
||||||
> .ve-icon-contents {
|
|
||||||
color: var(--color-text-light, rgba(51,51,51,.8));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.engine-empty {
|
|
||||||
background: #f2f3f5;
|
|
||||||
color: #a7b1bd;
|
|
||||||
outline: 1px dashed rgba(31, 56, 88, 0.2);
|
|
||||||
outline-offset: -1px !important;
|
|
||||||
height: 66px;
|
|
||||||
max-height: 100%;
|
|
||||||
min-width: 140px;
|
|
||||||
text-align: center;
|
|
||||||
overflow: hidden;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.engine-empty:before {
|
|
||||||
content: '\62D6\62FD\7EC4\4EF6\6216\6A21\677F\5230\8FD9\91CC';
|
|
||||||
font-size: 14px;
|
|
||||||
z-index: 1;
|
|
||||||
width: 100%;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// dirty fix override vision reset
|
|
||||||
.engine-design-mode {
|
|
||||||
.next-input-group,
|
|
||||||
.next-checkbox-group,.next-date-picker,.next-input,.next-month-picker,
|
|
||||||
.next-number-picker,.next-radio-group,.next-range,.next-range-picker,
|
|
||||||
.next-rating,.next-select,.next-switch,.next-time-picker,.next-upload,
|
|
||||||
.next-year-picker,
|
|
||||||
.next-breadcrumb-item,.next-calendar-header,.next-calendar-table {
|
|
||||||
pointer-events: auto !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.vs-icon .vs-icon-del, .vs-icon .vs-icon-entry {
|
|
||||||
width: 16px!important;
|
|
||||||
height: 16px!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
// .lc-left-float-pane {
|
|
||||||
// font-size: 14px;
|
|
||||||
// }
|
|
||||||
|
|
||||||
html.engine-preview-mode {
|
|
||||||
.lc-left-area, .lc-right-area {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.ve-popups .ve-message {
|
|
||||||
right: calc(var(--right-area-width, 300px) + 10px);
|
|
||||||
|
|
||||||
.ve-message-content {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
line-height: 22px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.lc-setter-mixed {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
@ -1,116 +0,0 @@
|
|||||||
import { Component } from 'react';
|
|
||||||
import set from 'lodash/set';
|
|
||||||
import cloneDeep from 'lodash/clonedeep';
|
|
||||||
import '../fixtures/window';
|
|
||||||
import divPrototypeConfig from '../fixtures/prototype/div-vision';
|
|
||||||
import trunk from '../../src/bundle/trunk';
|
|
||||||
import Prototype from '../../src/bundle/prototype';
|
|
||||||
import Bundle from '../../src/bundle/bundle';
|
|
||||||
import { Editor } from '@ali/lowcode-editor-core';
|
|
||||||
|
|
||||||
jest.mock('../../src/bundle/trunk', () => {
|
|
||||||
// mockComponentPrototype = jest.fn();
|
|
||||||
// return {
|
|
||||||
// mockComponentPrototype: jest.fn().mockImplementation(() => {
|
|
||||||
// return proto;
|
|
||||||
// }),
|
|
||||||
// }
|
|
||||||
// return jest.fn().mockImplementation(() => {
|
|
||||||
// return {playSoundFile: fakePlaySoundFile};
|
|
||||||
// });
|
|
||||||
// return jest.fn().mockImplementation(() => {
|
|
||||||
// return { mockComponentPrototype };
|
|
||||||
// });
|
|
||||||
return {
|
|
||||||
__esModule: true,
|
|
||||||
default: {
|
|
||||||
mockComponentPrototype: jest.fn(),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
function wrap(name, thing) {
|
|
||||||
return {
|
|
||||||
name,
|
|
||||||
componentName: name,
|
|
||||||
category: '布局',
|
|
||||||
module: thing,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const proto1 = new Prototype(divPrototypeConfig);
|
|
||||||
const protoConfig2 = cloneDeep(divPrototypeConfig);
|
|
||||||
set(protoConfig2, 'componentName', 'Div2');
|
|
||||||
const proto2 = new Prototype(protoConfig2);
|
|
||||||
|
|
||||||
const protoConfig3 = cloneDeep(divPrototypeConfig);
|
|
||||||
set(protoConfig3, 'componentName', 'Div3');
|
|
||||||
const proto3 = new Prototype(protoConfig3);
|
|
||||||
|
|
||||||
const protoConfig4 = cloneDeep(divPrototypeConfig);
|
|
||||||
set(protoConfig4, 'componentName', 'Div4');
|
|
||||||
const proto4 = new Prototype(protoConfig4);
|
|
||||||
|
|
||||||
const protoConfig5 = cloneDeep(divPrototypeConfig);
|
|
||||||
set(protoConfig5, 'componentName', 'Div5');
|
|
||||||
const proto5 = new Prototype(protoConfig5);
|
|
||||||
|
|
||||||
function getComponentProtos() {
|
|
||||||
return [
|
|
||||||
wrap('Div', proto1),
|
|
||||||
// wrap('Div2', proto2),
|
|
||||||
// wrap('Div3', proto3),
|
|
||||||
wrap('DivPortal', [proto2, proto3]),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
class Div extends Component {}
|
|
||||||
Div.displayName = 'Div';
|
|
||||||
class Div2 extends Component {}
|
|
||||||
Div2.displayName = 'Div2';
|
|
||||||
class Div3 extends Component {}
|
|
||||||
Div3.displayName = 'Div3';
|
|
||||||
class Div4 extends Component {}
|
|
||||||
Div4.displayName = 'Div4';
|
|
||||||
class Div5 extends Component {}
|
|
||||||
Div5.displayName = 'Div5';
|
|
||||||
|
|
||||||
function getComponentViews() {
|
|
||||||
return [
|
|
||||||
wrap('Div', Div),
|
|
||||||
// wrap('Div2', Div2),
|
|
||||||
// wrap('Div3', Div3),
|
|
||||||
wrap('DivPortal', [Div2, Div3]),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('Bundle', () => {
|
|
||||||
it('构造函数', () => {
|
|
||||||
const protos = getComponentProtos();
|
|
||||||
const views = getComponentViews();
|
|
||||||
const bundle = new Bundle(protos, views);
|
|
||||||
expect(bundle.getList()).toHaveLength(3);
|
|
||||||
expect(bundle.get('Div')).toBe(proto1);
|
|
||||||
expect(bundle.get('Div2')).toBe(proto2);
|
|
||||||
expect(bundle.get('Div3')).toBe(proto3);
|
|
||||||
bundle.addComponentBundle([proto4, Div4]);
|
|
||||||
expect(bundle.getList()).toHaveLength(4);
|
|
||||||
expect(bundle.get('Div4')).toBe(proto4);
|
|
||||||
bundle.replacePrototype('Div4', proto3);
|
|
||||||
expect(proto3.getView()).toBe(Div4);
|
|
||||||
|
|
||||||
bundle.removeComponentBundle('Div2');
|
|
||||||
expect(bundle.getList()).toHaveLength(3);
|
|
||||||
expect(bundle.get('Div2')).toBeUndefined;
|
|
||||||
|
|
||||||
expect(bundle.getFromMeta('Div')).toBe(proto1);
|
|
||||||
bundle.getFromMeta('Div5');
|
|
||||||
expect(bundle.getList()).toHaveLength(4);
|
|
||||||
});
|
|
||||||
it('静态方法 create', () => {
|
|
||||||
const protos = getComponentProtos();
|
|
||||||
const views = getComponentViews();
|
|
||||||
const bundle = Bundle.create(protos, views);
|
|
||||||
expect(bundle).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,219 +0,0 @@
|
|||||||
import { Component } from 'react';
|
|
||||||
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 divFullPrototypeConfig from '../fixtures/prototype/div-vision-full';
|
|
||||||
import divPrototypeMeta from '../fixtures/prototype/div-meta';
|
|
||||||
// import VisualEngine from '../../src';
|
|
||||||
import { designer } from '../../src/reducers';
|
|
||||||
import Prototype, { isPrototype } 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(isPrototype(proto)).toBeTruthy;
|
|
||||||
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('构造函数 - 全量 OldPrototypeConfig', () => {
|
|
||||||
const proto = new Prototype(divFullPrototypeConfig);
|
|
||||||
expect(isPrototype(proto)).toBeTruthy;
|
|
||||||
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);
|
|
||||||
});
|
|
||||||
describe('类成员函数', () => {
|
|
||||||
let proto: Prototype = null;
|
|
||||||
beforeEach(() => {
|
|
||||||
proto = new Prototype(divPrototypeConfig);
|
|
||||||
});
|
|
||||||
afterEach(() => {
|
|
||||||
proto = null;
|
|
||||||
});
|
|
||||||
it('各种函数', () => {
|
|
||||||
expect(proto.componentName).toBe('Div');
|
|
||||||
expect(proto.getComponentName()).toBe('Div');
|
|
||||||
expect(proto.getId()).toBe('Div');
|
|
||||||
expect(proto.getContextInfo('anything')).toBeUndefined;
|
|
||||||
expect(proto.getPropConfigs()).toBe(divPrototypeConfig);
|
|
||||||
expect(proto.getConfig()).toBe(divPrototypeConfig);
|
|
||||||
expect(proto.getConfig('componentName')).toBe('Div');
|
|
||||||
expect(proto.getConfig('configure')).toBe(divPrototypeConfig.configure);
|
|
||||||
expect(proto.getConfig('docUrl')).toBe(
|
|
||||||
'http://gitlab.alibaba-inc.com/vision-components/vc-block/blob/master/README.md',
|
|
||||||
);
|
|
||||||
expect(proto.getConfig('title')).toBe('容器');
|
|
||||||
expect(proto.getConfig('isContainer')).toBeTruthy;
|
|
||||||
|
|
||||||
class MockView extends Component {}
|
|
||||||
|
|
||||||
expect(proto.getView()).toBeUndefined;
|
|
||||||
proto.setView(MockView);
|
|
||||||
expect(proto.getView()).toBe(MockView);
|
|
||||||
expect(proto.meta.getMetadata().experimental?.view).toBe(MockView);
|
|
||||||
|
|
||||||
expect(proto.getPackageName()).toBeUndefined;
|
|
||||||
proto.setPackageName('@ali/vc-div');
|
|
||||||
expect(proto.getPackageName()).toBe('@ali/vc-div');
|
|
||||||
|
|
||||||
expect(proto.getConfig('category')).toBe('布局');
|
|
||||||
proto.setCategory('布局 new');
|
|
||||||
expect(proto.getConfig('category')).toBe('布局 new');
|
|
||||||
|
|
||||||
expect(proto.getConfigure()).toHaveLength(3);
|
|
||||||
expect(proto.getConfigure()[0].name).toBe('#props');
|
|
||||||
expect(proto.getConfigure()[1].name).toBe('#styles');
|
|
||||||
expect(proto.getConfigure()[2].name).toBe('#advanced');
|
|
||||||
|
|
||||||
expect(proto.getRectSelector()).toBeUndefined;
|
|
||||||
expect(proto.isAutoGenerated()).toBeFalsy;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('类成员函数', () => {
|
|
||||||
it('addGlobalPropsConfigure', () => {
|
|
||||||
Prototype.addGlobalPropsConfigure({
|
|
||||||
name: 'globalInsertProp1',
|
|
||||||
});
|
|
||||||
const proto1 = new Prototype(divPrototypeConfig);
|
|
||||||
expect(proto1.getConfigure()[2].items).toHaveLength(4);
|
|
||||||
expect(proto1.getConfigure()[2].items[3].name).toBe('globalInsertProp1');
|
|
||||||
Prototype.addGlobalPropsConfigure({
|
|
||||||
name: 'globalInsertProp2',
|
|
||||||
});
|
|
||||||
const proto2 = new Prototype(divPrototypeConfig);
|
|
||||||
expect(proto2.getConfigure()[2].items).toHaveLength(5);
|
|
||||||
expect(proto1.getConfigure()[2].items[4].name).toBe('globalInsertProp2');
|
|
||||||
|
|
||||||
Prototype.addGlobalPropsConfigure({
|
|
||||||
name: 'globalInsertProp3',
|
|
||||||
position: 'top',
|
|
||||||
});
|
|
||||||
|
|
||||||
const proto3 = new Prototype(divPrototypeConfig);
|
|
||||||
expect(proto3.getConfigure()[0].items).toHaveLength(3);
|
|
||||||
expect(proto1.getConfigure()[0].items[0].name).toBe('globalInsertProp3');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('removeGlobalPropsConfigure', () => {
|
|
||||||
Prototype.removeGlobalPropsConfigure('globalInsertProp1');
|
|
||||||
Prototype.removeGlobalPropsConfigure('globalInsertProp2');
|
|
||||||
Prototype.removeGlobalPropsConfigure('globalInsertProp3');
|
|
||||||
const proto2 = new Prototype(divPrototypeConfig);
|
|
||||||
expect(proto2.getConfigure()[0].items).toHaveLength(2);
|
|
||||||
expect(proto2.getConfigure()[2].items).toHaveLength(3);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('overridePropsConfigure', () => {
|
|
||||||
Prototype.addGlobalPropsConfigure({
|
|
||||||
name: 'globalInsertProp1',
|
|
||||||
title: 'globalInsertPropTitle',
|
|
||||||
position: 'top',
|
|
||||||
});
|
|
||||||
const proto1 = new Prototype(divPrototypeConfig);
|
|
||||||
expect(proto1.getConfigure()[0].items).toHaveLength(3);
|
|
||||||
expect(proto1.getConfigure()[0].items[0].name).toBe('globalInsertProp1');
|
|
||||||
expect(proto1.getConfigure()[0].items[0].title).toBe('globalInsertPropTitle');
|
|
||||||
|
|
||||||
Prototype.overridePropsConfigure('Div', [
|
|
||||||
{
|
|
||||||
name: 'globalInsertProp1',
|
|
||||||
title: 'globalInsertPropTitleChanged',
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
const proto2 = new Prototype(divPrototypeConfig);
|
|
||||||
expect(proto2.getConfigure()[0].name).toBe('globalInsertProp1');
|
|
||||||
expect(proto2.getConfigure()[0].title).toBe('globalInsertPropTitleChanged');
|
|
||||||
|
|
||||||
Prototype.overridePropsConfigure('Div', {
|
|
||||||
globalInsertProp1: {
|
|
||||||
name: 'globalInsertProp1',
|
|
||||||
title: 'globalInsertPropTitleChanged new',
|
|
||||||
position: 'top',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const proto3 = new Prototype(divPrototypeConfig);
|
|
||||||
expect(proto3.getConfigure()[0].items[0].name).toBe('globalInsertProp1');
|
|
||||||
expect(proto3.getConfigure()[0].items[0].title).toBe('globalInsertPropTitleChanged new');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('addGlobalExtraActions', () => {
|
|
||||||
function haha() { return 'heihei'; }
|
|
||||||
Prototype.addGlobalExtraActions(haha);
|
|
||||||
const proto1 = new Prototype(divPrototypeConfig);
|
|
||||||
expect(proto1.meta.availableActions).toHaveLength(4);
|
|
||||||
expect(proto1.meta.availableActions[3].name).toBe('haha');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,111 +0,0 @@
|
|||||||
import { Component } from 'react';
|
|
||||||
import set from 'lodash/set';
|
|
||||||
import cloneDeep from 'lodash/clonedeep';
|
|
||||||
import '../fixtures/window';
|
|
||||||
import divPrototypeConfig from '../fixtures/prototype/div-vision';
|
|
||||||
import Prototype from '../../src/bundle/prototype';
|
|
||||||
import Bundle from '../../src/bundle/bundle';
|
|
||||||
import trunk from '../../src/bundle/trunk';
|
|
||||||
import lg from '@ali/vu-logger';
|
|
||||||
|
|
||||||
const proto1 = new Prototype(divPrototypeConfig);
|
|
||||||
const protoConfig2 = cloneDeep(divPrototypeConfig);
|
|
||||||
set(protoConfig2, 'componentName', 'Div2');
|
|
||||||
const proto2 = new Prototype(protoConfig2);
|
|
||||||
|
|
||||||
const protoConfig3 = cloneDeep(divPrototypeConfig);
|
|
||||||
set(protoConfig3, 'componentName', 'Div3');
|
|
||||||
const proto3 = new Prototype(protoConfig3);
|
|
||||||
|
|
||||||
const mockComponentPrototype = jest.fn();
|
|
||||||
jest.mock('../../src/bundle/bundle', () => {
|
|
||||||
// return {
|
|
||||||
// mockComponentPrototype: jest.fn().mockImplementation(() => {
|
|
||||||
// return proto;
|
|
||||||
// }),
|
|
||||||
// }
|
|
||||||
// return jest.fn().mockImplementation(() => {
|
|
||||||
// return {playSoundFile: fakePlaySoundFile};
|
|
||||||
// });
|
|
||||||
return jest.fn().mockImplementation(() => {
|
|
||||||
return {
|
|
||||||
get: () => {},
|
|
||||||
getList: () => { return []; },
|
|
||||||
getFromMeta: () => {},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const mockError = jest.fn();
|
|
||||||
jest.mock('@ali/vu-logger');
|
|
||||||
lg.error = mockError;
|
|
||||||
|
|
||||||
function wrap(name, thing) {
|
|
||||||
return {
|
|
||||||
name,
|
|
||||||
componentName: name,
|
|
||||||
category: '布局',
|
|
||||||
module: thing,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getComponentProtos() {
|
|
||||||
return [
|
|
||||||
wrap('Div', proto1),
|
|
||||||
// wrap('Div2', proto2),
|
|
||||||
// wrap('Div3', proto3),
|
|
||||||
wrap('DivPortal', [proto2, proto3]),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
class Div extends Component {}
|
|
||||||
Div.displayName = 'Div';
|
|
||||||
class Div2 extends Component {}
|
|
||||||
Div2.displayName = 'Div2';
|
|
||||||
class Div3 extends Component {}
|
|
||||||
Div3.displayName = 'Div3';
|
|
||||||
|
|
||||||
function getComponentViews() {
|
|
||||||
return [
|
|
||||||
wrap('Div', Div),
|
|
||||||
// wrap('Div2', Div2),
|
|
||||||
// wrap('Div3', Div3),
|
|
||||||
wrap('DivPortal', [Div2, Div3]),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('Trunk', () => {
|
|
||||||
it('构造函数', () => {
|
|
||||||
const warn = console.warn = jest.fn();
|
|
||||||
const trunkChangeHandler = jest.fn();
|
|
||||||
const off = trunk.onTrunkChange(trunkChangeHandler);
|
|
||||||
trunk.addBundle(new Bundle([proto1], [Div]));
|
|
||||||
trunk.addBundle(new Bundle([proto2], [Div2]));
|
|
||||||
expect(trunkChangeHandler).toHaveBeenCalledTimes(2);
|
|
||||||
off();
|
|
||||||
trunk.addBundle(new Bundle([proto3], [Div3]));
|
|
||||||
expect(trunkChangeHandler).toHaveBeenCalledTimes(2);
|
|
||||||
trunk.getList();
|
|
||||||
trunk.getPrototype('Div');
|
|
||||||
trunk.getPrototypeById('Div');
|
|
||||||
trunk.getPrototypeView('Div');
|
|
||||||
trunk.listByCategory();
|
|
||||||
expect(trunk.mockComponentPrototype(new Bundle([proto3], [Div3]))).toBeUndefined;
|
|
||||||
expect(mockError).toHaveBeenCalled();
|
|
||||||
trunk.registerComponentPrototypeMocker({ mockPrototype: jest.fn().mockImplementation(() => { return proto3; }) });
|
|
||||||
expect(trunk.mockComponentPrototype(new Bundle([proto3], [Div3]))).toBe(proto3);
|
|
||||||
const hahaSetter = () => 'haha';
|
|
||||||
trunk.registerSetter('haha', hahaSetter);
|
|
||||||
expect(trunk.getSetter('haha')).toBe(hahaSetter);
|
|
||||||
trunk.getRecents(5);
|
|
||||||
trunk.setPackages();
|
|
||||||
expect(warn).toHaveBeenCalledTimes(1);
|
|
||||||
trunk.beforeLoadBundle();
|
|
||||||
expect(warn).toHaveBeenCalledTimes(2);
|
|
||||||
trunk.afterLoadBundle();
|
|
||||||
expect(warn).toHaveBeenCalledTimes(3);
|
|
||||||
trunk.getBundle();
|
|
||||||
expect(warn).toHaveBeenCalledTimes(4);
|
|
||||||
expect(trunk.isReady()).toBeTruthy;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,259 +0,0 @@
|
|||||||
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: [],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@ -1,293 +0,0 @@
|
|||||||
export default {
|
|
||||||
title: '容器',
|
|
||||||
componentName: 'Div',
|
|
||||||
docUrl: 'http://gitlab.alibaba-inc.com/vision-components/vc-block/blob/master/README.md',
|
|
||||||
category: '布局',
|
|
||||||
isContainer: true,
|
|
||||||
canOperating: false,
|
|
||||||
extraActions: [],
|
|
||||||
canContain: 'Form',
|
|
||||||
canDropTo: 'Div',
|
|
||||||
canDropIn: 'Div',
|
|
||||||
canResizing: true,
|
|
||||||
canDraging: false,
|
|
||||||
context: {},
|
|
||||||
initialChildren() {},
|
|
||||||
didDropIn() {},
|
|
||||||
didDropOut() {},
|
|
||||||
subtreeModified() {},
|
|
||||||
onResize() {},
|
|
||||||
onResizeStart() {},
|
|
||||||
onResizeEnd() {},
|
|
||||||
canUseCondition: true,
|
|
||||||
canLoop: true,
|
|
||||||
snippets: [
|
|
||||||
{
|
|
||||||
screenshot: 'https://img.alicdn.com/tfs/TB1CHN3u4z1gK0jSZSgXXavwpXa-112-64.png',
|
|
||||||
label: '普通型',
|
|
||||||
schema: {
|
|
||||||
componentName: 'Div',
|
|
||||||
props: {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
configure: [
|
|
||||||
{
|
|
||||||
name: 'myName',
|
|
||||||
title: '我的名字',
|
|
||||||
display: 'tab',
|
|
||||||
initialValue: 'NORMAL',
|
|
||||||
defaultValue: 'NORMAL',
|
|
||||||
collapsed: true,
|
|
||||||
supportVariable: true,
|
|
||||||
accessor(field, val) {},
|
|
||||||
mutator(field, val) {},
|
|
||||||
disabled() {
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
useVariableChange() {},
|
|
||||||
allowTextInput: true,
|
|
||||||
liveTextEditing: true,
|
|
||||||
setter: [
|
|
||||||
{
|
|
||||||
key: null,
|
|
||||||
ref: null,
|
|
||||||
props: {
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
title: '普通',
|
|
||||||
value: 'NORMAL',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '隐藏',
|
|
||||||
value: 'HIDDEN',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
loose: false,
|
|
||||||
cancelable: false,
|
|
||||||
},
|
|
||||||
_owner: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: null,
|
|
||||||
ref: null,
|
|
||||||
props: {
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
title: '普通',
|
|
||||||
value: 'NORMAL',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '隐藏',
|
|
||||||
value: 'HIDDEN',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
loose: false,
|
|
||||||
cancelable: false,
|
|
||||||
},
|
|
||||||
_owner: null,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'mySlotName',
|
|
||||||
slotName: 'mySlotName',
|
|
||||||
slotTitle: '我的 Slot 名字',
|
|
||||||
display: 'tab',
|
|
||||||
initialValue: 'NORMAL',
|
|
||||||
defaultValue: 'NORMAL',
|
|
||||||
collapsed: true,
|
|
||||||
supportVariable: true,
|
|
||||||
accessor(field, val) {},
|
|
||||||
mutator(field, val) {},
|
|
||||||
disabled() {
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
setter: {
|
|
||||||
key: null,
|
|
||||||
ref: null,
|
|
||||||
props: {
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
title: '普通',
|
|
||||||
value: 'NORMAL',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '隐藏',
|
|
||||||
value: 'HIDDEN',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
loose: false,
|
|
||||||
cancelable: false,
|
|
||||||
},
|
|
||||||
_owner: null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
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,175 +0,0 @@
|
|||||||
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,955 +0,0 @@
|
|||||||
export default {
|
|
||||||
componentName: 'Page',
|
|
||||||
id: 'node_k1ow3cb9',
|
|
||||||
props: {
|
|
||||||
extensions: {
|
|
||||||
启用页头: true,
|
|
||||||
},
|
|
||||||
pageStyle: {
|
|
||||||
backgroundColor: '#f2f3f5',
|
|
||||||
},
|
|
||||||
containerStyle: {},
|
|
||||||
className: 'page_kh05zf9c',
|
|
||||||
templateVersion: '1.0.0',
|
|
||||||
},
|
|
||||||
lifeCycles: {
|
|
||||||
constructor: {
|
|
||||||
type: 'js',
|
|
||||||
compiled:
|
|
||||||
"function constructor() {\nvar module = { exports: {} };\nvar _this = this;\nthis.__initMethods__(module.exports, module);\nObject.keys(module.exports).forEach(function(item) {\n if(typeof module.exports[item] === 'function'){\n _this[item] = module.exports[item];\n }\n});\n\n}",
|
|
||||||
source:
|
|
||||||
"function constructor() {\nvar module = { exports: {} };\nvar _this = this;\nthis.__initMethods__(module.exports, module);\nObject.keys(module.exports).forEach(function(item) {\n if(typeof module.exports[item] === 'function'){\n _this[item] = module.exports[item];\n }\n});\n\n}",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
condition: true,
|
|
||||||
css:
|
|
||||||
'body{background-color:#f2f3f5}.card_kh05zf9d {\n margin-bottom: 12px;\n}.card_kh05zf9e {\n margin-bottom: 12px;\n}.button_kh05zf9f {\n margin-right: 16px;\n width: 80px\n}.button_kh05zf9g {\n width: 80px;\n}.div_kh05zf9h {\n display: flex;\n align-items: flex-start;\n justify-content: center;\n background: #fff;\n padding: 20px 0;\n}',
|
|
||||||
methods: {
|
|
||||||
__initMethods__: {
|
|
||||||
type: 'js',
|
|
||||||
source: 'function (exports, module) { /*set actions code here*/ }',
|
|
||||||
compiled: 'function (exports, module) { /*set actions code here*/ }',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
dataSource: {
|
|
||||||
offline: [],
|
|
||||||
globalConfig: {
|
|
||||||
fit: {
|
|
||||||
compiled: '',
|
|
||||||
source: '',
|
|
||||||
type: 'js',
|
|
||||||
error: {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
online: [],
|
|
||||||
sync: true,
|
|
||||||
list: [],
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
componentName: 'RootHeader',
|
|
||||||
id: 'node_k1ow3cba',
|
|
||||||
props: {},
|
|
||||||
condition: true,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
componentName: 'PageHeader',
|
|
||||||
id: 'node_k1ow3cbd',
|
|
||||||
props: {
|
|
||||||
extraContent: '',
|
|
||||||
__slot__extraContent: false,
|
|
||||||
__slot__action: false,
|
|
||||||
title: '',
|
|
||||||
content: '',
|
|
||||||
__slot__logo: false,
|
|
||||||
__slot__crumb: false,
|
|
||||||
crumb: '',
|
|
||||||
tab: '',
|
|
||||||
logo: '',
|
|
||||||
action: '',
|
|
||||||
__slot__tab: false,
|
|
||||||
__style__: {},
|
|
||||||
__slot__content: false,
|
|
||||||
fieldId: 'pageHeader_k1ow3h1i',
|
|
||||||
subTitle: '',
|
|
||||||
},
|
|
||||||
condition: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
componentName: 'RootContent',
|
|
||||||
id: 'node_k1ow3cbb',
|
|
||||||
props: {
|
|
||||||
contentBgColor: 'transparent',
|
|
||||||
contentPadding: '0',
|
|
||||||
contentMargin: '20',
|
|
||||||
},
|
|
||||||
condition: true,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
componentName: 'Form',
|
|
||||||
id: 'form',
|
|
||||||
props: {
|
|
||||||
size: 'medium',
|
|
||||||
labelAlign: 'top',
|
|
||||||
autoValidate: true,
|
|
||||||
scrollToFirstError: true,
|
|
||||||
autoUnmount: true,
|
|
||||||
behavior: 'NORMAL',
|
|
||||||
dataSource: {
|
|
||||||
type: 'variable',
|
|
||||||
variable: 'state.formData',
|
|
||||||
},
|
|
||||||
__style__: {},
|
|
||||||
fieldId: 'form',
|
|
||||||
fieldOptions: {},
|
|
||||||
},
|
|
||||||
condition: true,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
componentName: 'Card',
|
|
||||||
id: 'node_k1ow3cbj',
|
|
||||||
props: {
|
|
||||||
__slot__title: false,
|
|
||||||
subTitle: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
en_US: '',
|
|
||||||
zh_CN: '',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
__slot__subTitle: false,
|
|
||||||
extra: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
zh_CN: '',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
className: 'card_kh05zf9d',
|
|
||||||
title: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
en_US: 'Title',
|
|
||||||
zh_CN: '基本信息',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
__slot__extra: false,
|
|
||||||
showHeadDivider: true,
|
|
||||||
__style__: ':root {\n margin-bottom: 12px;\n}',
|
|
||||||
showTitleBullet: true,
|
|
||||||
contentHeight: '',
|
|
||||||
fieldId: 'card_k1ow3h1l',
|
|
||||||
dividerNoInset: false,
|
|
||||||
},
|
|
||||||
condition: true,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
componentName: 'CardContent',
|
|
||||||
id: 'node_k1ow3cbk',
|
|
||||||
props: {},
|
|
||||||
condition: true,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
componentName: 'ColumnsLayout',
|
|
||||||
id: 'node_k1ow3cbw',
|
|
||||||
props: {
|
|
||||||
layout: '4:8',
|
|
||||||
columnGap: '20',
|
|
||||||
rowGap: 0,
|
|
||||||
__style__: {},
|
|
||||||
fieldId: 'columns_k1ow3h1v',
|
|
||||||
},
|
|
||||||
condition: true,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
componentName: 'Column',
|
|
||||||
id: 'node_k1ow3cbx',
|
|
||||||
props: {
|
|
||||||
colSpan: '',
|
|
||||||
__style__: {},
|
|
||||||
fieldId: 'column_k1p1bnjm',
|
|
||||||
},
|
|
||||||
condition: true,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
componentName: 'TextField',
|
|
||||||
id: 'node_k1ow3cbz',
|
|
||||||
props: {
|
|
||||||
fieldName: 'name',
|
|
||||||
hasClear: false,
|
|
||||||
autoFocus: false,
|
|
||||||
tips: {
|
|
||||||
en_US: '',
|
|
||||||
zh_CN: '',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
trim: false,
|
|
||||||
labelTextAlign: 'right',
|
|
||||||
placeholder: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
en_US: 'please input',
|
|
||||||
zh_CN: '请输入',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
state: '',
|
|
||||||
behavior: 'NORMAL',
|
|
||||||
value: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
zh_CN: '',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
addonBefore: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
zh_CN: '',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
validation: [
|
|
||||||
{
|
|
||||||
type: 'required',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
hasLimitHint: false,
|
|
||||||
cutString: false,
|
|
||||||
__style__: {},
|
|
||||||
fieldId: 'textField_k1ow3h1w',
|
|
||||||
htmlType: 'input',
|
|
||||||
autoHeight: false,
|
|
||||||
labelColOffset: 0,
|
|
||||||
label: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
en_US: 'TextField',
|
|
||||||
zh_CN: '姓名',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
__category__: 'form',
|
|
||||||
labelColSpan: 4,
|
|
||||||
wrapperColSpan: 0,
|
|
||||||
rows: 4,
|
|
||||||
addonAfter: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
zh_CN: '',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
wrapperColOffset: 0,
|
|
||||||
size: 'medium',
|
|
||||||
labelAlign: 'top',
|
|
||||||
__useMediator: 'value',
|
|
||||||
labelTipsTypes: 'none',
|
|
||||||
labelTipsIcon: '',
|
|
||||||
labelTipsText: {
|
|
||||||
type: 'i18n',
|
|
||||||
use: 'zh_CN',
|
|
||||||
en_US: '',
|
|
||||||
zh_CN: '',
|
|
||||||
},
|
|
||||||
maxLength: 200,
|
|
||||||
},
|
|
||||||
condition: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
componentName: 'TextField',
|
|
||||||
id: 'node_k1ow3cc1',
|
|
||||||
props: {
|
|
||||||
fieldName: 'englishName',
|
|
||||||
hasClear: false,
|
|
||||||
autoFocus: false,
|
|
||||||
tips: {
|
|
||||||
en_US: '',
|
|
||||||
zh_CN: '',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
trim: false,
|
|
||||||
labelTextAlign: 'right',
|
|
||||||
placeholder: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
en_US: 'please input',
|
|
||||||
zh_CN: '请输入',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
state: '',
|
|
||||||
behavior: 'NORMAL',
|
|
||||||
value: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
zh_CN: '',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
addonBefore: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
zh_CN: '',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
validation: [],
|
|
||||||
hasLimitHint: false,
|
|
||||||
cutString: false,
|
|
||||||
__style__: {},
|
|
||||||
fieldId: 'textField_k1ow3h1y',
|
|
||||||
htmlType: 'input',
|
|
||||||
autoHeight: false,
|
|
||||||
labelColOffset: 0,
|
|
||||||
label: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
en_US: 'TextField',
|
|
||||||
zh_CN: '英文名',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
__category__: 'form',
|
|
||||||
labelColSpan: 4,
|
|
||||||
wrapperColSpan: 0,
|
|
||||||
rows: 4,
|
|
||||||
addonAfter: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
zh_CN: '',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
wrapperColOffset: 0,
|
|
||||||
size: 'medium',
|
|
||||||
labelAlign: 'top',
|
|
||||||
__useMediator: 'value',
|
|
||||||
labelTipsTypes: 'none',
|
|
||||||
labelTipsIcon: '',
|
|
||||||
labelTipsText: {
|
|
||||||
type: 'i18n',
|
|
||||||
use: 'zh_CN',
|
|
||||||
en_US: '',
|
|
||||||
zh_CN: '',
|
|
||||||
},
|
|
||||||
maxLength: 200,
|
|
||||||
},
|
|
||||||
condition: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
componentName: 'TextField',
|
|
||||||
id: 'node_k1ow3cc3',
|
|
||||||
props: {
|
|
||||||
fieldName: 'jobTitle',
|
|
||||||
hasClear: false,
|
|
||||||
autoFocus: false,
|
|
||||||
tips: {
|
|
||||||
en_US: '',
|
|
||||||
zh_CN: '',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
trim: false,
|
|
||||||
labelTextAlign: 'right',
|
|
||||||
placeholder: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
en_US: 'please input',
|
|
||||||
zh_CN: '请输入',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
state: '',
|
|
||||||
behavior: 'NORMAL',
|
|
||||||
value: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
zh_CN: '',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
addonBefore: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
zh_CN: '',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
validation: [],
|
|
||||||
hasLimitHint: false,
|
|
||||||
cutString: false,
|
|
||||||
__style__: {},
|
|
||||||
fieldId: 'textField_k1ow3h20',
|
|
||||||
htmlType: 'input',
|
|
||||||
autoHeight: false,
|
|
||||||
labelColOffset: 0,
|
|
||||||
label: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
en_US: 'TextField',
|
|
||||||
zh_CN: '职位',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
__category__: 'form',
|
|
||||||
labelColSpan: 4,
|
|
||||||
wrapperColSpan: 0,
|
|
||||||
rows: 4,
|
|
||||||
addonAfter: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
zh_CN: '',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
wrapperColOffset: 0,
|
|
||||||
size: 'medium',
|
|
||||||
labelAlign: 'top',
|
|
||||||
__useMediator: 'value',
|
|
||||||
labelTipsTypes: 'none',
|
|
||||||
labelTipsIcon: '',
|
|
||||||
labelTipsText: {
|
|
||||||
type: 'i18n',
|
|
||||||
use: 'zh_CN',
|
|
||||||
en_US: '',
|
|
||||||
zh_CN: '',
|
|
||||||
},
|
|
||||||
maxLength: 200,
|
|
||||||
},
|
|
||||||
condition: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
componentName: 'Column',
|
|
||||||
id: 'node_k1ow3cby',
|
|
||||||
props: {
|
|
||||||
colSpan: '',
|
|
||||||
__style__: {},
|
|
||||||
fieldId: 'column_k1p1bnjn',
|
|
||||||
},
|
|
||||||
condition: true,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
componentName: 'TextField',
|
|
||||||
id: 'node_k1ow3cc2',
|
|
||||||
props: {
|
|
||||||
fieldName: 'nickName',
|
|
||||||
hasClear: false,
|
|
||||||
autoFocus: false,
|
|
||||||
tips: {
|
|
||||||
en_US: '',
|
|
||||||
zh_CN: '',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
trim: false,
|
|
||||||
labelTextAlign: 'right',
|
|
||||||
placeholder: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
en_US: 'please input',
|
|
||||||
zh_CN: '请输入',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
state: '',
|
|
||||||
behavior: 'NORMAL',
|
|
||||||
value: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
zh_CN: '',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
addonBefore: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
zh_CN: '',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
validation: [],
|
|
||||||
hasLimitHint: false,
|
|
||||||
cutString: false,
|
|
||||||
__style__: {},
|
|
||||||
fieldId: 'textField_k1ow3h1z',
|
|
||||||
htmlType: 'input',
|
|
||||||
autoHeight: false,
|
|
||||||
labelColOffset: 0,
|
|
||||||
label: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
en_US: 'TextField',
|
|
||||||
zh_CN: '花名',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
__category__: 'form',
|
|
||||||
labelColSpan: 4,
|
|
||||||
wrapperColSpan: 0,
|
|
||||||
rows: 4,
|
|
||||||
addonAfter: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
zh_CN: '',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
wrapperColOffset: 0,
|
|
||||||
size: 'medium',
|
|
||||||
labelAlign: 'top',
|
|
||||||
__useMediator: 'value',
|
|
||||||
labelTipsTypes: 'none',
|
|
||||||
labelTipsIcon: '',
|
|
||||||
labelTipsText: {
|
|
||||||
type: 'i18n',
|
|
||||||
use: 'zh_CN',
|
|
||||||
en_US: '',
|
|
||||||
zh_CN: '',
|
|
||||||
},
|
|
||||||
maxLength: 200,
|
|
||||||
},
|
|
||||||
condition: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
componentName: 'SelectField',
|
|
||||||
id: 'node_k1ow3cc0',
|
|
||||||
props: {
|
|
||||||
fieldName: 'gender',
|
|
||||||
hasClear: false,
|
|
||||||
tips: {
|
|
||||||
en_US: '',
|
|
||||||
zh_CN: '',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
mode: 'single',
|
|
||||||
showSearch: false,
|
|
||||||
autoWidth: true,
|
|
||||||
labelTextAlign: 'right',
|
|
||||||
placeholder: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
en_US: 'please select',
|
|
||||||
zh_CN: '请选择',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
hasBorder: true,
|
|
||||||
behavior: 'NORMAL',
|
|
||||||
value: '',
|
|
||||||
validation: [
|
|
||||||
{
|
|
||||||
type: 'required',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
__style__: {},
|
|
||||||
fieldId: 'select_k1ow3h1x',
|
|
||||||
notFoundContent: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
labelColOffset: 0,
|
|
||||||
label: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
en_US: 'SelectField',
|
|
||||||
zh_CN: '性别',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
__category__: 'form',
|
|
||||||
labelColSpan: 4,
|
|
||||||
wrapperColSpan: 0,
|
|
||||||
wrapperColOffset: 0,
|
|
||||||
hasSelectAll: false,
|
|
||||||
hasArrow: true,
|
|
||||||
size: 'medium',
|
|
||||||
labelAlign: 'top',
|
|
||||||
filterLocal: true,
|
|
||||||
dataSource: [
|
|
||||||
{
|
|
||||||
defaultChecked: false,
|
|
||||||
text: {
|
|
||||||
en_US: 'Option 1',
|
|
||||||
zh_CN: '男',
|
|
||||||
type: 'i18n',
|
|
||||||
__sid__: 'param_k1owc4tb',
|
|
||||||
},
|
|
||||||
__sid__: 'serial_k1owc4t1',
|
|
||||||
value: 'M',
|
|
||||||
sid: 'opt_k1owc4t2',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
defaultChecked: false,
|
|
||||||
text: {
|
|
||||||
en_US: 'Option 2',
|
|
||||||
zh_CN: '女',
|
|
||||||
type: 'i18n',
|
|
||||||
__sid__: 'param_k1owc4tf',
|
|
||||||
},
|
|
||||||
__sid__: 'serial_k1owc4t2',
|
|
||||||
value: 'F',
|
|
||||||
sid: 'opt_k1owc4t3',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
__useMediator: 'value',
|
|
||||||
labelTipsTypes: 'none',
|
|
||||||
labelTipsIcon: '',
|
|
||||||
labelTipsText: {
|
|
||||||
type: 'i18n',
|
|
||||||
use: 'zh_CN',
|
|
||||||
en_US: '',
|
|
||||||
zh_CN: '',
|
|
||||||
},
|
|
||||||
useDetailValue: false,
|
|
||||||
searchDelay: 300,
|
|
||||||
},
|
|
||||||
condition: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
componentName: 'Card',
|
|
||||||
id: 'node_k1ow3cbl',
|
|
||||||
props: {
|
|
||||||
__slot__title: false,
|
|
||||||
subTitle: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
en_US: '',
|
|
||||||
zh_CN: '',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
__slot__subTitle: false,
|
|
||||||
extra: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
zh_CN: '',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
className: 'card_kh05zf9e',
|
|
||||||
title: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
en_US: 'Title',
|
|
||||||
zh_CN: '部门信息',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
__slot__extra: false,
|
|
||||||
showHeadDivider: true,
|
|
||||||
__style__: ':root {\n margin-bottom: 12px;\n}',
|
|
||||||
showTitleBullet: true,
|
|
||||||
contentHeight: '',
|
|
||||||
fieldId: 'card_k1ow3h1m',
|
|
||||||
dividerNoInset: false,
|
|
||||||
},
|
|
||||||
condition: true,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
componentName: 'CardContent',
|
|
||||||
id: 'node_k1ow3cbm',
|
|
||||||
props: {},
|
|
||||||
condition: true,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
componentName: 'TextField',
|
|
||||||
id: 'node_k1ow3cc4',
|
|
||||||
props: {
|
|
||||||
fieldName: 'department',
|
|
||||||
hasClear: false,
|
|
||||||
autoFocus: false,
|
|
||||||
tips: {
|
|
||||||
en_US: '',
|
|
||||||
zh_CN: '',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
trim: false,
|
|
||||||
labelTextAlign: 'right',
|
|
||||||
placeholder: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
en_US: 'please input',
|
|
||||||
zh_CN: '请输入',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
state: '',
|
|
||||||
behavior: 'NORMAL',
|
|
||||||
value: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
zh_CN: '',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
addonBefore: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
zh_CN: '',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
validation: [],
|
|
||||||
hasLimitHint: false,
|
|
||||||
cutString: false,
|
|
||||||
__style__: {},
|
|
||||||
fieldId: 'textField_k1ow3h21',
|
|
||||||
htmlType: 'input',
|
|
||||||
autoHeight: false,
|
|
||||||
labelColOffset: 0,
|
|
||||||
label: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
en_US: 'TextField',
|
|
||||||
zh_CN: '所属部门',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
__category__: 'form',
|
|
||||||
labelColSpan: 4,
|
|
||||||
wrapperColSpan: 0,
|
|
||||||
rows: 4,
|
|
||||||
addonAfter: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
zh_CN: '',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
wrapperColOffset: 0,
|
|
||||||
size: 'medium',
|
|
||||||
labelAlign: 'top',
|
|
||||||
__useMediator: 'value',
|
|
||||||
labelTipsTypes: 'none',
|
|
||||||
labelTipsIcon: '',
|
|
||||||
labelTipsText: {
|
|
||||||
type: 'i18n',
|
|
||||||
use: 'zh_CN',
|
|
||||||
en_US: '',
|
|
||||||
zh_CN: '',
|
|
||||||
},
|
|
||||||
maxLength: 200,
|
|
||||||
},
|
|
||||||
condition: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
componentName: 'ColumnsLayout',
|
|
||||||
id: 'node_k1ow3cc5',
|
|
||||||
props: {
|
|
||||||
layout: '6:6',
|
|
||||||
columnGap: '20',
|
|
||||||
rowGap: 0,
|
|
||||||
__style__: {},
|
|
||||||
fieldId: 'columns_k1ow3h22',
|
|
||||||
},
|
|
||||||
condition: true,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
componentName: 'Column',
|
|
||||||
id: 'node_k1ow3cc6',
|
|
||||||
props: {
|
|
||||||
colSpan: '',
|
|
||||||
__style__: {},
|
|
||||||
fieldId: 'column_k1p1bnjo',
|
|
||||||
},
|
|
||||||
condition: true,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
componentName: 'TextField',
|
|
||||||
id: 'node_k1ow3cc8',
|
|
||||||
props: {
|
|
||||||
fieldName: 'leader',
|
|
||||||
hasClear: false,
|
|
||||||
autoFocus: false,
|
|
||||||
tips: {
|
|
||||||
en_US: '',
|
|
||||||
zh_CN: '',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
trim: false,
|
|
||||||
labelTextAlign: 'right',
|
|
||||||
placeholder: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
en_US: 'please input',
|
|
||||||
zh_CN: '请输入',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
state: '',
|
|
||||||
behavior: 'NORMAL',
|
|
||||||
value: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
zh_CN: '',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
addonBefore: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
zh_CN: '',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
validation: [],
|
|
||||||
hasLimitHint: false,
|
|
||||||
cutString: false,
|
|
||||||
__style__: {},
|
|
||||||
fieldId: 'textField_k1ow3h23',
|
|
||||||
htmlType: 'input',
|
|
||||||
autoHeight: false,
|
|
||||||
labelColOffset: 0,
|
|
||||||
label: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
en_US: 'TextField',
|
|
||||||
zh_CN: '主管',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
__category__: 'form',
|
|
||||||
labelColSpan: 4,
|
|
||||||
wrapperColSpan: 0,
|
|
||||||
rows: 4,
|
|
||||||
addonAfter: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
zh_CN: '',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
wrapperColOffset: 0,
|
|
||||||
size: 'medium',
|
|
||||||
labelAlign: 'top',
|
|
||||||
__useMediator: 'value',
|
|
||||||
labelTipsTypes: 'none',
|
|
||||||
labelTipsIcon: '',
|
|
||||||
labelTipsText: {
|
|
||||||
type: 'i18n',
|
|
||||||
use: 'zh_CN',
|
|
||||||
en_US: '',
|
|
||||||
zh_CN: '',
|
|
||||||
},
|
|
||||||
maxLength: 200,
|
|
||||||
},
|
|
||||||
condition: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
componentName: 'Column',
|
|
||||||
id: 'node_k1ow3cc7',
|
|
||||||
props: {
|
|
||||||
colSpan: '',
|
|
||||||
__style__: {},
|
|
||||||
fieldId: 'column_k1p1bnjp',
|
|
||||||
},
|
|
||||||
condition: true,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
componentName: 'TextField',
|
|
||||||
id: 'node_k1ow3cc9',
|
|
||||||
props: {
|
|
||||||
fieldName: 'hrg',
|
|
||||||
hasClear: false,
|
|
||||||
autoFocus: false,
|
|
||||||
tips: {
|
|
||||||
en_US: '',
|
|
||||||
zh_CN: '',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
trim: false,
|
|
||||||
labelTextAlign: 'right',
|
|
||||||
placeholder: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
en_US: 'please input',
|
|
||||||
zh_CN: '请输入',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
state: '',
|
|
||||||
behavior: 'NORMAL',
|
|
||||||
value: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
zh_CN: '',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
addonBefore: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
zh_CN: '',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
validation: [],
|
|
||||||
hasLimitHint: false,
|
|
||||||
cutString: false,
|
|
||||||
__style__: {},
|
|
||||||
fieldId: 'textField_k1ow3h24',
|
|
||||||
htmlType: 'input',
|
|
||||||
autoHeight: false,
|
|
||||||
labelColOffset: 0,
|
|
||||||
label: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
en_US: 'TextField',
|
|
||||||
zh_CN: 'HRG',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
__category__: 'form',
|
|
||||||
labelColSpan: 4,
|
|
||||||
wrapperColSpan: 0,
|
|
||||||
rows: 4,
|
|
||||||
addonAfter: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
zh_CN: '',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
wrapperColOffset: 0,
|
|
||||||
size: 'medium',
|
|
||||||
labelAlign: 'top',
|
|
||||||
__useMediator: 'value',
|
|
||||||
labelTipsTypes: 'none',
|
|
||||||
labelTipsIcon: '',
|
|
||||||
labelTipsText: {
|
|
||||||
type: 'i18n',
|
|
||||||
use: 'zh_CN',
|
|
||||||
en_US: '',
|
|
||||||
zh_CN: '',
|
|
||||||
},
|
|
||||||
maxLength: 200,
|
|
||||||
},
|
|
||||||
condition: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
componentName: 'Div',
|
|
||||||
id: 'node_k1ow3cbo',
|
|
||||||
props: {
|
|
||||||
className: 'div_kh05zf9h',
|
|
||||||
behavior: 'NORMAL',
|
|
||||||
__style__:
|
|
||||||
':root {\n display: flex;\n align-items: flex-start;\n justify-content: center;\n background: #fff;\n padding: 20px 0;\n}',
|
|
||||||
events: {},
|
|
||||||
fieldId: 'div_k1ow3h1o',
|
|
||||||
useFieldIdAsDomId: false,
|
|
||||||
customClassName: '',
|
|
||||||
},
|
|
||||||
condition: true,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
componentName: 'Button',
|
|
||||||
id: 'node_k1ow3cbn',
|
|
||||||
props: {
|
|
||||||
triggerEventsWhenLoading: false,
|
|
||||||
onClick: {
|
|
||||||
rawType: 'events',
|
|
||||||
type: 'JSExpression',
|
|
||||||
value:
|
|
||||||
'this.utils.legaoBuiltin.execEventFlow.bind(this, [this.submit])',
|
|
||||||
events: [
|
|
||||||
{
|
|
||||||
name: 'submit',
|
|
||||||
id: 'submit',
|
|
||||||
params: {},
|
|
||||||
type: 'actionRef',
|
|
||||||
uuid: '1570966253282_0',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
size: 'medium',
|
|
||||||
baseIcon: '',
|
|
||||||
otherIcon: '',
|
|
||||||
className: 'button_kh05zf9f',
|
|
||||||
type: 'primary',
|
|
||||||
behavior: 'NORMAL',
|
|
||||||
loading: false,
|
|
||||||
content: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
en_US: 'Button',
|
|
||||||
zh_CN: '提交',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
__style__: ':root {\n margin-right: 16px;\n width: 80px\n}',
|
|
||||||
fieldId: 'button_k1ow3h1n',
|
|
||||||
},
|
|
||||||
condition: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
componentName: 'Button',
|
|
||||||
id: 'node_k1ow3cbp',
|
|
||||||
props: {
|
|
||||||
triggerEventsWhenLoading: false,
|
|
||||||
size: 'medium',
|
|
||||||
baseIcon: '',
|
|
||||||
otherIcon: '',
|
|
||||||
className: 'button_kh05zf9g',
|
|
||||||
type: 'normal',
|
|
||||||
behavior: 'NORMAL',
|
|
||||||
loading: false,
|
|
||||||
content: {
|
|
||||||
use: 'zh_CN',
|
|
||||||
en_US: 'Button',
|
|
||||||
zh_CN: '取消',
|
|
||||||
type: 'i18n',
|
|
||||||
},
|
|
||||||
__style__: ':root {\n width: 80px;\n}',
|
|
||||||
fieldId: 'button_k1ow3h1p',
|
|
||||||
},
|
|
||||||
condition: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
componentName: 'RootFooter',
|
|
||||||
id: 'node_k1ow3cbc',
|
|
||||||
props: {},
|
|
||||||
condition: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
React.PropTypes = PropTypes;
|
|
||||||
window.React = React;
|
|
||||||
|
|
||||||
document.documentElement.requestFullscreen = () => {};
|
|
||||||
document.exitFullscreen = () => {};
|
|
||||||
@ -1,50 +0,0 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
||||||
|
|
||||||
exports[`deepValueParser 测试 designMode: design 1`] = `
|
|
||||||
Object {
|
|
||||||
"a": "111",
|
|
||||||
"arr": Array [
|
|
||||||
"111",
|
|
||||||
"111",
|
|
||||||
],
|
|
||||||
"b": "222",
|
|
||||||
"c": "中文",
|
|
||||||
"slot": Object {
|
|
||||||
"type": "JSSlot",
|
|
||||||
"value": Array [
|
|
||||||
Object {
|
|
||||||
"componentName": "Div",
|
|
||||||
"props": Object {},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`deepValueParser 测试 designMode: live 1`] = `
|
|
||||||
Object {
|
|
||||||
"a": Object {
|
|
||||||
"mock": "111",
|
|
||||||
"type": "JSExpression",
|
|
||||||
"value": "state.a",
|
|
||||||
},
|
|
||||||
"arr": Array [
|
|
||||||
Object {
|
|
||||||
"mock": "111",
|
|
||||||
"type": "JSExpression",
|
|
||||||
"value": "state.a",
|
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"mock": "111",
|
|
||||||
"type": "JSExpression",
|
|
||||||
"value": "state.b",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"b": Object {
|
|
||||||
"mock": "222",
|
|
||||||
"type": "JSExpression",
|
|
||||||
"value": "state.b",
|
|
||||||
},
|
|
||||||
"c": "中文",
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
@ -1,240 +0,0 @@
|
|||||||
import '../fixtures/window';
|
|
||||||
import bus from '../../src/bus';
|
|
||||||
import { editor } from '../../src/reducers';
|
|
||||||
|
|
||||||
describe('bus 测试', () => {
|
|
||||||
afterEach(() => {
|
|
||||||
bus.unsub('evt1');
|
|
||||||
});
|
|
||||||
it('sub / pub 测试', () => {
|
|
||||||
const mockFn1 = jest.fn();
|
|
||||||
const off1 = bus.sub('evt1', mockFn1);
|
|
||||||
|
|
||||||
const evtData = { a: 1 };
|
|
||||||
bus.pub('evt1', evtData);
|
|
||||||
|
|
||||||
expect(mockFn1).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockFn1).toHaveBeenCalledWith(evtData);
|
|
||||||
|
|
||||||
off1();
|
|
||||||
|
|
||||||
bus.pub('evt1', evtData);
|
|
||||||
expect(mockFn1).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockFn1).toHaveBeenCalledWith(evtData);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('on / emit 测试', () => {
|
|
||||||
const mockFn1 = jest.fn();
|
|
||||||
const off1 = bus.on('evt1', mockFn1);
|
|
||||||
|
|
||||||
const evtData = { a: 1 };
|
|
||||||
bus.emit('evt1', evtData);
|
|
||||||
|
|
||||||
expect(mockFn1).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockFn1).toHaveBeenCalledWith(evtData);
|
|
||||||
|
|
||||||
off1();
|
|
||||||
|
|
||||||
bus.emit('evt1', evtData);
|
|
||||||
expect(mockFn1).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockFn1).toHaveBeenCalledWith(evtData);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('once / emit 测试', () => {
|
|
||||||
const mockFn1 = jest.fn();
|
|
||||||
bus.once('evt1', mockFn1);
|
|
||||||
|
|
||||||
const evtData = { a: 1 };
|
|
||||||
bus.emit('evt1', evtData);
|
|
||||||
|
|
||||||
expect(mockFn1).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockFn1).toHaveBeenCalledWith(evtData);
|
|
||||||
|
|
||||||
bus.emit('evt1', evtData);
|
|
||||||
expect(mockFn1).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockFn1).toHaveBeenCalledWith(evtData);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('once / emit 测试,调用解绑函数', () => {
|
|
||||||
const mockFn1 = jest.fn();
|
|
||||||
const off1 = bus.once('evt1', mockFn1);
|
|
||||||
|
|
||||||
off1();
|
|
||||||
|
|
||||||
const evtData = { a: 1 };
|
|
||||||
bus.emit('evt1', evtData);
|
|
||||||
|
|
||||||
expect(mockFn1).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('removeListener 测试', () => {
|
|
||||||
const mockFn1 = jest.fn();
|
|
||||||
bus.on('evt1', mockFn1);
|
|
||||||
|
|
||||||
const evtData = { a: 1 };
|
|
||||||
bus.emit('evt1', evtData);
|
|
||||||
|
|
||||||
expect(mockFn1).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockFn1).toHaveBeenCalledWith(evtData);
|
|
||||||
|
|
||||||
bus.removeListener('evt1', mockFn1);
|
|
||||||
bus.emit('evt1', evtData);
|
|
||||||
|
|
||||||
expect(mockFn1).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockFn1).toHaveBeenCalledWith(evtData);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('unsub 测试 - 只有一个 handler', () => {
|
|
||||||
const mockFn1 = jest.fn();
|
|
||||||
bus.on('evt1', mockFn1);
|
|
||||||
|
|
||||||
const evtData = { a: 1 };
|
|
||||||
bus.emit('evt1', evtData);
|
|
||||||
|
|
||||||
expect(mockFn1).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockFn1).toHaveBeenCalledWith(evtData);
|
|
||||||
|
|
||||||
bus.unsub('evt1', mockFn1);
|
|
||||||
bus.emit('evt1', evtData);
|
|
||||||
|
|
||||||
expect(mockFn1).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockFn1).toHaveBeenCalledWith(evtData);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('unsub 测试 - 只 unsub 一个 handler', () => {
|
|
||||||
const mockFn1 = jest.fn();
|
|
||||||
const mockFn2 = jest.fn();
|
|
||||||
bus.on('evt1', mockFn1);
|
|
||||||
bus.on('evt1', mockFn2);
|
|
||||||
|
|
||||||
const evtData = { a: 1 };
|
|
||||||
bus.emit('evt1', evtData);
|
|
||||||
|
|
||||||
expect(mockFn1).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockFn1).toHaveBeenCalledWith(evtData);
|
|
||||||
expect(mockFn2).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockFn2).toHaveBeenCalledWith(evtData);
|
|
||||||
|
|
||||||
bus.unsub('evt1', mockFn1);
|
|
||||||
const evtData2 = { a: 2 };
|
|
||||||
bus.emit('evt1', evtData2);
|
|
||||||
|
|
||||||
expect(mockFn1).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockFn1).toHaveBeenCalledWith(evtData);
|
|
||||||
expect(mockFn2).toHaveBeenCalledTimes(2);
|
|
||||||
expect(mockFn2).toHaveBeenLastCalledWith(evtData2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('unsub 测试 - 多个 handler', () => {
|
|
||||||
const mockFn1 = jest.fn();
|
|
||||||
const mockFn2 = jest.fn();
|
|
||||||
bus.on('evt1', mockFn1);
|
|
||||||
bus.on('evt1', mockFn2);
|
|
||||||
|
|
||||||
const evtData = { a: 1 };
|
|
||||||
bus.emit('evt1', evtData);
|
|
||||||
|
|
||||||
expect(mockFn1).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockFn1).toHaveBeenCalledWith(evtData);
|
|
||||||
expect(mockFn2).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockFn2).toHaveBeenCalledWith(evtData);
|
|
||||||
|
|
||||||
bus.unsub('evt1');
|
|
||||||
bus.emit('evt1', evtData);
|
|
||||||
|
|
||||||
expect(mockFn1).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockFn1).toHaveBeenCalledWith(evtData);
|
|
||||||
expect(mockFn2).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockFn2).toHaveBeenCalledWith(evtData);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('off 测试 - 只有一个 handler', () => {
|
|
||||||
const mockFn1 = jest.fn();
|
|
||||||
bus.on('evt1', mockFn1);
|
|
||||||
|
|
||||||
const evtData = { a: 1 };
|
|
||||||
bus.emit('evt1', evtData);
|
|
||||||
|
|
||||||
expect(mockFn1).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockFn1).toHaveBeenCalledWith(evtData);
|
|
||||||
|
|
||||||
bus.off('evt1', mockFn1);
|
|
||||||
bus.emit('evt1', evtData);
|
|
||||||
|
|
||||||
expect(mockFn1).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockFn1).toHaveBeenCalledWith(evtData);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('off 测试 - 只 off 一个 handler', () => {
|
|
||||||
const mockFn1 = jest.fn();
|
|
||||||
const mockFn2 = jest.fn();
|
|
||||||
bus.on('evt1', mockFn1);
|
|
||||||
bus.on('evt1', mockFn2);
|
|
||||||
|
|
||||||
const evtData = { a: 1 };
|
|
||||||
bus.emit('evt1', evtData);
|
|
||||||
|
|
||||||
expect(mockFn1).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockFn1).toHaveBeenCalledWith(evtData);
|
|
||||||
expect(mockFn2).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockFn2).toHaveBeenCalledWith(evtData);
|
|
||||||
|
|
||||||
bus.off('evt1', mockFn1);
|
|
||||||
const evtData2 = { a: 2 };
|
|
||||||
bus.emit('evt1', evtData2);
|
|
||||||
|
|
||||||
expect(mockFn1).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockFn1).toHaveBeenCalledWith(evtData);
|
|
||||||
expect(mockFn2).toHaveBeenCalledTimes(2);
|
|
||||||
expect(mockFn2).toHaveBeenLastCalledWith(evtData2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('off 测试 - 多个 handler', () => {
|
|
||||||
const mockFn1 = jest.fn();
|
|
||||||
const mockFn2 = jest.fn();
|
|
||||||
bus.on('evt1', mockFn1);
|
|
||||||
bus.on('evt1', mockFn2);
|
|
||||||
|
|
||||||
const evtData = { a: 1 };
|
|
||||||
bus.emit('evt1', evtData);
|
|
||||||
|
|
||||||
expect(mockFn1).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockFn1).toHaveBeenCalledWith(evtData);
|
|
||||||
expect(mockFn2).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockFn2).toHaveBeenCalledWith(evtData);
|
|
||||||
|
|
||||||
bus.off('evt1');
|
|
||||||
bus.emit('evt1', evtData);
|
|
||||||
|
|
||||||
expect(mockFn1).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockFn1).toHaveBeenCalledWith(evtData);
|
|
||||||
expect(mockFn2).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockFn2).toHaveBeenCalledWith(evtData);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('简单测试(dummy)', () => {
|
|
||||||
bus.getEmitter();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('editor 事件转发', () => {
|
|
||||||
const fwdEvtMap = {
|
|
||||||
've.hotkey.callback.call': 'hotkey.callback.call',
|
|
||||||
've.history.back': 'history.back',
|
|
||||||
've.history.forward': 'history.forward',
|
|
||||||
'node.prop.change': 'node.prop.change',
|
|
||||||
};
|
|
||||||
|
|
||||||
Object.keys(fwdEvtMap).forEach(veEventName => {
|
|
||||||
it(`${veEventName} 测试`, () => {
|
|
||||||
const mockFn1 = jest.fn();
|
|
||||||
const evtData1 = { a: 1 };
|
|
||||||
bus.on(veEventName, mockFn1);
|
|
||||||
|
|
||||||
editor.emit(fwdEvtMap[veEventName], evtData1);
|
|
||||||
|
|
||||||
expect(mockFn1).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockFn1).toHaveBeenCalledWith(evtData1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,62 +0,0 @@
|
|||||||
import '../fixtures/window';
|
|
||||||
// import { Project } from '../../src/project/project';
|
|
||||||
// import { Node } from '../../src/document/node/node';
|
|
||||||
// import { Designer } from '../../src/designer/designer';
|
|
||||||
import { VisualEngineContext } from '../../src/context';
|
|
||||||
import { autorun } from '@ali/lowcode-editor-core';
|
|
||||||
|
|
||||||
describe('VisualEngineContext 测试', () => {
|
|
||||||
it('registerManager | getManager', () => {
|
|
||||||
const ctx = new VisualEngineContext();
|
|
||||||
|
|
||||||
ctx.registerManager({
|
|
||||||
mgr1: {},
|
|
||||||
});
|
|
||||||
ctx.registerManager('mgr2', {});
|
|
||||||
expect(ctx.getManager('mgr1')).toEqual({});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('registerModule | getModule', () => {
|
|
||||||
const ctx = new VisualEngineContext();
|
|
||||||
|
|
||||||
ctx.registerModule({
|
|
||||||
mod1: {},
|
|
||||||
});
|
|
||||||
ctx.registerModule('mod2', {});
|
|
||||||
expect(ctx.getModule('mod1')).toEqual({});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('use | getPlugin', () => {
|
|
||||||
const ctx = new VisualEngineContext();
|
|
||||||
|
|
||||||
ctx.use('plugin1', { plugin: 1 });
|
|
||||||
ctx.registerManager({
|
|
||||||
mgr1: { manager: 1 },
|
|
||||||
});
|
|
||||||
ctx.registerModule({
|
|
||||||
mod1: { mod: 1 },
|
|
||||||
});
|
|
||||||
expect(ctx.getPlugin('plugin1')).toEqual({ plugin: 1 });
|
|
||||||
expect(ctx.getPlugin('mgr1')).toEqual({ manager: 1 });
|
|
||||||
expect(ctx.getPlugin('mod1')).toEqual({ mod: 1 });
|
|
||||||
expect(ctx.getPlugin()).toBeUndefined;
|
|
||||||
|
|
||||||
ctx.use('ve.settingField.variableSetter', {});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('registerTreePane | getModule', () => {
|
|
||||||
const ctx = new VisualEngineContext();
|
|
||||||
|
|
||||||
ctx.registerTreePane({ pane: 1 }, { core: 2 });
|
|
||||||
expect(ctx.getModule('TreePane')).toEqual({ pane: 1 });
|
|
||||||
expect(ctx.getModule('TreeCore')).toEqual({ core: 2 });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('registerDynamicSetterProvider', () => {
|
|
||||||
const ctx = new VisualEngineContext();
|
|
||||||
|
|
||||||
ctx.registerDynamicSetterProvider({});
|
|
||||||
expect(ctx.getPlugin('ve.plugin.setterProvider')).toEqual({});
|
|
||||||
ctx.registerDynamicSetterProvider();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,84 +0,0 @@
|
|||||||
import '../fixtures/window';
|
|
||||||
import { deepValueParser } from '../../src/props-reducers/deep-value-reducer';
|
|
||||||
import { editor } from '../../src/reducers';
|
|
||||||
|
|
||||||
describe('deepValueParser 测试', () => {
|
|
||||||
it('null & undefined', () => {
|
|
||||||
expect(deepValueParser()).toBeNull;
|
|
||||||
expect(deepValueParser()).toBeUndefined;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('designMode: design', () => {
|
|
||||||
expect(deepValueParser({
|
|
||||||
a: {
|
|
||||||
type: 'variable',
|
|
||||||
variable: 'state.a',
|
|
||||||
value: '111',
|
|
||||||
},
|
|
||||||
b: {
|
|
||||||
type: 'JSExpression',
|
|
||||||
value: 'state.b',
|
|
||||||
mock: '222',
|
|
||||||
},
|
|
||||||
c: {
|
|
||||||
type: 'i18n',
|
|
||||||
use: 'zh_CN',
|
|
||||||
zh_CN: '中文',
|
|
||||||
en_US: 'eng',
|
|
||||||
},
|
|
||||||
slot: {
|
|
||||||
type: 'JSSlot',
|
|
||||||
value: [{
|
|
||||||
componentName: 'Div',
|
|
||||||
props: {},
|
|
||||||
}],
|
|
||||||
},
|
|
||||||
arr: [
|
|
||||||
{
|
|
||||||
type: 'variable',
|
|
||||||
variable: 'state.a',
|
|
||||||
value: '111',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'variable',
|
|
||||||
variable: 'state.b',
|
|
||||||
value: '111',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('designMode: live', () => {
|
|
||||||
editor.set('designMode', 'live');
|
|
||||||
expect(deepValueParser({
|
|
||||||
a: {
|
|
||||||
type: 'variable',
|
|
||||||
variable: 'state.a',
|
|
||||||
value: '111',
|
|
||||||
},
|
|
||||||
b: {
|
|
||||||
type: 'JSExpression',
|
|
||||||
value: 'state.b',
|
|
||||||
mock: '222',
|
|
||||||
},
|
|
||||||
c: {
|
|
||||||
type: 'i18n',
|
|
||||||
use: 'zh_CN',
|
|
||||||
zh_CN: '中文',
|
|
||||||
en_US: 'eng',
|
|
||||||
},
|
|
||||||
arr: [
|
|
||||||
{
|
|
||||||
type: 'variable',
|
|
||||||
variable: 'state.a',
|
|
||||||
value: '111',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'variable',
|
|
||||||
variable: 'state.b',
|
|
||||||
value: '111',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,182 +0,0 @@
|
|||||||
import '../fixtures/window';
|
|
||||||
// import { Project } from '../../src/project/project';
|
|
||||||
// import { Node } from '../../src/document/node/node';
|
|
||||||
// import { Editor } from '@ali/lowcode-editor-core';
|
|
||||||
// import { Designer } from '@ali/lowcode-designer';
|
|
||||||
import { designer } from '../../src/reducers';
|
|
||||||
import DragEngine from '../../src/drag-engine';
|
|
||||||
import formSchema from '../fixtures/schema/form';
|
|
||||||
|
|
||||||
// const editor = new Editor();
|
|
||||||
// const designer = new Designer({ editor });
|
|
||||||
designer.project.open(formSchema);
|
|
||||||
|
|
||||||
const mockBoostPrototype = jest.fn((e: MouseEvent) => {
|
|
||||||
return {
|
|
||||||
isPrototype: true,
|
|
||||||
getComponentName() {
|
|
||||||
return 'Div';
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const mockBoostNode = jest.fn((e: MouseEvent) => {
|
|
||||||
return designer.currentDocument?.getNode('node_k1ow3cbo');
|
|
||||||
});
|
|
||||||
|
|
||||||
const mockBoostNodeData = jest.fn((e: MouseEvent) => {
|
|
||||||
return {
|
|
||||||
type: 'NodeData',
|
|
||||||
componentName: 'Div',
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const mockBoostNull = jest.fn((e: MouseEvent) => {
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
|
|
||||||
const mockDragstart = jest.fn();
|
|
||||||
const mockDrag = jest.fn();
|
|
||||||
const mockDragend = jest.fn();
|
|
||||||
|
|
||||||
describe('drag-engine 测试', () => {
|
|
||||||
it('prototype', async () => {
|
|
||||||
DragEngine.from(document, mockBoostPrototype);
|
|
||||||
|
|
||||||
DragEngine.onDragstart(mockDragstart);
|
|
||||||
DragEngine.onDrag(mockDrag);
|
|
||||||
DragEngine.onDragend(mockDragend);
|
|
||||||
|
|
||||||
const mousedownEvt = new MouseEvent('mousedown');
|
|
||||||
document.dispatchEvent(mousedownEvt);
|
|
||||||
designer.dragon.emitter.emit('dragstart', {
|
|
||||||
dragObject: {
|
|
||||||
nodes: [designer.currentDocument?.getNode('node_k1ow3cbo')],
|
|
||||||
},
|
|
||||||
originalEvent: mousedownEvt,
|
|
||||||
});
|
|
||||||
|
|
||||||
// await new Promise(resolve => resolve(setTimeout, 500));
|
|
||||||
|
|
||||||
expect(mockDragstart).toHaveBeenCalled();
|
|
||||||
|
|
||||||
designer.dragon.emitter.emit('drag', {
|
|
||||||
dragObject: {
|
|
||||||
nodes: [designer.currentDocument?.getNode('node_k1ow3cbo')],
|
|
||||||
},
|
|
||||||
originalEvent: mousedownEvt,
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(mockDrag).toHaveBeenCalled();
|
|
||||||
expect(DragEngine.inDragging()).toBeTruthy;
|
|
||||||
|
|
||||||
designer.dragon.emitter.emit('dragend', {
|
|
||||||
dragObject: {
|
|
||||||
nodes: [designer.currentDocument?.getNode('node_k1ow3cbo')],
|
|
||||||
},
|
|
||||||
originalEvent: mousedownEvt,
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(mockDragend).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Node', async () => {
|
|
||||||
DragEngine.from(document, mockBoostNode);
|
|
||||||
|
|
||||||
DragEngine.onDragstart(mockDragstart);
|
|
||||||
DragEngine.onDrag(mockDrag);
|
|
||||||
DragEngine.onDragend(mockDragend);
|
|
||||||
|
|
||||||
const mousedownEvt = new MouseEvent('mousedown');
|
|
||||||
document.dispatchEvent(mousedownEvt);
|
|
||||||
designer.dragon.emitter.emit('dragstart', {
|
|
||||||
dragObject: {
|
|
||||||
nodes: [designer.currentDocument?.getNode('node_k1ow3cbo')],
|
|
||||||
},
|
|
||||||
originalEvent: mousedownEvt,
|
|
||||||
});
|
|
||||||
|
|
||||||
// await new Promise(resolve => resolve(setTimeout, 500));
|
|
||||||
|
|
||||||
expect(mockDragstart).toHaveBeenCalled();
|
|
||||||
|
|
||||||
designer.dragon.emitter.emit('drag', {
|
|
||||||
dragObject: {
|
|
||||||
nodes: [designer.currentDocument?.getNode('node_k1ow3cbo')],
|
|
||||||
},
|
|
||||||
originalEvent: mousedownEvt,
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(mockDrag).toHaveBeenCalled();
|
|
||||||
|
|
||||||
designer.dragon.emitter.emit('dragend', {
|
|
||||||
dragObject: {
|
|
||||||
nodes: [designer.currentDocument?.getNode('node_k1ow3cbo')],
|
|
||||||
},
|
|
||||||
originalEvent: mousedownEvt,
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(mockDragend).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('NodeData', async () => {
|
|
||||||
DragEngine.from(document, mockBoostNodeData);
|
|
||||||
|
|
||||||
DragEngine.onDragstart(mockDragstart);
|
|
||||||
DragEngine.onDrag(mockDrag);
|
|
||||||
DragEngine.onDragend(mockDragend);
|
|
||||||
|
|
||||||
const mousedownEvt = new MouseEvent('mousedown');
|
|
||||||
document.dispatchEvent(mousedownEvt);
|
|
||||||
designer.dragon.emitter.emit('dragstart', {
|
|
||||||
dragObject: {
|
|
||||||
nodes: [designer.currentDocument?.getNode('node_k1ow3cbo')],
|
|
||||||
},
|
|
||||||
originalEvent: mousedownEvt,
|
|
||||||
});
|
|
||||||
|
|
||||||
// await new Promise(resolve => resolve(setTimeout, 500));
|
|
||||||
|
|
||||||
expect(mockDragstart).toHaveBeenCalled();
|
|
||||||
|
|
||||||
designer.dragon.emitter.emit('drag', {
|
|
||||||
dragObject: {
|
|
||||||
nodes: [designer.currentDocument?.getNode('node_k1ow3cbo')],
|
|
||||||
},
|
|
||||||
originalEvent: mousedownEvt,
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(mockDrag).toHaveBeenCalled();
|
|
||||||
|
|
||||||
designer.dragon.emitter.emit('dragend', {
|
|
||||||
dragObject: {
|
|
||||||
type: 'nodedata',
|
|
||||||
data: {
|
|
||||||
componentName: 'Div',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
originalEvent: mousedownEvt,
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(mockDragend).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('null', async () => {
|
|
||||||
DragEngine.from(document, mockBoostNull);
|
|
||||||
|
|
||||||
DragEngine.onDragstart(mockDragstart);
|
|
||||||
DragEngine.onDrag(mockDrag);
|
|
||||||
DragEngine.onDragend(mockDragend);
|
|
||||||
|
|
||||||
const mousedownEvt = new MouseEvent('mousedown');
|
|
||||||
document.dispatchEvent(mousedownEvt);
|
|
||||||
designer.dragon.emitter.emit('dragstart', {
|
|
||||||
dragObject: {
|
|
||||||
nodes: [designer.currentDocument?.getNode('node_k1ow3cbo')],
|
|
||||||
},
|
|
||||||
originalEvent: mousedownEvt,
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(mockDragstart).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,111 +0,0 @@
|
|||||||
import '../fixtures/window';
|
|
||||||
// import { Project } from '../../src/project/project';
|
|
||||||
// import { Node } from '../../src/document/node/node';
|
|
||||||
// import { Designer } from '../../src/designer/designer';
|
|
||||||
import env from '../../src/env';
|
|
||||||
import { autorun } from '@ali/lowcode-editor-core';
|
|
||||||
|
|
||||||
describe('env 测试', () => {
|
|
||||||
describe('常规 API 测试', () => {
|
|
||||||
it('setEnv / getEnv / setEnvMap / set / get', () => {
|
|
||||||
expect(env.getEnv('xxx')).toBeUndefined;
|
|
||||||
|
|
||||||
const mockFn1 = jest.fn();
|
|
||||||
const off1 = env.onEnvChange(mockFn1);
|
|
||||||
|
|
||||||
const envData = { a: 1 };
|
|
||||||
env.setEnv('xxx', envData);
|
|
||||||
expect(env.getEnv('xxx')).toEqual(envData);
|
|
||||||
expect(env.get('xxx')).toEqual(envData);
|
|
||||||
expect(mockFn1).toHaveBeenCalled();
|
|
||||||
expect(mockFn1).toHaveBeenCalledWith(env.envs, 'xxx', envData);
|
|
||||||
mockFn1.mockClear();
|
|
||||||
|
|
||||||
// 设置相同的值
|
|
||||||
env.setEnv('xxx', envData);
|
|
||||||
expect(env.getEnv('xxx')).toEqual(envData);
|
|
||||||
expect(env.get('xxx')).toEqual(envData);
|
|
||||||
expect(mockFn1).not.toHaveBeenCalled();
|
|
||||||
mockFn1.mockClear();
|
|
||||||
|
|
||||||
// 设置另一个 envName
|
|
||||||
const envData2 = { b: 1 };
|
|
||||||
env.set('yyy', envData2);
|
|
||||||
expect(env.getEnv('yyy')).toEqual(envData2);
|
|
||||||
expect(env.get('yyy')).toEqual(envData2);
|
|
||||||
expect(mockFn1).toHaveBeenCalled();
|
|
||||||
expect(mockFn1).toHaveBeenCalledWith(env.envs, 'yyy', envData2);
|
|
||||||
mockFn1.mockClear();
|
|
||||||
|
|
||||||
env.setEnvMap({
|
|
||||||
zzz: { a: 1, b: 1 },
|
|
||||||
});
|
|
||||||
expect(env.getEnv('xxx')).toBeUndefined;
|
|
||||||
expect(env.getEnv('yyy')).toBeUndefined;
|
|
||||||
expect(env.getEnv('zzz')).toEqual({ a: 1, b: 1 });
|
|
||||||
expect(mockFn1).toHaveBeenCalled();
|
|
||||||
expect(mockFn1).toHaveBeenCalledWith(env.envs);
|
|
||||||
mockFn1.mockClear();
|
|
||||||
|
|
||||||
// 解绑事件
|
|
||||||
off1();
|
|
||||||
env.setEnvMap({
|
|
||||||
zzz: { a: 1, b: 1 },
|
|
||||||
});
|
|
||||||
expect(mockFn1).not.toHaveBeenCalled();
|
|
||||||
mockFn1.mockClear();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('setLocale / getLocale', () => {
|
|
||||||
expect(env.getLocale()).toBe('zh_CN');
|
|
||||||
env.setLocale('en_US');
|
|
||||||
expect(env.getLocale()).toBe('en_US');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('setExpertMode / isExpertMode', () => {
|
|
||||||
expect(env.isExpertMode()).toBeFalsy;
|
|
||||||
env.setExpertMode('truthy value');
|
|
||||||
expect(env.isExpertMode()).toBeTruthy;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('getSupportFeatures / setSupportFeatures / supports', () => {
|
|
||||||
expect(env.getSupportFeatures()).toEqual({});
|
|
||||||
env.setSupportFeatures({
|
|
||||||
mobile: true,
|
|
||||||
pc: true,
|
|
||||||
});
|
|
||||||
expect(env.getSupportFeatures()).toEqual({
|
|
||||||
mobile: true,
|
|
||||||
pc: true,
|
|
||||||
});
|
|
||||||
expect(env.supports('mobile')).toBeTruthy;
|
|
||||||
expect(env.supports('pc')).toBeTruthy;
|
|
||||||
expect(env.supports('iot')).toBeFalsy;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('getAliSchemaVersion', () => {
|
|
||||||
expect(env.getAliSchemaVersion()).toBe('1.0.0');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('envs obx 测试', async () => {
|
|
||||||
const mockFn = jest.fn();
|
|
||||||
env.clear();
|
|
||||||
|
|
||||||
autorun(() => {
|
|
||||||
mockFn(env.envs);
|
|
||||||
env.envs;
|
|
||||||
});
|
|
||||||
|
|
||||||
await new Promise(resolve => setTimeout(resolve, 16));
|
|
||||||
|
|
||||||
expect(mockFn).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockFn).toHaveBeenLastCalledWith({});
|
|
||||||
|
|
||||||
env.setEnv('abc', { a: 1 });
|
|
||||||
|
|
||||||
await new Promise(resolve => setTimeout(resolve, 16));
|
|
||||||
expect(mockFn).toHaveBeenCalledTimes(2);
|
|
||||||
expect(mockFn).toHaveBeenLastCalledWith({ abc: { a: 1 } });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,71 +0,0 @@
|
|||||||
import '../fixtures/window';
|
|
||||||
import flagsCtrl from '../../src/flags';
|
|
||||||
import domready from 'domready';
|
|
||||||
|
|
||||||
jest.mock('domready', () => {
|
|
||||||
return (fn) => fn();
|
|
||||||
});
|
|
||||||
// domready.mockImplementation((fn) => fn());
|
|
||||||
|
|
||||||
describe('flags 测试', () => {
|
|
||||||
it('flags', () => {
|
|
||||||
const mockFlagsChange = jest.fn();
|
|
||||||
flagsCtrl.flags = [];
|
|
||||||
const off = flagsCtrl.onFlagsChange(mockFlagsChange);
|
|
||||||
flagsCtrl.add('a');
|
|
||||||
expect(mockFlagsChange).toHaveBeenCalledTimes(1);
|
|
||||||
off();
|
|
||||||
flagsCtrl.add('b');
|
|
||||||
expect(mockFlagsChange).toHaveBeenCalledTimes(1);
|
|
||||||
|
|
||||||
|
|
||||||
expect(flagsCtrl.getFlags()).toEqual(['a', 'b']);
|
|
||||||
|
|
||||||
flagsCtrl.flags = [];
|
|
||||||
flagsCtrl.setDragMode(true);
|
|
||||||
expect(flagsCtrl.getFlags()).toEqual(['drag-mode']);
|
|
||||||
flagsCtrl.setDragMode(false);
|
|
||||||
expect(flagsCtrl.getFlags()).toEqual([]);
|
|
||||||
|
|
||||||
flagsCtrl.setPreviewMode(true);
|
|
||||||
expect(flagsCtrl.getFlags()).toEqual(['preview-mode']);
|
|
||||||
flagsCtrl.setPreviewMode(false);
|
|
||||||
expect(flagsCtrl.getFlags()).toEqual(['design-mode']);
|
|
||||||
|
|
||||||
flagsCtrl.flags = [];
|
|
||||||
flagsCtrl.setHideSlate(true);
|
|
||||||
expect(flagsCtrl.getFlags()).toEqual(['hide-slate']);
|
|
||||||
flagsCtrl.setHideSlate(false);
|
|
||||||
expect(flagsCtrl.getFlags()).toEqual([]);
|
|
||||||
|
|
||||||
flagsCtrl.flags = [];
|
|
||||||
flagsCtrl.setSlateFixedMode(true);
|
|
||||||
expect(flagsCtrl.getFlags()).toEqual(['slate-fixed']);
|
|
||||||
flagsCtrl.setHideSlate(true);
|
|
||||||
expect(flagsCtrl.getFlags()).toEqual(['slate-fixed']);
|
|
||||||
flagsCtrl.setSlateFixedMode(false);
|
|
||||||
expect(flagsCtrl.getFlags()).toEqual([]);
|
|
||||||
|
|
||||||
flagsCtrl.flags = [];
|
|
||||||
flagsCtrl.setSlateFullMode(true);
|
|
||||||
expect(flagsCtrl.getFlags()).toEqual(['slate-full-screen']);
|
|
||||||
flagsCtrl.setSlateFullMode(false);
|
|
||||||
expect(flagsCtrl.getFlags()).toEqual([]);
|
|
||||||
|
|
||||||
expect([].slice.apply(document.documentElement.classList)).toEqual(flagsCtrl.getFlags());
|
|
||||||
|
|
||||||
flagsCtrl.flags = [];
|
|
||||||
// setWithShell
|
|
||||||
flagsCtrl.setWithShell('shellA');
|
|
||||||
expect(flagsCtrl.getFlags()).toEqual(['with-iphone6shell']);
|
|
||||||
flagsCtrl.setWithShell('iPhone6');
|
|
||||||
expect(flagsCtrl.getFlags()).toEqual(['with-iphone6shell']);
|
|
||||||
|
|
||||||
flagsCtrl.flags = [];
|
|
||||||
// setSimulator
|
|
||||||
flagsCtrl.setSimulator('simA');
|
|
||||||
expect(flagsCtrl.getFlags()).toEqual(['simulator-simA']);
|
|
||||||
flagsCtrl.setSimulator('simB');
|
|
||||||
expect(flagsCtrl.getFlags()).toEqual(['simulator-simB']);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,176 +0,0 @@
|
|||||||
import '../fixtures/window';
|
|
||||||
// import { Project } from '../../src/project/project';
|
|
||||||
// import { Node } from '../../src/document/node/node';
|
|
||||||
// import { Designer } from '../../src/designer/designer';
|
|
||||||
import panes from '../../src/panes';
|
|
||||||
import { autorun } from '@ali/lowcode-editor-core';
|
|
||||||
|
|
||||||
describe('panes 测试', () => {
|
|
||||||
it('add: type dock | PanelDock', () => {
|
|
||||||
const mockDockShow = jest.fn();
|
|
||||||
const mockDockHide = jest.fn();
|
|
||||||
const { DockPane } = panes;
|
|
||||||
const offDockShow = DockPane.onDockShow(mockDockShow);
|
|
||||||
const offDockHide = DockPane.onDockHide(mockDockHide);
|
|
||||||
|
|
||||||
const pane1 = panes.add({
|
|
||||||
name: 'trunk',
|
|
||||||
type: 'dock',
|
|
||||||
width: 300,
|
|
||||||
description: '组件库',
|
|
||||||
contents: [
|
|
||||||
{
|
|
||||||
title: '普通组件',
|
|
||||||
tip: '普通组件',
|
|
||||||
content: () => 'haha',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
menu: '组件库',
|
|
||||||
defaultFixed: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
const pane2 = panes.add({
|
|
||||||
name: 'trunk2',
|
|
||||||
type: 'dock',
|
|
||||||
width: 300,
|
|
||||||
description: '组件库',
|
|
||||||
contents: [
|
|
||||||
{
|
|
||||||
title: '普通组件',
|
|
||||||
tip: '普通组件',
|
|
||||||
content: () => 'haha',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
menu: '组件库',
|
|
||||||
defaultFixed: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
const pane3 = panes.add({
|
|
||||||
name: 'trunk3',
|
|
||||||
type: 'dock',
|
|
||||||
isAction: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
// DockPane.container.items.map(item => console.log(item.name))
|
|
||||||
// 2 trunks + 1 outline-pane
|
|
||||||
expect(DockPane.container.items.length).toBe(4);
|
|
||||||
|
|
||||||
DockPane.activeDock(pane1);
|
|
||||||
// expect(mockDockShow).toHaveBeenCalledTimes(1);
|
|
||||||
// expect(mockDockShow).toHaveBeenLastCalledWith(pane1);
|
|
||||||
expect(DockPane.container.items[1].visible).toBeTruthy;
|
|
||||||
|
|
||||||
DockPane.activeDock(pane2);
|
|
||||||
expect(DockPane.container.items[2].visible).toBeTruthy;
|
|
||||||
// expect(mockDockShow).toHaveBeenCalledTimes(2);
|
|
||||||
// expect(mockDockShow).toHaveBeenLastCalledWith(pane2);
|
|
||||||
// expect(mockDockHide).toHaveBeenCalledTimes(1);
|
|
||||||
// expect(mockDockHide).toHaveBeenLastCalledWith(pane1);
|
|
||||||
|
|
||||||
DockPane.activeDock();
|
|
||||||
DockPane.activeDock({ name: 'unexisting' });
|
|
||||||
|
|
||||||
offDockShow();
|
|
||||||
offDockHide();
|
|
||||||
|
|
||||||
// DockPane.activeDock(pane1);
|
|
||||||
// expect(mockDockShow).toHaveBeenCalledTimes(2);
|
|
||||||
// expect(mockDockHide).toHaveBeenCalledTimes(1);
|
|
||||||
|
|
||||||
expect(typeof DockPane.getDocks).toBe('function');
|
|
||||||
DockPane.getDocks();
|
|
||||||
expect(typeof DockPane.setFixed).toBe('function');
|
|
||||||
DockPane.setFixed();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('add: type action', () => {
|
|
||||||
panes.add({
|
|
||||||
name: 'trunk',
|
|
||||||
type: 'action',
|
|
||||||
init() {},
|
|
||||||
destroy() {},
|
|
||||||
});
|
|
||||||
|
|
||||||
const { ActionPane } = panes;
|
|
||||||
expect(typeof ActionPane.getActions).toBe('function');
|
|
||||||
ActionPane.getActions();
|
|
||||||
expect(typeof ActionPane.setActions).toBe('function');
|
|
||||||
ActionPane.setActions();
|
|
||||||
expect(ActionPane.getActions()).toBe(ActionPane.actions);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('add: type action - extraConfig', () => {
|
|
||||||
panes.add({
|
|
||||||
name: 'trunk',
|
|
||||||
type: 'action',
|
|
||||||
init() {},
|
|
||||||
destroy() {},
|
|
||||||
}, {});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('add: type action - function', () => {
|
|
||||||
panes.add(() => ({
|
|
||||||
name: 'trunk',
|
|
||||||
type: 'action',
|
|
||||||
init() {},
|
|
||||||
destroy() {},
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('add: type tab', () => {
|
|
||||||
panes.add({
|
|
||||||
name: 'trunk',
|
|
||||||
type: 'tab',
|
|
||||||
});
|
|
||||||
const { TabPane } = panes;
|
|
||||||
expect(typeof TabPane.setFloat).toBe('function');
|
|
||||||
TabPane.setFloat();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('add: type stage', () => {
|
|
||||||
panes.add({
|
|
||||||
id: 'stage1',
|
|
||||||
type: 'stage',
|
|
||||||
});
|
|
||||||
panes.add({
|
|
||||||
type: 'stage',
|
|
||||||
});
|
|
||||||
|
|
||||||
const { Stages } = panes;
|
|
||||||
expect(typeof Stages.getStage).toBe('function');
|
|
||||||
Stages.getStage();
|
|
||||||
expect(typeof Stages.createStage).toBe('function');
|
|
||||||
Stages.createStage({
|
|
||||||
id: 'stage1',
|
|
||||||
type: 'stage',
|
|
||||||
});
|
|
||||||
Stages.createStage({
|
|
||||||
type: 'stage',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('add: type stage - id', () => {
|
|
||||||
panes.add({
|
|
||||||
id: 'trunk',
|
|
||||||
name: 'trunk',
|
|
||||||
type: 'stage',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('add: type widget', () => {
|
|
||||||
panes.add({
|
|
||||||
name: 'trunk',
|
|
||||||
type: 'widget',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('add: type null', () => {
|
|
||||||
panes.add({
|
|
||||||
name: 'trunk',
|
|
||||||
});
|
|
||||||
|
|
||||||
const { toolbar } = panes;
|
|
||||||
expect(typeof toolbar.setContents).toBe('function');
|
|
||||||
toolbar.setContents();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
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 symbols from '../../src/symbols';
|
|
||||||
|
|
||||||
describe('symbols 测试', () => {
|
|
||||||
it('API', () => {
|
|
||||||
symbols.create('abc');
|
|
||||||
symbols.create('abc');
|
|
||||||
symbols.get('abc');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,189 +0,0 @@
|
|||||||
import '../fixtures/window';
|
|
||||||
import { Editor, globalContext } from '@ali/lowcode-editor-core';
|
|
||||||
import { editor } from '../../src/reducers';
|
|
||||||
import { Viewport } from '../../src/viewport';
|
|
||||||
import domready from 'domready';
|
|
||||||
|
|
||||||
// const editor = globalContext.get(Editor);
|
|
||||||
|
|
||||||
jest.mock('domready', () => {
|
|
||||||
return (fn) => fn();
|
|
||||||
});
|
|
||||||
|
|
||||||
// 貌似 jsdom 没有响应 fullscreen 变更事件,先这么 mock 吧
|
|
||||||
const mockSetFullscreen = flag => { document.fullscreen = flag; };
|
|
||||||
|
|
||||||
describe('viewport 测试', () => {
|
|
||||||
mockSetFullscreen(true);
|
|
||||||
|
|
||||||
it('getDevice / setDevice / getViewport / onDeviceChange / onViewportChange', async () => {
|
|
||||||
const viewport = new Viewport();
|
|
||||||
const mockDeviceChange = jest.fn();
|
|
||||||
const mockViewportChange = jest.fn();
|
|
||||||
const offDevice = viewport.onDeviceChange(mockDeviceChange);
|
|
||||||
const offViewport = viewport.onViewportChange(mockViewportChange);
|
|
||||||
expect(viewport.getDevice()).toBe('pc');
|
|
||||||
expect(viewport.getViewport()).toBe('design-pc');
|
|
||||||
editor.set('currentDocument', { simulator: { set() {} } });
|
|
||||||
|
|
||||||
await viewport.setDevice('mobile');
|
|
||||||
expect(viewport.getDevice()).toBe('mobile');
|
|
||||||
expect(viewport.getViewport()).toBe('design-mobile');
|
|
||||||
expect(mockDeviceChange).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockViewportChange).toHaveBeenCalledTimes(1);
|
|
||||||
|
|
||||||
offDevice();
|
|
||||||
offViewport();
|
|
||||||
await viewport.setDevice('pc');
|
|
||||||
expect(mockDeviceChange).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockViewportChange).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('setPreview / isPreview / togglePreivew / getViewport / onViewportChange', () => {
|
|
||||||
const viewport = new Viewport();
|
|
||||||
const mockViewportChange = jest.fn();
|
|
||||||
const mockPreivewChange = jest.fn();
|
|
||||||
const off = viewport.onViewportChange(mockViewportChange);
|
|
||||||
const offPreview = viewport.onPreview(mockPreivewChange);
|
|
||||||
viewport.setPreview(true);
|
|
||||||
expect(viewport.isPreview).toBeTruthy;
|
|
||||||
expect(viewport.getViewport()).toBe('preview-pc');
|
|
||||||
expect(mockViewportChange).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockPreivewChange).toHaveBeenCalledTimes(1);
|
|
||||||
viewport.setPreview(false);
|
|
||||||
expect(viewport.isPreview).toBeFalsy;
|
|
||||||
expect(viewport.getViewport()).toBe('design-pc');
|
|
||||||
expect(mockViewportChange).toHaveBeenCalledTimes(2);
|
|
||||||
expect(mockPreivewChange).toHaveBeenCalledTimes(2);
|
|
||||||
viewport.togglePreview();
|
|
||||||
expect(viewport.getViewport()).toBe('preview-pc');
|
|
||||||
expect(mockViewportChange).toHaveBeenCalledTimes(3);
|
|
||||||
expect(mockPreivewChange).toHaveBeenCalledTimes(3);
|
|
||||||
viewport.togglePreview();
|
|
||||||
expect(viewport.getViewport()).toBe('design-pc');
|
|
||||||
expect(mockViewportChange).toHaveBeenCalledTimes(4);
|
|
||||||
expect(mockPreivewChange).toHaveBeenCalledTimes(4);
|
|
||||||
|
|
||||||
off();
|
|
||||||
offPreview();
|
|
||||||
viewport.togglePreview();
|
|
||||||
expect(mockViewportChange).toHaveBeenCalledTimes(4);
|
|
||||||
expect(mockPreivewChange).toHaveBeenCalledTimes(4);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('setFocusTarget / returnFocus / setFocus / isFocus / onFocusChange', () => {
|
|
||||||
const viewport = new Viewport();
|
|
||||||
const mockFocusChange = jest.fn();
|
|
||||||
const off = viewport.onFocusChange(mockFocusChange);
|
|
||||||
viewport.setFocusTarget(document.createElement('div'));
|
|
||||||
viewport.returnFocus();
|
|
||||||
|
|
||||||
viewport.setFocus(true);
|
|
||||||
expect(viewport.isFocus()).toBeTruthy();
|
|
||||||
expect(mockFocusChange).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockFocusChange).toHaveBeenLastCalledWith(true);
|
|
||||||
viewport.setFocus(false);
|
|
||||||
expect(viewport.isFocus()).toBeFalsy();
|
|
||||||
expect(mockFocusChange).toHaveBeenCalledTimes(2);
|
|
||||||
expect(mockFocusChange).toHaveBeenLastCalledWith(false);
|
|
||||||
|
|
||||||
off();
|
|
||||||
viewport.setFocus(false);
|
|
||||||
expect(mockFocusChange).toHaveBeenCalledTimes(2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('isFullscreen / toggleFullscreen / setFullscreen / onFullscreenChange', () => {
|
|
||||||
const viewport = new Viewport();
|
|
||||||
const mockFullscreenChange = jest.fn();
|
|
||||||
const off = viewport.onFullscreenChange(mockFullscreenChange);
|
|
||||||
|
|
||||||
mockSetFullscreen(false);
|
|
||||||
viewport.setFullscreen(true);
|
|
||||||
mockSetFullscreen(true);
|
|
||||||
expect(viewport.isFullscreen()).toBeTruthy;
|
|
||||||
// expect(mockFullscreenChange).toHaveBeenCalledTimes(1);
|
|
||||||
viewport.setFullscreen(true);
|
|
||||||
// expect(mockFullscreenChange).toHaveBeenCalledTimes(1);
|
|
||||||
|
|
||||||
mockSetFullscreen(true);
|
|
||||||
viewport.setFullscreen(false);
|
|
||||||
mockSetFullscreen(false);
|
|
||||||
expect(viewport.isFullscreen()).toBeFalsy;
|
|
||||||
// expect(mockFullscreenChange).toHaveBeenCalledTimes(2);
|
|
||||||
viewport.setFullscreen(false);
|
|
||||||
// expect(mockFullscreenChange).toHaveBeenCalledTimes(2);
|
|
||||||
|
|
||||||
mockSetFullscreen(true);
|
|
||||||
viewport.toggleFullscreen();
|
|
||||||
mockSetFullscreen(false);
|
|
||||||
// expect(mockFullscreenChange).toHaveBeenCalledTimes(3);
|
|
||||||
viewport.toggleFullscreen();
|
|
||||||
// expect(mockFullscreenChange).toHaveBeenCalledTimes(4);
|
|
||||||
|
|
||||||
off();
|
|
||||||
viewport.toggleFullscreen();
|
|
||||||
// expect(mockFullscreenChange).toHaveBeenCalledTimes(4);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('setWithShell', () => {
|
|
||||||
const viewport = new Viewport();
|
|
||||||
viewport.setWithShell();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('onSlateFixedChange', () => {
|
|
||||||
const viewport = new Viewport();
|
|
||||||
const mockSlateFixedChange = jest.fn();
|
|
||||||
const off = viewport.onSlateFixedChange(mockSlateFixedChange);
|
|
||||||
|
|
||||||
viewport.emitter.emit('slatefixed');
|
|
||||||
expect(mockSlateFixedChange).toHaveBeenCalledTimes(1);
|
|
||||||
off();
|
|
||||||
viewport.emitter.emit('slatefixed');
|
|
||||||
expect(mockSlateFixedChange).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('setGlobalCSS', () => {
|
|
||||||
const viewport = new Viewport();
|
|
||||||
viewport.setGlobalCSS([{
|
|
||||||
media: '*',
|
|
||||||
type: 'URL',
|
|
||||||
content: '//path/to.css',
|
|
||||||
}, {
|
|
||||||
media: 'ALL',
|
|
||||||
type: 'text',
|
|
||||||
content: 'body {font-size: 50px;}',
|
|
||||||
}, {
|
|
||||||
media: '',
|
|
||||||
type: 'text',
|
|
||||||
content: 'body {font-size: 50px;}',
|
|
||||||
}, {
|
|
||||||
media: 'mobile',
|
|
||||||
type: 'text',
|
|
||||||
content: 'body {font-size: 50px;}',
|
|
||||||
}]);
|
|
||||||
|
|
||||||
viewport.cssResourceSet[0].apply();
|
|
||||||
viewport.cssResourceSet[0].init();
|
|
||||||
viewport.cssResourceSet[1].apply();
|
|
||||||
viewport.cssResourceSet[1].apply();
|
|
||||||
viewport.cssResourceSet[1].unmount();
|
|
||||||
|
|
||||||
viewport.setGlobalCSS([{
|
|
||||||
media: '*',
|
|
||||||
type: 'URL',
|
|
||||||
content: '//path/to.css',
|
|
||||||
}, {
|
|
||||||
media: 'ALL',
|
|
||||||
type: 'text',
|
|
||||||
content: 'body {font-size: 50px;}',
|
|
||||||
}, {
|
|
||||||
media: '',
|
|
||||||
type: 'text',
|
|
||||||
content: 'body {font-size: 50px;}',
|
|
||||||
}, {
|
|
||||||
media: 'mobile',
|
|
||||||
type: 'text',
|
|
||||||
content: 'body {font-size: 50px;}',
|
|
||||||
}]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,96 +0,0 @@
|
|||||||
import '../fixtures/window';
|
|
||||||
import { Node, Designer, getConvertedExtraKey } from '@ali/lowcode-designer';
|
|
||||||
import { Editor } from '@ali/lowcode-editor-core';
|
|
||||||
import {
|
|
||||||
compatibleReducer,
|
|
||||||
} from '../../src/props-reducers/downgrade-schema-reducer';
|
|
||||||
import formSchema from '../fixtures/schema/form';
|
|
||||||
|
|
||||||
describe('compatibleReducer 测试', () => {
|
|
||||||
it('compatibleReducer 测试', () => {
|
|
||||||
const downgradedProps = {
|
|
||||||
a: {
|
|
||||||
type: 'JSBlock',
|
|
||||||
value: {
|
|
||||||
componentName: 'Slot',
|
|
||||||
props: {
|
|
||||||
slotTitle: '标题',
|
|
||||||
slotName: 'title',
|
|
||||||
},
|
|
||||||
children: [],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
c: {
|
|
||||||
c1: {
|
|
||||||
type: 'JSBlock',
|
|
||||||
value: {
|
|
||||||
componentName: 'Slot',
|
|
||||||
props: {
|
|
||||||
slotTitle: '标题',
|
|
||||||
slotName: 'title',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
d: {
|
|
||||||
type: 'variable',
|
|
||||||
variable: 'state.a',
|
|
||||||
value: '111',
|
|
||||||
},
|
|
||||||
e: {
|
|
||||||
e1: {
|
|
||||||
type: 'variable',
|
|
||||||
variable: 'state.b',
|
|
||||||
value: '222',
|
|
||||||
},
|
|
||||||
e2: {
|
|
||||||
type: 'JSExpression',
|
|
||||||
value: 'state.b',
|
|
||||||
mock: '222',
|
|
||||||
events: {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(compatibleReducer({
|
|
||||||
a: {
|
|
||||||
type: 'JSSlot',
|
|
||||||
title: '标题',
|
|
||||||
name: 'title',
|
|
||||||
value: [],
|
|
||||||
},
|
|
||||||
c: {
|
|
||||||
c1: {
|
|
||||||
type: 'JSSlot',
|
|
||||||
title: '标题',
|
|
||||||
name: 'title',
|
|
||||||
value: undefined,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
d: {
|
|
||||||
type: 'JSExpression',
|
|
||||||
value: 'state.a',
|
|
||||||
mock: '111',
|
|
||||||
},
|
|
||||||
e: {
|
|
||||||
e1: {
|
|
||||||
type: 'JSExpression',
|
|
||||||
value: 'state.b',
|
|
||||||
mock: '222',
|
|
||||||
},
|
|
||||||
e2: {
|
|
||||||
type: 'JSExpression',
|
|
||||||
value: 'state.b',
|
|
||||||
mock: '222',
|
|
||||||
events: {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})).toEqual(downgradedProps);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('空值', () => {
|
|
||||||
expect(compatibleReducer(null)).toBeNull;
|
|
||||||
expect(compatibleReducer(undefined)).toBeUndefined;
|
|
||||||
expect(compatibleReducer(111)).toBe(111);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,81 +0,0 @@
|
|||||||
import '../fixtures/window';
|
|
||||||
import { Node, Designer, getConvertedExtraKey } from '@ali/lowcode-designer';
|
|
||||||
import { Editor } from '@ali/lowcode-editor-core';
|
|
||||||
import { filterReducer } from '../../src/props-reducers/filter-reducer';
|
|
||||||
import formSchema from '../fixtures/schema/form';
|
|
||||||
|
|
||||||
describe('filterReducer 测试', () => {
|
|
||||||
it('filterReducer 测试 - 有 filters', () => {
|
|
||||||
const mockNode = {
|
|
||||||
componentMeta: {
|
|
||||||
getMetadata() {
|
|
||||||
return {
|
|
||||||
experimental: {
|
|
||||||
filters: [
|
|
||||||
{
|
|
||||||
name: 'shouldBeFitlered',
|
|
||||||
filter: () => false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'keeped',
|
|
||||||
filter: () => true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'throwErr',
|
|
||||||
filter: () => { throw new Error('xxx'); },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'zzz',
|
|
||||||
filter: () => true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
settingEntry: {
|
|
||||||
getProp(propName) {
|
|
||||||
return { name: propName };
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
expect(filterReducer({
|
|
||||||
shouldBeFitlered: 111,
|
|
||||||
keeped: 222,
|
|
||||||
noCorresponingFilter: 222,
|
|
||||||
throwErr: 111,
|
|
||||||
}, mockNode)).toEqual({
|
|
||||||
keeped: 222,
|
|
||||||
noCorresponingFilter: 222,
|
|
||||||
throwErr: 111,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('filterReducer 测试 - 无 filters', () => {
|
|
||||||
const mockNode = {
|
|
||||||
componentMeta: {
|
|
||||||
getMetadata() {
|
|
||||||
return {
|
|
||||||
experimental: {
|
|
||||||
filters: [],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
settingEntry: {
|
|
||||||
getProp(propName) {
|
|
||||||
return { name: propName };
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
expect(filterReducer({
|
|
||||||
shouldBeFitlered: 111,
|
|
||||||
keeped: 222,
|
|
||||||
noCorresponingFilter: 222,
|
|
||||||
}, mockNode)).toEqual({
|
|
||||||
shouldBeFitlered: 111,
|
|
||||||
keeped: 222,
|
|
||||||
noCorresponingFilter: 222,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,488 +0,0 @@
|
|||||||
import '../fixtures/window';
|
|
||||||
import { Node, Designer, getConvertedExtraKey } from '@ali/lowcode-designer';
|
|
||||||
import { Editor, globalContext } from '@ali/lowcode-editor-core';
|
|
||||||
import { initNodeReducer } from '../../src/props-reducers/init-node-reducer';
|
|
||||||
import formSchema from '../fixtures/schema/form';
|
|
||||||
|
|
||||||
describe('initNodeReducer 测试', () => {
|
|
||||||
it('initNodeReducer 测试 - 有 initials', () => {
|
|
||||||
const mockNode = {
|
|
||||||
componentMeta: {
|
|
||||||
getMetadata() {
|
|
||||||
return {
|
|
||||||
experimental: {
|
|
||||||
initials: [
|
|
||||||
{
|
|
||||||
name: 'propA',
|
|
||||||
initial: () => '111',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'propB',
|
|
||||||
initial: () => '111',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'propC',
|
|
||||||
initial: () => {
|
|
||||||
throw new Error('111');
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'propD',
|
|
||||||
initial: () => '111',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'propE',
|
|
||||||
initial: () => '111',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'propF',
|
|
||||||
initial: () => '111',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
prototype: {
|
|
||||||
options: {
|
|
||||||
configure: [
|
|
||||||
{
|
|
||||||
name: 'propF',
|
|
||||||
setter: {
|
|
||||||
type: {
|
|
||||||
displayName: 'I18nSetter',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
settingEntry: {
|
|
||||||
getProp(propName) {
|
|
||||||
return { name: propName };
|
|
||||||
},
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
has() {
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
add() {},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
expect(
|
|
||||||
initNodeReducer(
|
|
||||||
{
|
|
||||||
propA: '111',
|
|
||||||
propC: '222',
|
|
||||||
propD: {
|
|
||||||
type: 'JSExpression',
|
|
||||||
mock: '111',
|
|
||||||
},
|
|
||||||
propE: {
|
|
||||||
type: 'variable',
|
|
||||||
value: '111',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
mockNode,
|
|
||||||
),
|
|
||||||
).toEqual({
|
|
||||||
propA: '111',
|
|
||||||
propB: '111',
|
|
||||||
propC: '222',
|
|
||||||
propD: {
|
|
||||||
type: 'JSExpression',
|
|
||||||
mock: '111',
|
|
||||||
},
|
|
||||||
propE: {
|
|
||||||
type: 'variable',
|
|
||||||
value: '111',
|
|
||||||
},
|
|
||||||
propF: {
|
|
||||||
type: 'i18n',
|
|
||||||
use: 'zh_CN',
|
|
||||||
zh_CN: '111',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('filterReducer 测试 - 无 initials', () => {
|
|
||||||
const mockNode = {
|
|
||||||
componentMeta: {
|
|
||||||
getMetadata() {
|
|
||||||
return {
|
|
||||||
experimental: {},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
settingEntry: {
|
|
||||||
getProp(propName) {
|
|
||||||
return { name: propName };
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
expect(
|
|
||||||
initNodeReducer(
|
|
||||||
{
|
|
||||||
propA: 111,
|
|
||||||
},
|
|
||||||
mockNode,
|
|
||||||
),
|
|
||||||
).toEqual({
|
|
||||||
propA: 111,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('i18n', () => {
|
|
||||||
const mockNode = {
|
|
||||||
componentMeta: {
|
|
||||||
getMetadata() {
|
|
||||||
return {
|
|
||||||
experimental: {
|
|
||||||
initials: [
|
|
||||||
{
|
|
||||||
name: 'propF',
|
|
||||||
initial: () => 111,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
prototype: {
|
|
||||||
options: {
|
|
||||||
configure: [
|
|
||||||
{
|
|
||||||
name: 'propF',
|
|
||||||
setter: {
|
|
||||||
type: {
|
|
||||||
displayName: 'I18nSetter',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
has() {
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
add() {},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
it('isI18NObject(ov): true', () => {
|
|
||||||
expect(
|
|
||||||
initNodeReducer(
|
|
||||||
{
|
|
||||||
propF: {
|
|
||||||
type: 'i18n',
|
|
||||||
zh_CN: '222',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
mockNode,
|
|
||||||
),
|
|
||||||
).toEqual({
|
|
||||||
propF: {
|
|
||||||
type: 'i18n',
|
|
||||||
zh_CN: '222',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('isJSExpression(ov): true', () => {
|
|
||||||
expect(
|
|
||||||
initNodeReducer(
|
|
||||||
{
|
|
||||||
propF: {
|
|
||||||
type: 'JSExpression',
|
|
||||||
value: 'state.a',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
mockNode,
|
|
||||||
),
|
|
||||||
).toEqual({
|
|
||||||
propF: {
|
|
||||||
type: 'JSExpression',
|
|
||||||
value: 'state.a',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('isJSBlock(ov): true', () => {
|
|
||||||
expect(
|
|
||||||
initNodeReducer(
|
|
||||||
{
|
|
||||||
propF: {
|
|
||||||
type: 'JSBlock',
|
|
||||||
value: 'state.a',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
mockNode,
|
|
||||||
),
|
|
||||||
).toEqual({
|
|
||||||
propF: {
|
|
||||||
type: 'JSBlock',
|
|
||||||
value: 'state.a',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('isJSSlot(ov): true', () => {
|
|
||||||
expect(
|
|
||||||
initNodeReducer(
|
|
||||||
{
|
|
||||||
propF: {
|
|
||||||
type: 'JSSlot',
|
|
||||||
value: 'state.a',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
mockNode,
|
|
||||||
),
|
|
||||||
).toEqual({
|
|
||||||
propF: {
|
|
||||||
type: 'JSSlot',
|
|
||||||
value: 'state.a',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('isVariable(ov): true', () => {
|
|
||||||
expect(
|
|
||||||
initNodeReducer(
|
|
||||||
{
|
|
||||||
propF: {
|
|
||||||
type: 'variable',
|
|
||||||
value: 'state.a',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
mockNode,
|
|
||||||
),
|
|
||||||
).toEqual({
|
|
||||||
propF: {
|
|
||||||
type: 'variable',
|
|
||||||
value: 'state.a',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('isI18NObject(v): false', () => {
|
|
||||||
const mockNode = {
|
|
||||||
componentMeta: {
|
|
||||||
getMetadata() {
|
|
||||||
return {
|
|
||||||
experimental: {
|
|
||||||
initials: [
|
|
||||||
{
|
|
||||||
name: 'propF',
|
|
||||||
initial: () => 111,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
prototype: {
|
|
||||||
options: {
|
|
||||||
configure: [
|
|
||||||
{
|
|
||||||
name: 'propF',
|
|
||||||
setter: {
|
|
||||||
type: {
|
|
||||||
displayName: 'I18nSetter',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
has() {
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
add() {},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
expect(
|
|
||||||
initNodeReducer(
|
|
||||||
{
|
|
||||||
propF: {
|
|
||||||
type: 'variable',
|
|
||||||
value: 'state.a',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
mockNode,
|
|
||||||
),
|
|
||||||
).toEqual({
|
|
||||||
propF: {
|
|
||||||
type: 'variable',
|
|
||||||
value: 'state.a',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('isI18NObject(v): false', () => {
|
|
||||||
const mockNode = {
|
|
||||||
componentMeta: {
|
|
||||||
getMetadata() {
|
|
||||||
return {
|
|
||||||
experimental: {
|
|
||||||
initials: [{
|
|
||||||
name: 'propF',
|
|
||||||
initial: () => 111,
|
|
||||||
}],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
prototype: {
|
|
||||||
options: {
|
|
||||||
configure: [
|
|
||||||
{
|
|
||||||
name: 'propF',
|
|
||||||
setter: {
|
|
||||||
type: {
|
|
||||||
displayName: 'I18nSetter',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
has() {
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
add() {},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
expect(
|
|
||||||
initNodeReducer(
|
|
||||||
{
|
|
||||||
propF: {
|
|
||||||
type: 'variable',
|
|
||||||
value: 'state.a',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
mockNode,
|
|
||||||
),
|
|
||||||
).toEqual({
|
|
||||||
propF: {
|
|
||||||
type: 'variable',
|
|
||||||
value: 'state.a',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('成功使用兼容后的 i18n 对象', () => {
|
|
||||||
const mockNode = {
|
|
||||||
componentMeta: {
|
|
||||||
getMetadata() {
|
|
||||||
return {
|
|
||||||
experimental: {
|
|
||||||
initials: [{
|
|
||||||
name: 'propF',
|
|
||||||
initial: () => {
|
|
||||||
return {
|
|
||||||
type: 'i18n',
|
|
||||||
use: 'zh_CN',
|
|
||||||
zh_CN: '111',
|
|
||||||
};
|
|
||||||
},
|
|
||||||
}],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
prototype: {
|
|
||||||
options: {
|
|
||||||
configure: [
|
|
||||||
{
|
|
||||||
name: 'propF',
|
|
||||||
setter: {
|
|
||||||
type: {
|
|
||||||
displayName: 'I18nSetter',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
has() {
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
add() {},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
expect(
|
|
||||||
initNodeReducer(
|
|
||||||
{
|
|
||||||
propF: '111',
|
|
||||||
},
|
|
||||||
mockNode,
|
|
||||||
),
|
|
||||||
).toEqual({
|
|
||||||
propF: {
|
|
||||||
type: 'i18n',
|
|
||||||
use: 'zh_CN',
|
|
||||||
zh_CN: '111',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('fieldId', () => {
|
|
||||||
const mockNode = {
|
|
||||||
componentMeta: {
|
|
||||||
getMetadata() {
|
|
||||||
return {
|
|
||||||
experimental: {
|
|
||||||
initials: [
|
|
||||||
{
|
|
||||||
name: 'propA',
|
|
||||||
initial: () => '111',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
settingEntry: {
|
|
||||||
getProp(propName) {
|
|
||||||
return { name: propName };
|
|
||||||
},
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
has() {
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
add() {},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const editor = new Editor();
|
|
||||||
globalContext.register(editor, Editor);
|
|
||||||
const designer = new Designer({ editor });
|
|
||||||
editor.set('designer', designer);
|
|
||||||
designer.project.open(formSchema);
|
|
||||||
it('fieldId - 已存在', () => {
|
|
||||||
expect(initNodeReducer({
|
|
||||||
propA: '111',
|
|
||||||
fieldId: 'form',
|
|
||||||
}, mockNode)).toEqual({
|
|
||||||
propA: '111',
|
|
||||||
fieldId: undefined,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('fieldId - 已存在,但有全局关闭标识', () => {
|
|
||||||
window.__disable_unique_id_checker__ = true;
|
|
||||||
expect(initNodeReducer({
|
|
||||||
propA: '111',
|
|
||||||
fieldId: 'form',
|
|
||||||
}, mockNode)).toEqual({
|
|
||||||
propA: '111',
|
|
||||||
fieldId: 'form',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,78 +0,0 @@
|
|||||||
import '../fixtures/window';
|
|
||||||
import { Node, Designer, getConvertedExtraKey } from '@ali/lowcode-designer';
|
|
||||||
import { Editor, globalContext } from '@ali/lowcode-editor-core';
|
|
||||||
import { liveLifecycleReducer } from '../../src/props-reducers/live-lifecycle-reducer';
|
|
||||||
import formSchema from '../fixtures/schema/form';
|
|
||||||
|
|
||||||
const editor = new Editor();
|
|
||||||
globalContext.register(editor, Editor);
|
|
||||||
|
|
||||||
it('liveLifecycleReducer 测试 - live', () => {
|
|
||||||
const mockDidMount = jest.fn();
|
|
||||||
const mockWillUnmount = jest.fn();
|
|
||||||
editor.set('designMode', 'live');
|
|
||||||
const newProps = liveLifecycleReducer(
|
|
||||||
{
|
|
||||||
lifeCycles: {
|
|
||||||
didMount: mockDidMount,
|
|
||||||
willUnmount: mockWillUnmount,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
isRoot() {
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const { lifeCycles } = newProps;
|
|
||||||
expect(typeof lifeCycles.componentDidMount).toBe('function');
|
|
||||||
expect(typeof lifeCycles.componentWillUnMount).toBe('function');
|
|
||||||
|
|
||||||
lifeCycles.didMount();
|
|
||||||
lifeCycles.willUnmount();
|
|
||||||
|
|
||||||
expect(mockDidMount).toHaveBeenCalled();
|
|
||||||
expect(mockWillUnmount).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('liveLifecycleReducer 测试 - design', () => {
|
|
||||||
const mockDidMount = jest.fn();
|
|
||||||
const mockWillUnmount = jest.fn();
|
|
||||||
editor.set('designMode', 'design');
|
|
||||||
const newProps = liveLifecycleReducer(
|
|
||||||
{
|
|
||||||
lifeCycles: {
|
|
||||||
didMount: mockDidMount,
|
|
||||||
willUnmount: mockWillUnmount,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
isRoot() {
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const { lifeCycles } = newProps;
|
|
||||||
expect(lifeCycles).toEqual({});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('liveLifecycleReducer 测试', () => {
|
|
||||||
const mockDidMount = jest.fn();
|
|
||||||
const mockWillUnmount = jest.fn();
|
|
||||||
editor.set('designMode', 'design');
|
|
||||||
const newProps = liveLifecycleReducer(
|
|
||||||
{
|
|
||||||
propA: '111',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
isRoot() {
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const { lifeCycles } = newProps;
|
|
||||||
expect(lifeCycles).toBeUndefined;
|
|
||||||
});
|
|
||||||
@ -1,28 +0,0 @@
|
|||||||
import '../fixtures/window';
|
|
||||||
import { nodeTopFixedReducer } from '../../src/props-reducers/node-top-fixed-reducer';
|
|
||||||
import formSchema from '../fixtures/schema/form';
|
|
||||||
|
|
||||||
it('nodeTopFixedReducer 测试', () => {
|
|
||||||
expect(
|
|
||||||
nodeTopFixedReducer(
|
|
||||||
{
|
|
||||||
propA: '111',
|
|
||||||
},
|
|
||||||
{ componentMeta: { isTopFixed: true } },
|
|
||||||
),
|
|
||||||
).toEqual({
|
|
||||||
propA: '111',
|
|
||||||
__isTopFixed__: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(
|
|
||||||
nodeTopFixedReducer(
|
|
||||||
{
|
|
||||||
propA: '111',
|
|
||||||
},
|
|
||||||
{ componentMeta: { } },
|
|
||||||
),
|
|
||||||
).toEqual({
|
|
||||||
propA: '111',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,62 +0,0 @@
|
|||||||
import '../fixtures/window';
|
|
||||||
import { Node, Designer, getConvertedExtraKey } from '@ali/lowcode-designer';
|
|
||||||
import { Editor, globalContext } from '@ali/lowcode-editor-core';
|
|
||||||
import { removeEmptyPropsReducer } from '../../src/props-reducers/remove-empty-prop-reducer';
|
|
||||||
import formSchema from '../fixtures/schema/form';
|
|
||||||
|
|
||||||
it('removeEmptyPropsReducer 测试', () => {
|
|
||||||
const newProps = removeEmptyPropsReducer(
|
|
||||||
{
|
|
||||||
propA: '111',
|
|
||||||
dataSource: {
|
|
||||||
online: [
|
|
||||||
{
|
|
||||||
options: {
|
|
||||||
params: [
|
|
||||||
{
|
|
||||||
name: 'propA',
|
|
||||||
value: '111',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: '111',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
isRoot() {
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(newProps).toEqual({
|
|
||||||
propA: '111',
|
|
||||||
dataSource: {
|
|
||||||
online: [
|
|
||||||
{
|
|
||||||
options: {
|
|
||||||
params: [{
|
|
||||||
name: 'propA',
|
|
||||||
value: '111',
|
|
||||||
}, {
|
|
||||||
value: '111',
|
|
||||||
}],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
list: [
|
|
||||||
{
|
|
||||||
options: {
|
|
||||||
params: {
|
|
||||||
propA: '111',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,121 +0,0 @@
|
|||||||
import '../fixtures/window';
|
|
||||||
import { Node, Designer, getConvertedExtraKey } from '@ali/lowcode-designer';
|
|
||||||
import { Editor, globalContext } from '@ali/lowcode-editor-core';
|
|
||||||
import { stylePropsReducer } from '../../src/props-reducers/style-reducer';
|
|
||||||
import formSchema from '../fixtures/schema/form';
|
|
||||||
|
|
||||||
const editor: Editor = new Editor();
|
|
||||||
globalContext.register(editor, Editor);
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
// const designer = new Designer({ editor });
|
|
||||||
editor.set('designer', {
|
|
||||||
currentDocument: {
|
|
||||||
simulator: {
|
|
||||||
contentDocument: document,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
// designer.project.open(formSchema);
|
|
||||||
|
|
||||||
describe('stylePropsReducer 测试', () => {
|
|
||||||
it('无 style 相关属性', () => {
|
|
||||||
expect(stylePropsReducer({ propA: 1 })).toEqual({ propA: 1 });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('__style__', () => {
|
|
||||||
const props = {
|
|
||||||
__style__: {
|
|
||||||
'font-size': '50px',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const mockNode = { id: 'id1' };
|
|
||||||
expect(stylePropsReducer(props, mockNode)).toEqual({
|
|
||||||
className: '_css_pesudo_id1',
|
|
||||||
__style__: {
|
|
||||||
'font-size': '50px',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
expect(document.querySelector('#_style_pesudo_id1')).textContent =
|
|
||||||
'._css_pesudo_id1 { font-size: 50px; }';
|
|
||||||
});
|
|
||||||
|
|
||||||
it('__style__ - 无 contentDocument', () => {
|
|
||||||
editor.set('designer', {
|
|
||||||
currentDocument: {
|
|
||||||
simulator: {
|
|
||||||
contentDocument: undefined,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const props = {
|
|
||||||
__style__: {
|
|
||||||
'font-size': '50px',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const mockNode = { id: 'id11' };
|
|
||||||
expect(stylePropsReducer(props, mockNode)).toEqual({
|
|
||||||
__style__: {
|
|
||||||
'font-size': '50px',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
expect(document.querySelector('#_style_pesudo_id11')).toBeNull;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('__style__ - css id 已存在', () => {
|
|
||||||
const s = document.createElement('style');
|
|
||||||
s.setAttribute('type', 'text/css');
|
|
||||||
s.setAttribute('id', '_style_pesudo_id2');
|
|
||||||
document.getElementsByTagName('head')[0].appendChild(s);
|
|
||||||
s.appendChild(document.createTextNode('body {}'));
|
|
||||||
const props = {
|
|
||||||
__style__: {
|
|
||||||
'font-size': '50px',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const mockNode = { id: 'id2' };
|
|
||||||
expect(stylePropsReducer(props, mockNode)).toEqual({
|
|
||||||
className: '_css_pesudo_id2',
|
|
||||||
__style__: {
|
|
||||||
'font-size': '50px',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
expect(document.querySelector('#_style_pesudo_id2')).textContent =
|
|
||||||
'._css_pesudo_id2 { font-size: 50px; }';
|
|
||||||
});
|
|
||||||
|
|
||||||
it('containerStyle', () => {
|
|
||||||
const props = {
|
|
||||||
containerStyle: {
|
|
||||||
'font-size': '50px',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const mockNode = { id: 'id3' };
|
|
||||||
expect(stylePropsReducer(props, mockNode)).toEqual({
|
|
||||||
className: '_css_pesudo_id3',
|
|
||||||
containerStyle: {
|
|
||||||
'font-size': '50px',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
expect(document.querySelector('#_style_pesudo_id3')).textContent =
|
|
||||||
'._css_pesudo_id3 { font-size: 50px; }';
|
|
||||||
});
|
|
||||||
|
|
||||||
it('pageStyle', () => {
|
|
||||||
const props = {
|
|
||||||
pageStyle: {
|
|
||||||
'font-size': '50rpx',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const mockNode = { id: 'id4' };
|
|
||||||
expect(stylePropsReducer(props, mockNode)).toEqual({
|
|
||||||
className: 'engine-document',
|
|
||||||
pageStyle: {
|
|
||||||
'font-size': '50rpx',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
expect(document.querySelector('#_style_pesudo_id4')).textContent =
|
|
||||||
'._css_pesudo_id4 { font-size: 50px; }';
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,107 +0,0 @@
|
|||||||
import '../fixtures/window';
|
|
||||||
import { Node, Designer, getConvertedExtraKey } from '@ali/lowcode-designer';
|
|
||||||
import { Editor } from '@ali/lowcode-editor-core';
|
|
||||||
import {
|
|
||||||
upgradePropsReducer,
|
|
||||||
upgradePageLifeCyclesReducer,
|
|
||||||
} from '../../src/props-reducers/upgrade-reducer';
|
|
||||||
import formSchema from '../fixtures/schema/form';
|
|
||||||
|
|
||||||
describe('upgradePropsReducer 测试', () => {
|
|
||||||
it('upgradePropsReducer 测试', () => {
|
|
||||||
const props = {
|
|
||||||
a: {
|
|
||||||
type: 'JSBlock',
|
|
||||||
value: {
|
|
||||||
componentName: 'Slot',
|
|
||||||
props: {
|
|
||||||
slotTitle: '标题',
|
|
||||||
slotName: 'title',
|
|
||||||
},
|
|
||||||
children: [],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
b: {
|
|
||||||
type: 'JSBlock',
|
|
||||||
value: {
|
|
||||||
componentName: 'Div',
|
|
||||||
props: {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
c: {
|
|
||||||
c1: {
|
|
||||||
type: 'JSBlock',
|
|
||||||
value: {
|
|
||||||
componentName: 'Slot',
|
|
||||||
props: {
|
|
||||||
slotTitle: '标题',
|
|
||||||
slotName: 'title',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
d: {
|
|
||||||
type: 'variable',
|
|
||||||
variable: 'state.a',
|
|
||||||
value: '111',
|
|
||||||
},
|
|
||||||
__slot__haha: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(upgradePropsReducer(props)).toEqual({
|
|
||||||
a: {
|
|
||||||
type: 'JSSlot',
|
|
||||||
title: '标题',
|
|
||||||
name: 'title',
|
|
||||||
value: [],
|
|
||||||
},
|
|
||||||
b: {
|
|
||||||
componentName: 'Div',
|
|
||||||
props: {},
|
|
||||||
},
|
|
||||||
c: {
|
|
||||||
c1: {
|
|
||||||
type: 'JSSlot',
|
|
||||||
title: '标题',
|
|
||||||
name: 'title',
|
|
||||||
value: undefined,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
d: {
|
|
||||||
type: 'JSExpression',
|
|
||||||
value: 'state.a',
|
|
||||||
mock: '111',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('空值', () => {
|
|
||||||
expect(upgradePropsReducer(null)).toBeNull;
|
|
||||||
expect(upgradePropsReducer(undefined)).toBeUndefined;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const editor = new Editor();
|
|
||||||
const designer = new Designer({ editor });
|
|
||||||
designer.project.open(formSchema);
|
|
||||||
|
|
||||||
it('upgradePageLifeCyclesReducer 测试', () => {
|
|
||||||
const rootNode = designer.currentDocument?.rootNode;
|
|
||||||
const mockDidMount = jest.fn();
|
|
||||||
const mockWillUnmount = jest.fn();
|
|
||||||
upgradePageLifeCyclesReducer({
|
|
||||||
didMount: mockDidMount,
|
|
||||||
willUnmount: mockWillUnmount,
|
|
||||||
}, rootNode);
|
|
||||||
|
|
||||||
const lifeCycles = rootNode?.getPropValue(getConvertedExtraKey('lifeCycles'));
|
|
||||||
|
|
||||||
expect(typeof lifeCycles.didMount).toBe('function');
|
|
||||||
expect(typeof lifeCycles.willUnmount).toBe('function');
|
|
||||||
|
|
||||||
lifeCycles.didMount();
|
|
||||||
lifeCycles.willUnmount();
|
|
||||||
|
|
||||||
expect(mockDidMount).toHaveBeenCalled();
|
|
||||||
expect(mockWillUnmount).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
@ -1 +0,0 @@
|
|||||||
export { getIdsFromSchema, getNodeFromSchemaById } from '@ali/lowcode-test-mate/es/utils';
|
|
||||||
@ -1,87 +0,0 @@
|
|||||||
import set from 'lodash/set';
|
|
||||||
import cloneDeep from 'lodash/clonedeep';
|
|
||||||
import '../fixtures/window';
|
|
||||||
// import { Project } from '../../src/project/project';
|
|
||||||
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,23 +0,0 @@
|
|||||||
import set from 'lodash/set';
|
|
||||||
import cloneDeep from 'lodash/clonedeep';
|
|
||||||
import '../fixtures/window';
|
|
||||||
import formSchema from '../fixtures/schema/form';
|
|
||||||
import VisualEngine from '../../src';
|
|
||||||
|
|
||||||
describe('VisualEngine.Exchange 相关 API 测试', () => {
|
|
||||||
it('select / getSelected', () => {
|
|
||||||
const doc = VisualEngine.Pages.addPage(formSchema);
|
|
||||||
VisualEngine.Exchange.select(doc?.getNode('form'));
|
|
||||||
expect(VisualEngine.Exchange.getSelected()?.componentName).toBe('Form');
|
|
||||||
expect(VisualEngine.Exchange.getSelected()?.id).toBe('form');
|
|
||||||
|
|
||||||
// clear selection
|
|
||||||
VisualEngine.Exchange.select();
|
|
||||||
expect(VisualEngine.Exchange.getSelected()).toBeUndefined;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('onIntoView', () => {
|
|
||||||
expect(typeof VisualEngine.Exchange.onIntoView).toBe('function');
|
|
||||||
VisualEngine.Exchange.onIntoView();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,170 +0,0 @@
|
|||||||
import set from 'lodash/set';
|
|
||||||
import cloneDeep from 'lodash/clonedeep';
|
|
||||||
import '../fixtures/window';
|
|
||||||
import formSchema from '../fixtures/schema/form';
|
|
||||||
import VisualEngine, { Prototype } from '../../src';
|
|
||||||
import { Editor } from '@ali/lowcode-editor-core';
|
|
||||||
import { getIdsFromSchema, getNodeFromSchemaById } from '../utils';
|
|
||||||
import divPrototypeConfig from '../fixtures/prototype/div-vision';
|
|
||||||
|
|
||||||
const pageSchema = { componentsTree: [formSchema] };
|
|
||||||
|
|
||||||
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,构造 prototype', () => {
|
|
||||||
const proto = new Prototype(divPrototypeConfig);
|
|
||||||
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', () => {
|
|
||||||
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);
|
|
||||||
expect(docChangeHandler).toHaveBeenCalledTimes(2);
|
|
||||||
expect(docChangeHandler).toHaveBeenLastCalledWith(doc2);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
describe('toData 系列', () => {
|
|
||||||
it('基本的节点模型初始化,模型导出,初始化传入 schema', () => {
|
|
||||||
const doc = VisualEngine.Pages.addPage(pageSchema);
|
|
||||||
const anotherFormSchema = set(cloneDeep(formSchema), 'id', 'page');
|
|
||||||
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');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
import set from 'lodash/set';
|
|
||||||
import cloneDeep from 'lodash/clonedeep';
|
|
||||||
import '../fixtures/window';
|
|
||||||
import formSchema from '../fixtures/schema/form';
|
|
||||||
import { Project } from '../../src';
|
|
||||||
|
|
||||||
describe('VisualEngine.Project 相关 API 测试', () => {
|
|
||||||
it('getSchema / setSchema 系列', () => {
|
|
||||||
Project.setSchema({
|
|
||||||
componentsMap: {},
|
|
||||||
componentsTree: [formSchema],
|
|
||||||
});
|
|
||||||
expect(Project.getSchema()).toEqual({
|
|
||||||
componentsMap: {},
|
|
||||||
componentsTree: [formSchema],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('setConfig', () => {
|
|
||||||
Project.setConfig({ haha: 1 });
|
|
||||||
expect(Project.get('config')).toEqual({
|
|
||||||
haha: 1,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "../../tsconfig.json",
|
|
||||||
"compilerOptions": {
|
|
||||||
"outDir": "lib"
|
|
||||||
},
|
|
||||||
"include": [
|
|
||||||
"./src/"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -33,11 +33,11 @@ lerna run cloud-build --stream
|
|||||||
# mv deploy-space/packages/demo/build $BUILD_DEST
|
# mv deploy-space/packages/demo/build $BUILD_DEST
|
||||||
mv ./packages/react-simulator-renderer/dist/* $BUILD_DEST
|
mv ./packages/react-simulator-renderer/dist/* $BUILD_DEST
|
||||||
mv ./packages/rax-simulator-renderer/dist/* $BUILD_DEST
|
mv ./packages/rax-simulator-renderer/dist/* $BUILD_DEST
|
||||||
#mv deploy-space/packages/editor-preset-vision/dist/* $BUILD_DEST
|
# mv deploy-space/packages/editor-preset-vision/dist/* $BUILD_DEST
|
||||||
mv ./packages/engine/dist/js/* $BUILD_DEST
|
mv ./packages/engine/dist/js/* $BUILD_DEST
|
||||||
mv ./packages/engine/dist/css/* $BUILD_DEST
|
mv ./packages/engine/dist/css/* $BUILD_DEST
|
||||||
mv ./packages/vision-polyfill/dist/js/* $BUILD_DEST
|
# mv ./packages/vision-polyfill/dist/js/* $BUILD_DEST
|
||||||
mv ./packages/vision-polyfill/dist/css/* $BUILD_DEST
|
# mv ./packages/vision-polyfill/dist/css/* $BUILD_DEST
|
||||||
# mv deploy-space/packages/editor-preset-general/dist/* $BUILD_DEST
|
# mv deploy-space/packages/editor-preset-general/dist/* $BUILD_DEST
|
||||||
# cp deploy-space/static/* $BUILD_DEST
|
# cp deploy-space/static/* $BUILD_DEST
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user