chore: merge from develop

This commit is contained in:
JackLian 2024-01-05 16:11:08 +08:00
commit 1261a6f169
69 changed files with 38 additions and 2853 deletions

View File

@ -12,8 +12,6 @@ sidebar_position: 3
| @alilc/lowcode-engine | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/engine |
| @alilc/lowcode-plugin-designer | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/plugin-designer |
| @alilc/lowcode-plugin-outline-pane | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/plugin-outline-pane |
| @alilc/lowcode-rax-renderer | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/rax-renderer |
| @alilc/lowcode-rax-simulator-renderer | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/rax-simulator-renderer |
| @alilc/lowcode-react-renderer | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/react-renderer |
| @alilc/lowcode-react-simulator-renderer | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/react-simulator-renderer |
| @alilc/lowcode-renderer-core | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/renderer-core |

View File

@ -15,15 +15,13 @@ sidebar_position: 2
5. ignitor
6. plugin-designer
7. plugin-outline-pane
8. rax-renderer
9. rax-simulator-renderer
10. react-renderer
11. react-simulator-renderer
12. renderer-core
13. types
14. utils
15. material-parser
16. code-generator
8. react-renderer
9. react-simulator-renderer
10. renderer-core
11. types
12. utils
13. material-parser
14. code-generator
## 2. 引擎官方扩展包
包含了常用的设置器setter、跟 setter 绑定的插件等

View File

@ -11,7 +11,6 @@ sidebar_position: 4
## npm 包与仓库信息
- React 框架渲染 npm 包:@alilc/lowcode-react-renderer
- Rax 框架渲染 npm 包:@alilc/lowcode-rax-renderer
- 仓库:[https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) 下的
- packages/renderer-core
- packages/react-renderer

View File

@ -40,7 +40,6 @@ ReactDOM.render((
), document.getElementById('root'));
```
- rax-renderernpm 包替换为 @alilc/lowcode-rax-renderer
####
### 项目使用示例
> [设计器 demo](https://lowcode-engine.cn/demo/demo-general/index.html)

View File

@ -47,15 +47,7 @@ npm install && npm run setup
[
"https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/react-simulator-renderer.css",
"http://localhost:5555/css/ReactSimulatorRenderer.css"
],
[
"https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/rax-simulator-renderer.js",
"http://localhost:5555/js/RaxSimulatorRenderer.js"
],
[
"https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/rax-simulator-renderer.css",
"http://localhost:5555/css/RaxSimulatorRenderer.css"
],
]
]
}
```

View File

@ -499,7 +499,6 @@ try {
- 说明:组件即将从 DOM 中移除
- componentDidCatch(error, info)
- 说明:组件捕获到异常
- Rax目前没有使用生命周期使用 hooks 替代生命周期;
该对象由一系列 key-value 组成key 为生命周期方法名value 为 JSFunction 的描述,详见下方示例:

View File

@ -1,6 +1,6 @@
{
"name": "@alilc/lowcode-engine-docs",
"version": "1.2.18",
"version": "1.2.19",
"description": "低代码引擎版本化文档",
"license": "MIT",
"files": [

View File

@ -52,7 +52,7 @@
"yarn": "^1.22.17",
"rimraf": "^3.0.2",
"@types/react-router": "5.1.18",
"@alilc/build-plugin-lce": "^0.0.3",
"@alilc/build-plugin-lce": "^0.0.4",
"babel-jest": "^26.5.2",
"@alilc/lowcode-test-mate": "^1.0.1"
},

View File

@ -39,6 +39,7 @@ import {
isDragAnyObject,
isDragNodeObject,
isLocationData,
Logger,
} from '@alilc/lowcode-utils';
import {
isShaken,
@ -72,6 +73,8 @@ import { IScroller } from '../designer/scroller';
import { isElementNode, isDOMNodeVisible } from '../utils/misc';
import { debounce } from 'lodash';
const logger = new Logger({ level: 'warn', bizName: 'designer' });
export type LibraryItem = IPublicTypePackage & {
package: string;
library: string;
@ -122,21 +125,6 @@ const defaultSimulatorUrl = (() => {
return urls;
})();
const defaultRaxSimulatorUrl = (() => {
const publicPath = getPublicPath();
let urls;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [_, prefix = '', dev] = /^(.+?)(\/js)?\/?$/.exec(publicPath) || [];
if (dev) {
urls = [`${prefix}/css/rax-simulator-renderer.css`, `${prefix}/js/rax-simulator-renderer.js`];
} else if (process.env.NODE_ENV === 'production') {
urls = [`${prefix}/rax-simulator-renderer.css`, `${prefix}/rax-simulator-renderer.js`];
} else {
urls = [`${prefix}/rax-simulator-renderer.css`, `${prefix}/rax-simulator-renderer.js`];
}
return urls;
})();
const defaultEnvironment = [
// https://g.alicdn.com/mylib/??react/16.11.0/umd/react.production.min.js,react-dom/16.8.6/umd/react-dom.production.min.js,prop-types/15.7.2/prop-types.min.js
assetItem(
@ -151,17 +139,6 @@ const defaultEnvironment = [
),
];
const defaultRaxEnvironment = [
assetItem(
AssetType.JSText,
'window.Rax=parent.Rax;window.React=parent.React;window.ReactDOM=parent.ReactDOM;window.VisualEngineUtils=parent.VisualEngineUtils;window.VisualEngine=parent.VisualEngine',
),
assetItem(
AssetType.JSText,
'window.PropTypes=parent.PropTypes;React.PropTypes=parent.PropTypes; window.__REACT_DEVTOOLS_GLOBAL_HOOK__ = window.parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;',
),
];
export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProps> {
readonly isSimulator = true;
@ -467,11 +444,15 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
const libraryAsset: AssetList = this.buildLibrary();
if (this.renderEnv === 'rax') {
logger.error('After LowcodeEngine v1.3.0, Rax is no longer supported.');
}
const vendors = [
// required & use once
assetBundle(
this.get('environment') ||
(this.renderEnv === 'rax' ? defaultRaxEnvironment : defaultEnvironment),
defaultEnvironment,
AssetLevel.Environment,
),
// required & use once
@ -484,7 +465,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
// required & use once
assetBundle(
this.get('simulatorUrl') ||
(this.renderEnv === 'rax' ? defaultRaxSimulatorUrl : defaultSimulatorUrl),
defaultSimulatorUrl,
AssetLevel.Runtime,
),
];

View File

@ -1,4 +1,4 @@
import { IPublicTypeCustomView, IPublicModelEditor, IPublicModelSettingTopEntry } from '@alilc/lowcode-types';
import { IPublicTypeCustomView, IPublicModelEditor, IPublicModelSettingTopEntry, IPublicApiSetters } from '@alilc/lowcode-types';
import { isCustomView } from '@alilc/lowcode-utils';
import { computed, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core';
import { ISettingEntry } from './setting-entry-type';
@ -6,7 +6,6 @@ import { ISettingField, SettingField } from './setting-field';
import { INode } from '../../document';
import type { IComponentMeta } from '../../component-meta';
import { IDesigner } from '../designer';
import { Setters } from '@alilc/lowcode-shell';
function generateSessionId(nodes: INode[]) {
return nodes
@ -19,18 +18,18 @@ export interface ISettingTopEntry extends ISettingEntry, IPublicModelSettingTopE
INode,
ISettingField
> {
purge(): void;
items: Array<ISettingField | IPublicTypeCustomView>;
readonly top: ISettingTopEntry;
readonly parent: ISettingTopEntry;
readonly path: never[];
items: Array<ISettingField | IPublicTypeCustomView>;
componentMeta: IComponentMeta | null;
purge(): void;
getExtraPropValue(propName: string): void;
setExtraPropValue(propName: string, value: any): void;
@ -92,7 +91,7 @@ export class SettingTopEntry implements ISettingTopEntry {
readonly designer: IDesigner | undefined;
readonly setters: Setters;
readonly setters: IPublicApiSetters;
disposeFunctions: any[] = [];
@ -103,7 +102,7 @@ export class SettingTopEntry implements ISettingTopEntry {
this.id = generateSessionId(nodes);
this.first = nodes[0];
this.designer = this.first.document?.designer;
this.setters = editor.get('setters') as Setters;
this.setters = editor.get('setters') as IPublicApiSetters;
// setups
this.setupComponentMeta();

View File

@ -44,7 +44,7 @@ const VALID_ENGINE_OPTIONS = {
},
renderEnv: {
type: 'string',
enum: ['react', 'rax', 'any string value'],
enum: ['react', 'any string value'],
default: 'react',
description: '渲染器类型',
},

View File

@ -126,7 +126,7 @@ https://cdn.jsdelivr.net/npm/@alilc/lowcode-react-simulator-renderer@1.0.18/dist
```
#### 方式 5使用自有 cdn
将源码中 packages/engine/dist 和 packages/(react|rax)-simulator-renderer/dist 下的文件传至你的 cdn 提供商
将源码中 packages/engine/dist 和 packages/react-simulator-renderer/dist 下的文件传至你的 cdn 提供商
## 🔗 相关链接

View File

@ -126,7 +126,7 @@ https://cdn.jsdelivr.net/npm/@alilc/lowcode-react-simulator-renderer@1.0.18/dist
```
#### Method 5: Use your own cdn
Pass the files under packages/engine/dist and packages/(react|rax)-simulator-renderer/dist in the source code to your cdn provider
Pass the files under packages/engine/dist and packages/react-simulator-renderer/dist in the source code to your cdn provider
## 🔗 Related Links

View File

@ -1,8 +1,7 @@
{
"entry": {
"AliLowCodeEngine": "../engine/src/index.ts",
"ReactSimulatorRenderer": "../react-simulator-renderer/src/index.ts",
"RaxSimulatorRenderer": "../rax-simulator-renderer/src/index.ts"
"ReactSimulatorRenderer": "../react-simulator-renderer/src/index.ts"
},
"vendor": false,
"devServer": {

View File

@ -1,49 +0,0 @@
# Rax Renderer
Rax 渲染模块。
## 安装
```
$ npm install @alilc/lowcode-rax-renderer --save
```
## 使用
```js
import { createElement, render } from 'rax';
import DriverUniversal from 'driver-universal';
import RaxRenderer from '@ali/lowcode-rax-renderer';
const components = {
View,
Text
};
const schema = {
componentName: 'Page',
fileName: 'home',
children: [
{
componentName: 'View',
children: [
{
componentName: 'Text',
props: {
type: 'primary'
},
children: ['Welcome to Your Rax App']
}
]
}
]
};
render(
<RaxRenderer
schema={schema}
components={components}
/>,
document.getElementById('root'), { driver: DriverUniversal }
);
```

View File

@ -1,11 +0,0 @@
{
"plugins": [
[
"build-plugin-rax-component",
{
"type": "rax",
"targets": ["web"]
}
]
]
}

View File

@ -1,35 +0,0 @@
import { createElement, render } from 'rax';
import DriverUniversal from 'driver-universal';
import View from 'rax-view';
import Text from 'rax-text';
import { Engine } from '../src/index';
const components = {
View,
Text,
};
const schema = {
componentName: 'Page',
fileName: 'home',
props: {},
children: [
{
componentName: 'View',
props: {},
children: [
{
componentName: 'Text',
props: {
type: 'primary',
},
children: ['Welcome to Your Rax App!'],
},
],
},
],
};
render(<Engine schema={schema} components={components} />, document.getElementById('root'), {
driver: DriverUniversal,
});

View File

@ -1 +0,0 @@
App({});

View File

@ -1,6 +0,0 @@
{
"pages": ["pages/index"],
"window": {
"defaultTitle": "demo"
}
}

View File

@ -1 +0,0 @@
<my-component></my-component>

View File

@ -1,4 +0,0 @@
Page({
onLoad() {},
onShow() {},
});

View File

@ -1,6 +0,0 @@
{
"defaultTitle": "Miniapp Rax Text demo",
"usingComponents": {
"my-component": "../components/Target/index"
}
}

View File

@ -1 +0,0 @@
App({});

View File

@ -1,6 +0,0 @@
{
"pages": ["pages/index"],
"window": {
"title": "demo"
}
}

View File

@ -1,4 +0,0 @@
Page({
onLoad() {},
onShow() {},
});

View File

@ -1,6 +0,0 @@
{
"title": "Wechat MiniProgram Rax Text demo",
"usingComponents": {
"my-component": "../components/Target/index"
}
}

View File

@ -1 +0,0 @@
<my-component></my-component>

View File

@ -1,54 +0,0 @@
{
"name": "@alilc/lowcode-rax-renderer",
"version": "1.3.0-beta.0",
"description": "Rax renderer for Ali lowCode engine",
"main": "lib/index.js",
"module": "es/index.js",
"miniappConfig": {
"main": "lib/miniapp/index",
"main:wechat": "lib/wechat-miniprogram/index"
},
"files": [
"dist",
"es",
"lib"
],
"keywords": [
"low-code",
"lowcode",
"Rax"
],
"engines": {
"npm": ">=3.0.0"
},
"peerDependencies": {
"prop-types": "^15.7.2",
"rax": "^1.1.0"
},
"scripts": {
"start": "build-scripts start",
"build": "build-scripts build"
},
"dependencies": {
"@alilc/lowcode-renderer-core": "1.3.0-beta.0",
"@alilc/lowcode-utils": "1.3.0-beta.0",
"rax-find-dom-node": "^1.0.1"
},
"devDependencies": {
"@alib/build-scripts": "^0.1.0",
"build-plugin-rax-component": "^0.2.11",
"driver-universal": "^3.1.3"
},
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org/"
},
"repository": {
"type": "http",
"url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/rax-renderer"
},
"license": "MIT",
"homepage": "https://github.com/alibaba/lowcode-engine/#readme",
"gitHead": "b279a68054fba2f891579287da5f03c26df9e5b8",
"bugs": "https://github.com/alibaba/lowcode-engine/issues"
}

View File

@ -1,82 +0,0 @@
// @ts-nocheck
import { Component, forwardRef } from 'rax';
import PropTypes from 'prop-types';
import { AppHelper } from '@alilc/lowcode-utils';
import { utils, contextFactory } from '@alilc/lowcode-renderer-core';
import componentRendererFactory from '../renderer/component';
import blockRendererFactory from '../renderer/block';
const { forEach, isFileSchema } = utils;
export default function compFactory(schema, components = {}, componentsMap = {}, config = {}) {
// 自定义组件需要有自己独立的appHelper
const appHelper = new AppHelper(config);
const CompRenderer = componentRendererFactory();
const BlockRenderer = blockRendererFactory();
const AppContext = contextFactory();
class LNCompView extends Component {
static displayName = 'LceCompFactory';
static version = config.version || '0.0.0';
static contextType = AppContext;
static propTypes = {
forwardedRef: PropTypes.func,
};
render() {
if (!schema || schema.componentName !== 'Component' || !isFileSchema(schema)) {
console.warn('自定义组件模型结构异常!');
return null;
}
const { forwardedRef, ...otherProps } = this.props;
// 低代码组件透传应用上下文
const ctx = ['utils', 'constants', 'history', 'location', 'match'];
ctx.forEach(key => {
if (!appHelper[key] && this.context?.appHelper && this.context?.appHelper[key]) {
appHelper.set(key, this.context.appHelper[key]);
}
});
// 支持通过context透传国际化配置
const localeProps = {};
const { locale, messages } = this.context;
if (locale && messages && messages[schema.fileName]) {
localeProps.locale = locale;
localeProps.messages = messages[schema.fileName];
}
const props = {
...schema.defaultProps,
...localeProps,
...otherProps,
__schema: schema,
ref: forwardedRef,
};
return (
<AppContext.Consumer>
{context => {
this.context = context;
return (
<CompRenderer
{...props}
__appHelper={appHelper}
__components={{ ...components, Component: CompRenderer, Block: BlockRenderer }}
__componentsMap={componentsMap}
/>
);
}}
</AppContext.Consumer>
);
}
}
const ResComp = forwardRef((props, ref) => <LNCompView {...props} forwardedRef={ref} />);
forEach(schema.static, (val, key) => {
ResComp[key] = val;
});
ResComp.version = config.version || '0.0.0';
return ResComp;
}

View File

@ -1,52 +0,0 @@
import { Component, PureComponent, createElement, createContext, forwardRef } from 'rax';
import findDOMNode from 'rax-find-dom-node';
import {
adapter,
addonRendererFactory,
tempRendererFactory,
rendererFactory,
} from '@alilc/lowcode-renderer-core';
import pageRendererFactory from './renderer/page';
import componentRendererFactory from './renderer/component';
import blockRendererFactory from './renderer/block';
import CompFactory from './hoc/compFactory';
adapter.setRuntime({
Component,
PureComponent,
createContext,
createElement,
forwardRef,
findDOMNode,
});
adapter.setRenderers({
PageRenderer: pageRendererFactory(),
ComponentRenderer: componentRendererFactory(),
BlockRenderer: blockRendererFactory(),
AddonRenderer: addonRendererFactory(),
TempRenderer: tempRendererFactory(),
});
function factory() {
const Renderer = rendererFactory();
return class extends Renderer {
constructor(props: any, context: any) {
super(props, context);
}
isValidComponent(obj: any) {
return obj?.prototype?.setState || obj?.prototype instanceof Component;
}
};
}
const RaxRenderer: any = factory();
const Engine: any = RaxRenderer;
export {
Engine,
CompFactory,
};
export default RaxRenderer;

View File

@ -1,25 +0,0 @@
import { blockRendererFactory, types } from '@alilc/lowcode-renderer-core';
const raxBlockRendererFactory: () => any = () => {
const OriginBlock = blockRendererFactory();
return class BlockRenderer extends OriginBlock {
render() {
// @ts-ignore
const that: types.IRenderer = this;
const { __schema, __components } = that.props;
if (that.__checkSchema(__schema)) {
return '区块 schema 结构异常!';
}
that.__debug(`render - ${__schema.fileName}`);
const children = ((context) => {
that.context = context;
that.__generateCtx({});
that.__render();
return that.__renderComp((__components as any)?.Block, { blockContext: that });
});
return that.__renderContextConsumer(children);
}
};
};
export default raxBlockRendererFactory;

View File

@ -1,37 +0,0 @@
import { componentRendererFactory, types } from '@alilc/lowcode-renderer-core';
const raxComponentRendererFactory: () => any = () => {
const OriginComponent = componentRendererFactory();
return class ComponentRenderer extends OriginComponent {
render() {
// @ts-ignore
const that: types.IRenderer = this;
const { __schema, __components } = that.props;
if (that.__checkSchema(__schema)) {
return '自定义组件 schema 结构异常!';
}
that.__debug(`render - ${__schema.fileName}`);
const { noContainer } = that.__parseData(__schema.props);
const children = ((context) => {
that.context = context;
that.__generateCtx({ component: that });
that.__render();
// 传 null使用内置的 div 来渲染,解决在页面中渲染 vc-component 报错的问题
return that.__renderComp(null, {
compContext: that,
blockContext: that,
});
});
const content = that.__renderContextConsumer(children);
if (noContainer) {
return content;
}
return that.__renderContent(content);
}
};
};
export default raxComponentRendererFactory;

View File

@ -1,38 +0,0 @@
import { pageRendererFactory, types } from '@alilc/lowcode-renderer-core';
const raxPageRendererFactory: () => any = () => {
const OriginPage = pageRendererFactory();
return class PageRenderer extends OriginPage {
async componentDidUpdate() {
// @ts-ignore
super.componentDidUpdate(...arguments);
}
render() {
// @ts-ignore
const that: types.IRenderer = this;
const { __schema, __components } = that.props;
if (that.__checkSchema(__schema)) {
return '页面 schema 结构异常!';
}
that.__debug(`render - ${__schema?.fileName}`);
const { Page } = __components as any;
if (Page) {
const children = ((context) => {
that.context = context;
that.__render();
return that.__renderComp(Page, { pageContext: that });
});
return that.__renderContextConsumer(children);
}
return that.__renderContent(that.__renderContextConsumer((context) => {
that.context = context;
return that.__renderContextProvider({ pageContext: that });
}));
}
};
};
export default raxPageRendererFactory;

View File

@ -1,26 +0,0 @@
{
"compilerOptions": {
"lib": ["es2015", "dom"],
"target": "esnext",
"module": "esnext",
"moduleResolution": "node",
"strict": false,
"strictPropertyInitialization": false,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"jsx": "react",
"jsxFactory": "createElement",
"importHelpers": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"sourceMap": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"outDir": "lib"
},
"exclude": ["test", "lib", "es", "node_modules"],
"include": [
"src"
]
}

View File

@ -1,9 +0,0 @@
{
"plugins": [
["@babel/plugin-transform-react-jsx", {
"pragma": "createElement", // default pragma is React.createElement
"pragmaFrag": "createFragment", // default is React.Fragment
"throwIfNamespace": false // defaults to true
}]
]
}

View File

@ -1 +0,0 @@
module.exports = require('../../babel.config');

View File

@ -1,3 +0,0 @@
{
"plugins": ["@alilc/build-plugin-lce", "./build.plugin.js"]
}

View File

@ -1,5 +0,0 @@
module.exports = ({ onGetWebpackConfig }) => {
onGetWebpackConfig((config) => {
config.performance.hints(false);
});
};

View File

@ -1,38 +0,0 @@
{
"entry": {
"rax-simulator-renderer": "src/index"
},
"sourceMap": true,
"library": "___RaxSimulatorRenderer___",
"libraryTarget": "umd",
"externals": {
"react": "var window.React",
"react-dom": "var window.ReactDOM",
"prop-types": "var window.PropTypes",
"@alifd/next": "var Next",
"@alilc/lowcode-engine-ext": "var window.AliLowCodeEngineExt",
"rax": "var window.Rax",
"moment": "var moment",
"lodash": "var _"
},
"polyfill": false,
"outputDir": "dist",
"vendor": false,
"ignoreHtmlTemplate": true,
"plugins": [
"build-plugin-react-app",
[
"build-plugin-fusion",
{
"externalNext": "umd"
}
],
[
"build-plugin-moment-locales",
{
"locales": ["zh-cn"]
}
],
"./build.plugin.js"
]
}

View File

@ -1,55 +0,0 @@
{
"name": "@alilc/lowcode-rax-simulator-renderer",
"version": "1.3.0-beta.0",
"description": "rax simulator renderer for alibaba lowcode designer",
"main": "lib/index.js",
"module": "es/index.js",
"license": "MIT",
"files": [
"dist"
],
"scripts": {
"build": "NODE_OPTIONS=--max_old_space_size=8192 build-scripts build",
"build:umd": "build-scripts build --config build.umd.json"
},
"dependencies": {
"@alilc/lowcode-designer": "1.3.0-beta.0",
"@alilc/lowcode-rax-renderer": "1.3.0-beta.0",
"@alilc/lowcode-types": "1.3.0-beta.0",
"@alilc/lowcode-utils": "1.3.0-beta.0",
"classnames": "^2.2.6",
"driver-universal": "^3.1.3",
"history": "^5.0.0",
"lodash": "^4.17.19",
"mobx": "^6.3.0",
"mobx-react": "^7.2.0",
"path-to-regexp": "3.2.0",
"rax-find-dom-node": "^1.0.0",
"react": "^16",
"react-dom": "^16.7.0"
},
"devDependencies": {
"@alib/build-scripts": "^0.1.18",
"@babel/plugin-transform-react-jsx": "^7.10.4",
"@types/classnames": "^2.2.7",
"@types/node": "^13.7.1",
"@types/rax": "^1.0.0",
"@types/react": "^16",
"@types/react-dom": "^16",
"build-plugin-rax-component": "^0.2.11"
},
"peerDependencies": {
"rax": "^1.1.0"
},
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org/"
},
"repository": {
"type": "http",
"url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/rax-simulator-renderer"
},
"homepage": "https://github.com/alibaba/lowcode-engine/#readme",
"gitHead": "b279a68054fba2f891579287da5f03c26df9e5b8",
"bugs": "https://github.com/alibaba/lowcode-engine/issues"
}

View File

@ -1,34 +0,0 @@
import { Component } from 'rax';
import lg from '@ali/vu-logger';
import './index.less';
export class UnknownComponent extends Component {
props: {
_componentName: string;
};
render() {
lg.log('ERROR_NO_COMPONENT_VIEW');
lg.error('Error component information:', this.props);
return <div className="engine-unknow-component"> {this.props._componentName} </div>;
}
}
export class FaultComponent extends Component {
props: {
_componentName: string;
};
render() {
return <div className="engine-fault-component"> {this.props._componentName} </div>;
}
}
export class HiddenComponent extends Component {
render() {
return <div className="engine-hidden-component"></div>;
}
}
export default { FaultComponent, HiddenComponent, UnknownComponent };

View File

@ -1,251 +0,0 @@
import { Component } from 'rax';
class Leaf extends Component {
static displayName = 'Leaf';
static componentMetadata = {
componentName: 'Leaf',
configure: {
props: [{
name: 'children',
setter: 'StringSetter',
}],
// events/className/style/general/directives
supports: false,
},
};
render() {
const { children } = this.props;
return children;
}
}
export default Leaf;
// import { Component, createElement } from 'rax';
// import findDOMNode from 'rax-find-dom-node';
// import { each, get, omit } from 'lodash';
// import { getView, setNativeNode, createNodeStyleSheet } from '../renderUtils';
// import { FaultComponent, HiddenComponent, UnknownComponent } from '../UnusualComponent';
// export interface ILeaf {
// leaf: any;
// }
// export default class Leaf extends Component<ILeaf, {}> {
// static displayName = 'Leaf';
// state = {
// hasError: false,
// };
// willDetach: any[];
// styleSheet: any;
// context: any;
// refs: any;
// componentWillMount() {
// const { leaf } = this.props;
// this.willDetach = [
// leaf.onPropsChange(() => {
// // 强制刷新
// this.setState(this.state);
// }),
// leaf.onChildrenChange(() => {
// // 强制刷新
// this.setState(this.state);
// }),
// leaf.onStatusChange((status: { dropping: boolean }, field: string) => {
// // console.log({...status}, field)
// if (status.dropping !== false) {
// // 当 dropping 为 Insertion 对象时,强制渲染会出错,原因待查
// return;
// }
// if (field === 'dragging' || field === 'dropping' || field === 'pseudo' || field === 'visibility') {
// // 强制刷新
// this.setState(this.state);
// }
// }),
// ];
// /**
// * while props replaced
// * bind the new event on it
// */
// leaf.onPropsReplace(() => {
// this.willDetach[0]();
// this.willDetach[0] = leaf.onPropsChange(() => {
// // 强制刷新
// this.setState(this.state);
// });
// });
// }
// componentDidMount() {
// this.modifyDOM();
// }
// shouldComponentUpdate() {
// // forceUpdate 的替代方案
// return true;
// // const pageCanRefresh = this.leaf.getPage().canRefresh();
// // if (pageCanRefresh) {
// // return pageCanRefresh;
// // }
// // const getExtProps = obj => {
// // const { leaf, ...props } = obj;
// // return props;
// // };
// // return !shallowEqual(getExtProps(this.props), getExtProps(nextProps));
// }
// componentDidUpdate() {
// this.modifyDOM();
// }
// componentWillUnmount() {
// if (this.willDetach) {
// this.willDetach.forEach((off) => off());
// }
// setNativeNode(this.props.leaf, null);
// }
// componentDidCatch() {
// this.setState({ hasError: true }, () => {
// console.log('error');
// });
// }
// modifyDOM() {
// const shell = findDOMNode(this);
// const { leaf } = this.props;
// // 与 React 不同rax 的 findDOMNode 找不到节点时,
// // shell 会是 <!-- empty -->,而不是 null
// // 所以这里进行是否为注释的判断
// if (shell && shell.nodeType !== window.Node.COMMENT_NODE) {
// setNativeNode(leaf, shell);
// if (leaf.getStatus('dragging')) {
// get(shell, 'classList').add('engine-dragging');
// } else {
// get(shell, 'classList').remove('engine-dragging');
// }
// each(get(shell, 'classList'), (cls) => {
// if (cls.substring(0, 8) === '-pseudo-') {
// get(shell, 'classList').remove(cls);
// }
// });
// const pseudo = leaf.getStatus('pseudo');
// if (pseudo) {
// get(shell, 'classList').add(`-pseudo-${pseudo}`);
// }
// } else {
// setNativeNode(leaf, null);
// }
// }
// render() {
// const props = omit(this.props, ['leaf']);
// const { leaf } = this.props;
// const componentName = leaf.getComponentName();
// const View = getView(componentName);
// const newProps = {
// _componentName: componentName,
// };
// if (!View) {
// return createElement(UnknownComponent, {
// // _componentName: componentName,
// ...newProps,
// });
// }
// let staticProps = {
// ...leaf.getStaticProps(false),
// ...props,
// _componentName: componentName,
// _leaf: leaf,
// componentId: leaf.getId(),
// };
// if (!leaf.isVisibleInPane()) {
// return null;
// }
// if (!leaf.isVisible()) {
// return createElement(HiddenComponent, {
// ...staticProps,
// });
// }
// if (this.state.hasError) {
// return createElement(FaultComponent, {
// // _componentName: componentName,
// ...newProps,
// });
// }
// if (this.styleSheet) {
// this.styleSheet.parentNode.removeChild(this.styleSheet);
// }
// this.styleSheet = createNodeStyleSheet(staticProps);
// if (leaf.ableToModifyChildren()) {
// const children = leaf
// .getChildren()
// .filter((child: any) => child.getComponentName() !== 'Slot')
// .map((child: any) =>
// createElement(Leaf, {
// key: child.getId(),
// leaf: child,
// }),
// );
// // const insertion = leaf.getStatus('dropping');
// // InsertionGhost 都是React节点,用Rax渲染会报错后面这些节点需要通过Rax组件来实现
// // if (children.length < 1 && insertion && insertion.getIndex() !== null) {
// // //children = [];
// // children = [<InsertionGhost key="insertion" />];
// // } else if (insertion && insertion.isNearEdge()) {
// // if (insertion.isNearAfter()) {
// // children.push(<InsertionGhost key="insertion" />);
// // } else {
// // children.unshift(<InsertionGhost key="insertion" />);
// // }
// // }
// staticProps = {
// ...staticProps,
// ...this.processSlots(this.props.leaf.getChildren()),
// };
// return createElement(
// View,
// {
// ...staticProps,
// },
// children,
// );
// }
// return createElement(View, {
// ...staticProps,
// });
// }
// processSlots(children: Rax.RaxNodeArray) {
// const slots: any = {};
// children &&
// children.length &&
// children.forEach((child: any) => {
// if (child.getComponentName() === 'Slot') {
// slots[child.getPropValue('slotName')] = <Leaf key={child.getId()} leaf={child} />;
// }
// });
// return slots;
// }
// }

View File

@ -1,83 +0,0 @@
import { isObject } from 'lodash';
import { css } from '@alilc/lowcode-utils';
const { toCss } = css;
const engine = (window as any).VisualEngine;
const { Trunk, Viewport } = engine;
export const NativeNodeCache: any = {};
function ucfirst(s: string) {
return s.charAt(0).toUpperCase() + s.substring(1);
}
export function shallowEqual(obj: { [key: string]: string }, tObj: { [key: string]: string }) {
for (const i in obj) {
if (Object.prototype.hasOwnProperty.call(obj, i) && obj[i] !== tObj[i]) {
return false;
}
}
return true;
}
export function createNodeStyleSheet(props: any) {
if (props && props.fieldId) {
let styleProp = props.__style__;
if (isObject(styleProp)) {
styleProp = toCss(styleProp);
}
if (typeof styleProp === 'string') {
const s = document.createElement('style');
const cssId = `_style_pesudo_${ props.fieldId}`;
const cssClass = `_css_pesudo_${ props.fieldId}`;
props.className = cssClass;
s.setAttribute('type', 'text/css');
s.setAttribute('id', cssId);
document.getElementsByTagName('head')[0].appendChild(s);
s.appendChild(
document.createTextNode(
styleProp
.replace(/(\d+)rpx/g, (a, b) => {
return `${b / 2}px`;
})
.replace(/:root/g, `.${ cssClass}`),
),
);
return s;
}
}
}
export function setNativeNode(leaf: any, node: Rax.RaxNode) {
const id = leaf.getId();
if (NativeNodeCache[id] === node) {
return;
}
NativeNodeCache[id] = node;
leaf.mountChange();
}
export function getView(componentName: string) {
// let view = new Trunk().getPrototypeView(componentName);
let view = Trunk.getPrototypeView(componentName);
if (!view) {
return null;
}
const viewport = Viewport.getViewport();
if (viewport) {
const [mode, device] = viewport.split('-', 2).map(ucfirst);
if (view.hasOwnProperty(device)) {
view = view[device];
}
if (view.hasOwnProperty(mode)) {
view = view[mode];
}
}
return view;
}

View File

@ -1,54 +0,0 @@
import { Component } from 'rax';
class Slot extends Component {
static displayName = 'Slot';
static componentMetadata = {
componentName: 'Slot',
configure: {
props: [{
name: '___title',
title: {
type: 'i18n',
'en-US': 'Slot Title',
'zh-CN': '插槽标题',
},
setter: 'StringSetter',
defaultValue: '插槽容器',
}, {
name: '___params',
title: {
type: 'i18n',
'en-US': 'Slot Params',
'zh-CN': '插槽入参',
},
setter: {
componentName: 'ArraySetter',
props: {
itemSetter: {
componentName: 'StringSetter',
props: {
placeholder: {
type: 'i18n',
'zh-CN': '参数名称',
'en-US': 'Argument Name',
},
},
},
},
},
}],
// events/className/style/general/directives
supports: false,
},
};
render() {
const { children } = this.props;
return (
<div className="lc-container">{children}</div>
);
}
}
export default Slot;

View File

@ -1,4 +0,0 @@
// NOTE: 仅做类型标注,切勿做其它用途
import { BuiltinSimulatorHost } from '@alilc/lowcode-designer';
export const host: BuiltinSimulatorHost = (window as any).LCSimulatorHost;

View File

@ -1,2 +0,0 @@
declare module 'rax-find-dom-node';
declare module '@alilc/lowcode-rax-renderer/lib/index';

View File

@ -1,7 +0,0 @@
import renderer from './renderer';
if (typeof window !== 'undefined') {
(window as any).SimulatorRenderer = renderer;
}
export default renderer;

View File

@ -1,288 +0,0 @@
// Inspired by react-router and universal-router
import { useState, useEffect, useLayoutEffect, createElement } from 'rax';
import pathToRegexp from 'path-to-regexp';
const cache = {};
function decodeParam(val) {
try {
return decodeURIComponent(val);
} catch (err) {
return val;
}
}
function matchPath(route, pathname, parentParams) {
let { path, routes, exact: end = true, strict = false, sensitive = false } = route;
// If not has path or has routes that should do not exact match
if (path == null || routes) {
end = false;
}
// Default path is empty
path = path || '';
const regexpCacheKey = `${path}|${end}|${strict}|${sensitive}`;
const keysCacheKey = `${regexpCacheKey }|`;
let regexp = cache[regexpCacheKey];
const keys = cache[keysCacheKey] || [];
if (!regexp) {
regexp = pathToRegexp(path, keys, {
end,
strict,
sensitive,
});
cache[regexpCacheKey] = regexp;
cache[keysCacheKey] = keys;
}
const result = regexp.exec(pathname);
if (!result) {
return null;
}
const url = result[0];
const params = { ...parentParams, history: router.history, location: router.history.location };
for (let i = 1; i < result.length; i++) {
const key = keys[i - 1];
const prop = key.name;
const value = result[i];
if (value !== undefined || !Object.prototype.hasOwnProperty.call(params, prop)) {
if (key.repeat) {
params[prop] = value ? value.split(key.delimiter).map(decodeParam) : [];
} else {
params[prop] = value ? decodeParam(value) : value;
}
}
}
return {
path: !end && url.charAt(url.length - 1) === '/' ? url.slice(1) : url,
params,
};
}
function matchRoute(route, baseUrl, pathname, parentParams) {
let matched;
let childMatches;
let childIndex = 0;
return {
next() {
if (!matched) {
matched = matchPath(route, pathname, parentParams);
if (matched) {
return {
done: false,
$: {
route,
baseUrl,
path: matched.path,
params: matched.params,
},
};
}
}
if (matched && route.routes) {
while (childIndex < route.routes.length) {
if (!childMatches) {
const childRoute = route.routes[childIndex];
childRoute.parent = route;
childMatches = matchRoute(
childRoute,
baseUrl + matched.path,
pathname.slice(matched.path.length),
matched.params,
);
}
const childMatch = childMatches.next();
if (!childMatch.done) {
return {
done: false,
$: childMatch.$,
};
}
childMatches = null;
childIndex++;
}
}
return { done: true };
},
};
}
let _initialized = false;
let _routerConfig = null;
const router = {
history: null,
handles: [],
errorHandler() { },
addHandle(handle) {
return router.handles.push(handle);
},
removeHandle(handleId) {
router.handles[handleId - 1] = null;
},
triggerHandles(component) {
router.handles.forEach((handle) => {
handle && handle(component);
});
},
match(fullpath) {
if (fullpath == null) return;
router.fullpath = fullpath;
const parent = router.root;
const matched = matchRoute(
parent,
parent.path,
fullpath,
);
function next(parent) {
const current = matched.next();
if (current.done) {
const error = new Error(`No match for ${fullpath}`);
return router.errorHandler(error, router.history.location);
}
let { component } = current.$.route;
if (typeof component === 'function') {
component = component(current.$.params, router.history.location);
}
if (component instanceof Promise) {
// Lazy loading component by import('./Foo')
return component.then((component) => {
// Check current fullpath avoid router has changed before lazy loading complete
if (fullpath === router.fullpath) {
router.triggerHandles(component);
}
});
} else if (component != null) {
router.triggerHandles(component);
return component;
} else {
return next(parent);
}
}
return next(parent);
},
};
function matchLocation({ pathname }) {
router.match(pathname);
}
function getInitialComponent(routerConfig) {
let InitialComponent = [];
if (_routerConfig === null) {
if (process.env.NODE_ENV !== 'production') {
if (!routerConfig) {
throw new Error('Error: useRouter should have routerConfig, see: https://www.npmjs.com/package/rax-use-router.');
}
if (!routerConfig.history || !routerConfig.routes) {
throw new Error('Error: routerConfig should contain history and routes, see: https://www.npmjs.com/package/rax-use-router.');
}
}
_routerConfig = routerConfig;
}
if (_routerConfig.InitialComponent) {
InitialComponent = _routerConfig.InitialComponent;
}
router.history = _routerConfig.history;
return InitialComponent;
}
let unlisten = null;
let handleId = null;
let pathes = '';
export function useRouter(routerConfig) {
const [component, setComponent] = useState(getInitialComponent(routerConfig));
let newPathes = '';
if (routerConfig) {
_routerConfig = routerConfig;
const { routes } = _routerConfig;
router.root = Array.isArray(routes) ? { routes } : routes;
if (Array.isArray(routes)) {
newPathes = routes.map(it => it.path).join(',');
} else {
newPathes = routes.path;
}
}
if (_initialized && _routerConfig.history) {
if (newPathes !== pathes) {
matchLocation(_routerConfig.history.location);
pathes = newPathes;
}
}
useLayoutEffect(() => {
if (unlisten) {
unlisten();
unlisten = null;
}
if (handleId) {
router.removeHandle(handleId);
handleId = null;
}
const { history } = _routerConfig;
const { routes } = _routerConfig;
router.root = Array.isArray(routes) ? { routes } : routes;
handleId = router.addHandle((component) => {
setComponent(component);
});
// Init path match
if (_initialized || !_routerConfig.InitialComponent) {
matchLocation(history.location);
pathes = newPathes;
}
unlisten = history.listen(({ location }) => {
matchLocation(location);
pathes = newPathes;
});
_initialized = true;
return () => {
pathes = '';
router.removeHandle(handleId);
handleId = null;
unlisten();
unlisten = null;
};
}, []);
return { component };
}
export function withRouter(Component) {
function Wrapper(props) {
const { history } = router;
return createElement(Component, { ...props, history, location: history.location });
}
Wrapper.displayName = `withRouter(${ Component.displayName || Component.name })`;
Wrapper.WrappedComponent = Component;
return Wrapper;
}

View File

@ -1,275 +0,0 @@
import RaxRenderer from '@alilc/lowcode-rax-renderer';
import { History } from 'history';
import { Component, createElement, Fragment } from 'rax';
import { useRouter } from './rax-use-router';
import { DocumentInstance, SimulatorRendererContainer } from './renderer';
import './renderer.less';
import { uniqueId } from '@alilc/lowcode-utils';
import { GlobalEvent } from '@alilc/lowcode-types';
import { host } from './host';
// patch cloneElement avoid lost keyProps
const originCloneElement = (window as any).Rax.cloneElement;
(window as any).Rax.cloneElement = (child: any, { _leaf, ...props }: any = {}, ...rest: any[]) => {
if (child.ref && props.ref) {
const dRef = props.ref;
const cRef = child.ref;
props.ref = (x: any) => {
if (cRef) {
if (typeof cRef === 'function') {
cRef(x);
} else {
try {
cRef.current = x;
} catch (e) {
console.error(e);
}
}
}
if (dRef) {
if (typeof dRef === 'function') {
dRef(x);
} else {
try {
dRef.current = x;
} catch (e) {
console.error(e);
}
}
}
};
}
return originCloneElement(child, props, ...rest);
};
export default class SimulatorRendererView extends Component<{ rendererContainer: SimulatorRendererContainer }> {
private unlisten: any;
componentDidMount() {
const { rendererContainer } = this.props;
this.unlisten = rendererContainer.onLayoutChange(() => {
this.forceUpdate();
});
}
componentWillUnmount() {
if (this.unlisten) {
this.unlisten();
}
}
render() {
const { rendererContainer } = this.props;
return (
<Layout rendererContainer={rendererContainer}>
<Routes rendererContainer={rendererContainer} history={rendererContainer.history} />
</Layout>
);
}
}
export const Routes = (props: {
rendererContainer: SimulatorRendererContainer;
history: History;
}) => {
const { rendererContainer, history } = props;
const { documentInstances } = rendererContainer;
const routes = {
history,
routes: documentInstances.map(instance => {
return {
path: instance.path,
component: (props: any) => <Renderer key={instance.id} rendererContainer={rendererContainer} documentInstance={instance} {...props} />,
};
}),
};
const { component } = useRouter(routes);
return component;
};
function ucfirst(s: string) {
return s.charAt(0).toUpperCase() + s.substring(1);
}
function getDeviceView(view: any, device: string, mode: string) {
if (!view || typeof view === 'string') {
return view;
}
// compatible vision Mobile | Preview
device = ucfirst(device);
if (device === 'Mobile' && view.hasOwnProperty(device)) {
view = view[device];
}
mode = ucfirst(mode);
if (mode === 'Preview' && view.hasOwnProperty(mode)) {
view = view[mode];
}
return view;
}
class Layout extends Component<{ rendererContainer: SimulatorRendererContainer }> {
constructor(props: any) {
super(props);
this.props.rendererContainer.onReRender(() => {
this.forceUpdate();
});
}
render() {
const { rendererContainer, children } = this.props;
const { layout } = rendererContainer;
if (layout) {
const { Component, props, componentName } = layout;
if (Component) {
return <Component props={props}>{children}</Component>;
}
if (componentName && rendererContainer.getComponent(componentName)) {
return createElement(
rendererContainer.getComponent(componentName),
{
...props,
rendererContainer,
},
[children],
);
}
}
return <Fragment>{children}</Fragment>;
}
}
class Renderer extends Component<{
rendererContainer: SimulatorRendererContainer;
documentInstance: DocumentInstance;
}> {
private unlisten: any;
private key: string;
private startTime: number | null = null;
componentWillMount() {
this.key = uniqueId('renderer');
}
componentDidMount() {
const { documentInstance } = this.props;
this.unlisten = documentInstance.onReRender((params) => {
if (params && params.shouldRemount) {
this.key = uniqueId('renderer');
}
this.forceUpdate();
});
}
componentWillUnmount() {
if (this.unlisten) {
this.unlisten();
}
}
shouldComponentUpdate() {
return false;
}
componentDidUpdate() {
if (this.startTime) {
const time = Date.now() - this.startTime;
const nodeCount = host.designer.currentDocument?.getNodeCount?.();
host.designer.editor?.eventBus.emit(GlobalEvent.Node.Rerender, {
componentName: 'Renderer',
type: 'All',
time,
nodeCount,
});
}
}
schemaChangedSymbol = false;
getSchemaChangedSymbol = () => {
return this.schemaChangedSymbol;
};
setSchemaChangedSymbol = (symbol: boolean) => {
this.schemaChangedSymbol = symbol;
};
render() {
const { documentInstance } = this.props;
const { container, document } = documentInstance;
const { designMode, device } = container;
const { rendererContainer: renderer } = this.props;
this.startTime = Date.now();
this.schemaChangedSymbol = false;
return (
<RaxRenderer
schema={documentInstance.schema}
components={renderer.components}
appHelper={renderer.context}
context={renderer.context}
device={device}
designMode={renderer.designMode}
key={this.key}
__host={host}
__container={container}
suspended={documentInstance.suspended}
self={documentInstance.scope}
onCompGetRef={(schema: any, ref: any) => {
documentInstance.mountInstance(schema.id, ref);
}}
thisRequiredInJSE={host.thisRequiredInJSE}
documentId={document.id}
getNode={(id: string) => documentInstance.getNode(id) as any}
rendererName="PageRenderer"
customCreateElement={(Component: any, props: any, children: any) => {
const { __id, ...viewProps } = props;
viewProps.componentId = __id;
const leaf = documentInstance.getNode(__id);
viewProps._leaf = leaf;
viewProps._componentName = leaf?.componentName;
// 如果是容器 && 无children && 高宽为空 增加一个占位容器,方便拖动
if (
!viewProps.dataSource &&
leaf?.isContainer() &&
(children == null || (Array.isArray(children) && !children.length)) &&
(!viewProps.style || Object.keys(viewProps.style).length === 0)
) {
children = (
<div className="lc-container-placeholder" style={viewProps.placeholderStyle}>
{viewProps.placeholder || '拖拽组件或模板到这里'}
</div>
);
}
// if (viewProps._componentName === 'Menu') {
// Object.assign(viewProps, {
// _componentName: 'Menu',
// className: '_css_pesudo_menu_kbrzyh0f',
// context: { VE: (window as any).VisualLowCodeRenderer },
// direction: undefined,
// events: { ignored: true },
// fieldId: 'menu_kbrzyh0f',
// footer: '',
// header: '',
// mode: 'inline',
// onItemClick: { ignored: true },
// onSelect: { ignored: true },
// popupAlign: 'follow',
// selectMode: false,
// triggerType: 'click',
// });
// console.info('menuprops', viewProps);
// }
return createElement(
getDeviceView(Component, device, designMode),
viewProps,
leaf?.isContainer() ? (children == null ? [] : Array.isArray(children) ? children : [children]) : children,
);
}}
/>
);
}
}

View File

@ -1,125 +0,0 @@
body, html {
display: block;
background: white;
padding: 0;
margin: 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;
}
::-webkit-scrollbar {
display: none;
}
.lc-container {
&: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;
&:before {
content: '\62D6\62FD\7EC4\4EF6\6216\6A21\677F\5230\8FD9\91CC';
font-size: 14px;
z-index: 1;
width: 100%;
white-space: nowrap;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
}
}
.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;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.lc-container-placeholder {
min-height: 60px;
height: 100%;
width: 100%;
background-color: rgb(240, 240, 240);
border: 1px dotted;
color: rgb(167, 177, 189);
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
}
body.engine-document {
&:after, &:before {
content: "";
display: table;
}
&:after {
clear: both;
}
/*
.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: none !important;
} */
}
.engine-live-editing {
cursor: text;
outline: none;
box-shadow: 0 0 0 2px rgb(102, 188, 92);
user-select: text;
}
/* stylelint-disable-next-line selector-max-id */
#app {
height: 100vh;
}
.luna-page {
height: 100%;
}

View File

@ -1,690 +0,0 @@
import { BuiltinSimulatorRenderer, Component, IBaseNode, IDocumentModel } from '@alilc/lowcode-designer';
import { IPublicTypeComponentSchema, IPublicTypeNodeSchema, IPublicTypeNpmInfo, IPublicEnumTransformStage, IPublicTypeNodeInstance, IPublicTypeProjectSchema } from '@alilc/lowcode-types';
import { Asset, compatibleLegaoSchema, cursor, isElement, isESModule, isLowcodeProjectSchema, isComponentSchema, isPlainObject, isReactComponent, setNativeSelection } from '@alilc/lowcode-utils';
import LowCodeRenderer from '@alilc/lowcode-rax-renderer';
import { computed, observable as obx, makeObservable, configure } from 'mobx';
import DriverUniversal from 'driver-universal';
import { createMemoryHistory, MemoryHistory } from 'history';
// @ts-ignore
import Rax, { ComponentType, createElement, render as raxRender, shared } from 'rax';
import Leaf from './builtin-components/leaf';
import Slot from './builtin-components/slot';
import { host } from './host';
import SimulatorRendererView from './renderer-view';
import { raxFindDOMNodes } from './utils/find-dom-nodes';
import { getClientRects } from './utils/get-client-rects';
import loader from './utils/loader';
import { parseQuery, withQueryParams } from './utils/url';
import { IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core';
configure({ enforceActions: 'never' });
const { Instance } = shared;
export interface LibraryMap {
[key: string]: string;
}
const SYMBOL_VNID = Symbol('_LCNodeId');
const SYMBOL_VDID = Symbol('_LCDocId');
const INTERNAL = '_internal';
function accessLibrary(library: string | object) {
if (typeof library !== 'string') {
return library;
}
return (window as any)[library];
}
// Slot/Leaf and Fragment|FunctionComponent polyfill(ref)
const builtinComponents = {
Slot,
Leaf,
};
function buildComponents(
libraryMap: LibraryMap,
componentsMap: { [componentName: string]: IPublicTypeNpmInfo | ComponentType<any> | IPublicTypeComponentSchema },
createComponent: (schema: IPublicTypeProjectSchema<IPublicTypeComponentSchema>) => Component | null,
) {
const components: any = {
...builtinComponents,
};
Object.keys(componentsMap).forEach((componentName) => {
let component = componentsMap[componentName];
if (component && (isLowcodeProjectSchema(component) || isComponentSchema(component))) {
if (isComponentSchema(component)) {
components[componentName] = createComponent({
version: '',
componentsMap: [],
componentsTree: [component],
});
} else {
components[componentName] = createComponent(component);
}
} else if (isReactComponent(component)) {
components[componentName] = component;
} else {
component = findComponent(libraryMap, componentName, component as IPublicTypeNpmInfo);
if (component) {
components[componentName] = component;
}
}
});
return components;
}
let REACT_KEY = '';
function cacheReactKey(el: Element): Element {
if (REACT_KEY !== '') {
return el;
}
// react17 采用 __reactFiber 开头
REACT_KEY = Object.keys(el).find(
(key) => key.startsWith('__reactInternalInstance$') || key.startsWith('__reactFiber$'),
) || '';
if (!REACT_KEY && (el as HTMLElement).parentElement) {
return cacheReactKey((el as HTMLElement).parentElement!);
}
return el;
}
function checkInstanceMounted(instance: any): boolean {
if (isElement(instance)) {
return instance.parentElement != null;
}
return true;
}
function isValidDesignModeRaxComponentInstance(
raxComponentInst: any,
): raxComponentInst is {
props: {
_leaf: Exclude<IPublicTypeNodeInstance<any>['node'], null | undefined>;
};
} {
const leaf = raxComponentInst?.props?._leaf;
return leaf && typeof leaf === 'object' && leaf.isNode;
}
export class DocumentInstance {
private instancesMap = new Map<string, any[]>();
private emitter: IEventBus = createModuleEventBus('DocumentInstance');
get schema(): any {
return this.document.export(IPublicEnumTransformStage.Render);
}
constructor(readonly container: SimulatorRendererContainer, readonly document: IDocumentModel) {
makeObservable(this);
}
@computed get suspended(): any {
return false;
}
@computed get scope(): any {
return null;
}
get path(): string {
return `/${ this.document.fileName}`;
}
get id() {
return this.document.id;
}
private unmountIntance(id: string, instance: any) {
const instances = this.instancesMap.get(id);
if (instances) {
const i = instances.indexOf(instance);
if (i > -1) {
instances.splice(i, 1);
host.setInstance(this.document.id, id, instances);
}
}
}
refresh() {
this.emitter.emit('rerender', { shouldRemount: true });
}
onReRender(fn: () => void) {
this.emitter.on('rerender', fn);
return () => {
this.emitter.removeListener('renderer', fn);
};
}
mountInstance(id: string, instance: any) {
const docId = this.document.id;
const { instancesMap } = this;
if (instance == null) {
let instances = this.instancesMap.get(id);
if (instances) {
instances = instances.filter(checkInstanceMounted);
if (instances.length > 0) {
instancesMap.set(id, instances);
host.setInstance(this.document.id, id, instances);
} else {
instancesMap.delete(id);
host.setInstance(this.document.id, id, null);
}
}
return;
}
const unmountIntance = this.unmountIntance.bind(this);
const origId = (instance as any)[SYMBOL_VNID];
if (origId && origId !== id) {
// 另外一个节点的 instance 在此被复用了,需要从原来地方卸载
unmountIntance(origId, instance);
}
if (isElement(instance)) {
cacheReactKey(instance);
} else if (origId !== id) {
// 涵盖 origId == null || origId !== id 的情况
let origUnmount: any = instance.componentWillUnmount;
if (origUnmount && origUnmount.origUnmount) {
origUnmount = origUnmount.origUnmount;
}
// hack! delete instance from map
const newUnmount = function (this: any) {
unmountIntance(id, instance);
origUnmount && origUnmount.call(this);
};
(newUnmount as any).origUnmount = origUnmount;
instance.componentWillUnmount = newUnmount;
}
(instance as any)[SYMBOL_VNID] = id;
(instance as any)[SYMBOL_VDID] = docId;
let instances = this.instancesMap.get(id);
if (instances) {
const l = instances.length;
instances = instances.filter(checkInstanceMounted);
let updated = instances.length !== l;
if (!instances.includes(instance)) {
instances.push(instance);
updated = true;
}
if (!updated) {
return;
}
} else {
instances = [instance];
}
instancesMap.set(id, instances);
host.setInstance(this.document.id, id, instances);
}
mountContext(docId: string, id: string, ctx: object) {
// this.ctxMap.set(id, ctx);
}
getComponentInstances(id: string): any[] | null {
return this.instancesMap.get(id) || null;
}
getNode(id: string): IBaseNode<IPublicTypeNodeSchema> | null {
return this.document.getNode(id);
}
}
export class SimulatorRendererContainer implements BuiltinSimulatorRenderer {
readonly isSimulatorRenderer = true;
private dispose?: () => void;
readonly history: MemoryHistory;
private emitter: IEventBus = createModuleEventBus('SimulatorRendererContainer');
@obx.ref private _documentInstances: DocumentInstance[] = [];
get documentInstances() {
return this._documentInstances;
}
get currentDocumentInstance() {
return this._documentInstances.find((item) => item.id === host.project.currentDocument?.id);
}
constructor() {
this.dispose = host.connect(this, () => {
// sync layout config
this._layout = host.project.get('config').layout;
// todo: split with others, not all should recompute
if (this._libraryMap !== host.libraryMap || this._componentsMap !== host.designer.componentsMap) {
this._libraryMap = host.libraryMap || {};
this._componentsMap = host.designer.componentsMap;
this.buildComponents();
}
// sync designMode
this._designMode = host.designMode;
this._locale = host.locale;
// sync requestHandlersMap
this._requestHandlersMap = host.requestHandlersMap;
// sync device
this._device = host.device;
this.emitter.emit('layoutChange');
});
const documentInstanceMap = new Map<string, DocumentInstance>();
let initialEntry = '/';
let firstRun = true;
host.autorun(() => {
this._documentInstances = host.project.documents.map((doc) => {
let inst = documentInstanceMap.get(doc.id);
if (!inst) {
inst = new DocumentInstance(this, doc);
documentInstanceMap.set(doc.id, inst);
}
return inst;
});
const path = host.project.currentDocument ? documentInstanceMap.get(host.project.currentDocument.id)!.path : '/';
if (firstRun) {
initialEntry = path;
firstRun = false;
} else {
if (this.history.location.pathname !== path) {
this.history.replace(path);
}
this.emitter.emit('layoutChange');
}
});
const history = createMemoryHistory({
initialEntries: [initialEntry],
});
this.history = history;
history.listen(({ location }) => {
host.project.open(location.pathname.slice(1));
});
host.componentsConsumer.consume(async (componentsAsset) => {
if (componentsAsset) {
await this.load(componentsAsset);
this.buildComponents();
}
});
this._appContext = {
utils: {
router: {
push(path: string, params?: object) {
history.push(withQueryParams(path, params));
},
replace(path: string, params?: object) {
history.replace(withQueryParams(path, params));
},
back() {
history.back();
},
},
legaoBuiltins: {
getUrlParams() {
const { search } = history.location;
return parseQuery(search);
},
},
},
constants: {},
requestHandlersMap: this._requestHandlersMap,
};
host.injectionConsumer.consume((data) => {
// sync utils, i18n, contants,... config
});
}
@obx private _layout: any = null;
@computed get layout(): any {
// TODO: parse layout Component
return this._layout;
}
set layout(value: any) {
this._layout = value;
}
private _libraryMap: { [key: string]: string } = {};
private buildComponents() {
// TODO: remove this.createComponent
this._components = buildComponents(this._libraryMap, this._componentsMap, this.createComponent.bind(this));
}
@obx.ref private _components: Record<string, React.FC | React.ComponentClass> | null = {};
@computed get components(): Record<string, React.FC | React.ComponentClass> {
// 根据 device 选择不同组件,进行响应式
// 更好的做法是,根据 device 选择加载不同的组件资源,甚至是 simulatorUrl
return this._components || {};
}
// context from: utils、constants、history、location、match
@obx.ref private _appContext = {};
@computed get context(): any {
return this._appContext;
}
@obx.ref private _designMode: string = 'design';
@computed get designMode(): any {
return this._designMode;
}
@obx.ref private _device: string = 'default';
@computed get device() {
return this._device;
}
@obx.ref private _locale: string | undefined = undefined;
@computed get locale() {
return this._locale;
}
@obx.ref private _requestHandlersMap = null;
@computed get requestHandlersMap(): any {
return this._requestHandlersMap;
}
@obx.ref private _componentsMap = {};
@computed get componentsMap(): any {
return this._componentsMap;
}
/**
*
*/
load(asset: Asset): Promise<any> {
return loader.load(asset);
}
async loadAsyncLibrary(asyncLibraryMap: Record<string, any>) {
}
getComponent(componentName: string) {
const paths = componentName.split('.');
const subs: string[] = [];
while (true) {
const component = this._components?.[componentName];
if (component) {
return getSubComponent(component, subs);
}
const sub = paths.pop();
if (!sub) {
return null;
}
subs.unshift(sub);
componentName = paths.join('.');
}
}
getNodeInstance(dom: HTMLElement): IPublicTypeNodeInstance<any> | null {
const INTERNAL = '_internal';
let instance: any = dom;
if (!isElement(instance)) {
return {
docId: instance.props._leaf.document.id,
nodeId: instance.props._leaf.getId(),
instance,
node: instance.props._leaf,
};
}
instance = Instance.get(dom);
let loopNum = 0; // 防止由于某种意外而导致死循环
while (instance && instance[INTERNAL] && loopNum < 1000) {
if (isValidDesignModeRaxComponentInstance(instance)) {
// if (instance && SYMBOL_VNID in instance) {
// const docId = (instance.props as any).schema.docId;
return {
docId: instance.props._leaf.document?.id || '',
nodeId: instance.props._leaf.getId(),
instance,
node: instance.props._leaf,
};
}
instance = getRaxVDomParentInstance(instance);
loopNum += 1;
}
return null;
}
getClosestNodeInstance(from: any, nodeId?: string): IPublicTypeNodeInstance<any> | null {
const el: any = from;
if (el) {
// if (isElement(el)) {
// el = cacheReactKey(el);
// } else {
// return getNodeInstance(el, specId);
// }
return this.getNodeInstance(el);
}
return null;
}
findDOMNodes(instance: any, selector?: string): Array<Element | Text> | null {
let el = instance;
if (selector) {
el = document.querySelector(selector);
}
try {
return raxFindDOMNodes(el);
} catch (e) {
// ignore
}
if (el && el.type && el.props && el.props.componentId) {
el = document.querySelector(`${el.type}[componentid=${el.props.componentId}]`);
} else {
console.error(instance);
throw new Error('This instance may not a valid element');
}
return raxFindDOMNodes(el);
}
getClientRects(element: Element | Text) {
return getClientRects(element);
}
setNativeSelection(enableFlag: boolean) {
setNativeSelection(enableFlag);
}
setDraggingState(state: boolean) {
cursor.setDragging(state);
}
setCopyState(state: boolean) {
cursor.setCopy(state);
}
clearState() {
cursor.release();
}
onLayoutChange(cb: () => void) {
this.emitter.on('layoutChange', cb);
return () => {
this.emitter.removeListener('layoutChange', cb);
};
}
onReRender(fn: () => void) {
this.emitter.on('rerender', fn);
return () => {
this.emitter.removeListener('renderer', fn);
};
}
rerender() {
this.currentDocumentInstance?.refresh();
}
stopAutoRepaintNode() {
}
enableAutoRepaintNode() {
}
createComponent(schema: IPublicTypeProjectSchema<IPublicTypeComponentSchema>): Component | null {
const _schema: IPublicTypeProjectSchema<IPublicTypeComponentSchema> = {
...schema,
componentsTree: schema.componentsTree.map(compatibleLegaoSchema),
};
const componentsTreeSchema = _schema.componentsTree[0];
if (componentsTreeSchema.componentName === 'Component' && componentsTreeSchema.css) {
const doc = window.document;
const s = doc.createElement('style');
s.setAttribute('type', 'text/css');
s.setAttribute('id', `Component-${componentsTreeSchema.id || ''}`);
s.appendChild(doc.createTextNode(componentsTreeSchema.css || ''));
doc.getElementsByTagName('head')[0].appendChild(s);
}
const renderer = this;
const { componentsMap: components } = renderer;
class LowCodeComp extends Rax.Component {
render() {
const extraProps = getLowCodeComponentProps(this.props);
// @ts-ignore
return createElement(LowCodeRenderer, {
...extraProps,
schema: componentsTreeSchema,
components,
designMode: '',
locale: renderer.locale,
messages: _schema.i18n || {},
device: renderer.device,
appHelper: renderer.context,
rendererName: 'LowCodeRenderer',
thisRequiredInJSE: host.thisRequiredInJSE,
customCreateElement: (Comp: any, props: any, children: any) => {
const componentMeta = host.currentDocument?.getComponentMeta(Comp.displayName);
if (componentMeta?.isModal) {
return null;
}
const { __id, __designMode, ...viewProps } = props;
// mock _leaf减少性能开销
const _leaf = {
isEmpty: () => false,
isMock: true,
};
viewProps._leaf = _leaf;
return createElement(Comp, viewProps, children);
},
});
}
}
return LowCodeComp;
}
private _running = false;
run() {
if (this._running) {
return;
}
this._running = true;
const containerId = 'app';
let container = document.getElementById(containerId);
if (!container) {
container = document.createElement('div');
document.body.appendChild(container);
container.id = containerId;
}
// ==== compatiable vision
document.documentElement.classList.add('engine-page');
document.body.classList.add('engine-document'); // important! Stylesheet.invoke depends
raxRender(createElement(SimulatorRendererView, {
rendererContainer: this,
}), container, {
driver: DriverUniversal,
});
host.project.setRendererReady(this);
}
}
function getSubComponent(library: any, paths: string[]) {
const l = paths.length;
if (l < 1 || !library) {
return library;
}
let i = 0;
let component: any;
while (i < l) {
const key = paths[i]!;
let ex: any;
try {
component = library[key];
} catch (e) {
ex = e;
component = null;
}
if (i === 0 && component == null && key === 'default') {
if (ex) {
return l === 1 ? library : null;
}
component = library;
} else if (component == null) {
return null;
}
library = component;
i++;
}
return component;
}
function findComponent(libraryMap: LibraryMap, componentName: string, npm?: IPublicTypeNpmInfo) {
if (!npm) {
return accessLibrary(componentName);
}
// libraryName the key access to global
// export { exportName } from xxx exportName === global.libraryName.exportName
// export exportName from xxx exportName === global.libraryName.default || global.libraryName
// export { exportName as componentName } from package
// if exportName == null exportName === componentName;
// const componentName = exportName.subName, if exportName empty subName donot use
const exportName = npm.exportName || npm.componentName || componentName;
const libraryName = libraryMap[npm.package] || exportName;
const library = accessLibrary(libraryName);
const paths = npm.exportName && npm.subName ? npm.subName.split('.') : [];
if (npm.destructuring) {
paths.unshift(exportName);
} else if (isESModule(library)) {
paths.unshift('default');
}
return getSubComponent(library, paths);
}
function getLowCodeComponentProps(props: any) {
if (!props || !isPlainObject(props)) {
return props;
}
const newProps: any = {};
Object.keys(props).forEach(k => {
if (['children', 'componentId', '__designMode', '_componentName', '_leaf'].includes(k)) {
return;
}
newProps[k] = props[k];
});
return newProps;
}
/**
* Rax VDOM
* Rax development __parentInstance
* production __parentInstance
* _internal ()
*/
function getRaxVDomParentInstance(instance: { _internal: any }) {
const internalInstance = instance._internal;
return internalInstance.__parentInstance ||
Object.values(internalInstance).find(v => (
v !== null &&
v !== instance &&
typeof v === 'object' &&
typeof (v as {_internal: unknown})._internal === 'object'
));
}
export default new SimulatorRendererContainer();

View File

@ -1,17 +0,0 @@
export interface Defer<T = any> {
resolve(value?: T | PromiseLike<T>): void;
reject(reason?: any): void;
promise(): Promise<T>;
}
export function createDefer<T = any>(): Defer<T> {
const r: any = {};
const promise = new Promise<T>((resolve, reject) => {
r.resolve = resolve;
r.reject = reject;
});
r.promise = () => promise;
return r;
}

View File

@ -1,18 +0,0 @@
import { isElement } from '@alilc/lowcode-utils';
import findDOMNode from 'rax-find-dom-node';
// import { isDOMNode } from './is-dom-node';
export function raxFindDOMNodes(instance: any): Array<Element | Text> | null {
if (!instance) {
return null;
}
if (isElement(instance)) {
return [instance];
}
// eslint-disable-next-line react/no-find-dom-node
const result = findDOMNode(instance);
if (Array.isArray(result)) {
return result;
}
return [result];
}

View File

@ -1,13 +0,0 @@
import { isElement } from '@alilc/lowcode-utils';
// a range for test TextNode clientRect
const cycleRange = document.createRange();
export function getClientRects(node: Element | Text) {
if (isElement(node)) {
return [node.getBoundingClientRect()];
}
cycleRange.selectNode(node);
return Array.from(cycleRange.getClientRects());
}

View File

@ -1,23 +0,0 @@
function ucfirst(s: string) {
return s.charAt(0).toUpperCase() + s.substring(1);
}
function getDeviceView(view: any, device: string, mode: string) {
if (!view || typeof view === 'string') {
return view;
}
// compatible vision Mobile | Preview
device = ucfirst(device);
if (device === 'Mobile' && view.hasOwnProperty(device)) {
view = view[device];
}
mode = ucfirst(mode);
if (mode === 'Preview' && view.hasOwnProperty(mode)) {
view = view[mode];
}
return view;
}
export default {
getDeviceView,
};

View File

@ -1,4 +0,0 @@
export function isDOMNode(node: any): node is Element | Text {
if (!node) return false;
return node.nodeType && (node.nodeType === Node.ELEMENT_NODE || node.nodeType === Node.TEXT_NODE);
}

View File

@ -1,114 +0,0 @@
import { load, evaluate } from './script';
import StylePoint from './style';
import {
Asset,
AssetLevel,
AssetLevels,
AssetType,
AssetList,
isAssetBundle,
isAssetItem,
assetItem,
AssetItem,
isCSSUrl,
} from '@alilc/lowcode-utils';
function parseAssetList(scripts: any, styles: any, assets: AssetList, level?: AssetLevel) {
for (const asset of assets) {
parseAsset(scripts, styles, asset, level);
}
}
function parseAsset(scripts: any, styles: any, asset: Asset | undefined | null, level?: AssetLevel) {
if (!asset) {
return;
}
if (Array.isArray(asset)) {
return parseAssetList(scripts, styles, asset, level);
}
if (isAssetBundle(asset)) {
if (asset.assets) {
if (Array.isArray(asset.assets)) {
parseAssetList(scripts, styles, asset.assets, asset.level || level);
} else {
parseAsset(scripts, styles, asset.assets, asset.level || level);
}
return;
}
return;
}
if (!isAssetItem(asset)) {
asset = assetItem(isCSSUrl(asset) ? AssetType.CSSUrl : AssetType.JSUrl, asset, level)!;
}
let lv = asset.level || level;
if (!lv || AssetLevel[lv] == null) {
lv = AssetLevel.App;
}
asset.level = lv;
if (asset.type === AssetType.CSSUrl || asset.type == AssetType.CSSText) {
styles[lv].push(asset);
} else {
scripts[lv].push(asset);
}
}
export class AssetLoader {
async load(asset: Asset) {
const styles: any = {};
const scripts: any = {};
AssetLevels.forEach(lv => {
styles[lv] = [];
scripts[lv] = [];
});
parseAsset(scripts, styles, asset);
const styleQueue: AssetItem[] = styles[AssetLevel.Environment].concat(
styles[AssetLevel.Library],
styles[AssetLevel.Theme],
styles[AssetLevel.Runtime],
styles[AssetLevel.App],
);
const scriptQueue: AssetItem[] = scripts[AssetLevel.Environment].concat(
scripts[AssetLevel.Library],
scripts[AssetLevel.Theme],
scripts[AssetLevel.Runtime],
scripts[AssetLevel.App],
);
await Promise.all(
styleQueue.map(({ content, level, type, id }) => this.loadStyle(content, level!, type === AssetType.CSSUrl, id)),
);
await Promise.all(scriptQueue.map(({ content, type }) => this.loadScript(content, type === AssetType.JSUrl)));
}
private stylePoints = new Map<string, StylePoint>();
private loadStyle(content: string | undefined | null, level: AssetLevel, isUrl?: boolean, id?: string) {
if (!content) {
return;
}
let point: StylePoint | undefined;
if (id) {
point = this.stylePoints.get(id);
if (!point) {
point = new StylePoint(level, id);
this.stylePoints.set(id, point);
}
} else {
point = new StylePoint(level);
}
return isUrl ? point.applyUrl(content) : point.applyText(content);
}
private loadScript(content: string | undefined | null, isUrl?: boolean) {
if (!content) {
return;
}
return isUrl ? load(content) : evaluate(content);
}
}
export default new AssetLoader();

View File

@ -1,54 +0,0 @@
import { createDefer } from './create-defer';
export function evaluate(script: string) {
const scriptEl = document.createElement('script');
scriptEl.text = script;
document.head.appendChild(scriptEl);
document.head.removeChild(scriptEl);
}
export function load(url: string) {
const node: any = document.createElement('script');
// node.setAttribute('crossorigin', 'anonymous');
node.onload = onload;
node.onerror = onload;
const i = createDefer();
function onload(e: any) {
node.onload = null;
node.onerror = null;
if (e.type === 'load') {
i.resolve();
} else {
i.reject();
}
// document.head.removeChild(node);
// node = null;
}
// node.async = true;
node.src = url;
document.head.appendChild(node);
return i.promise();
}
export function evaluateExpression(expr: string) {
// eslint-disable-next-line no-new-func
const fn = new Function(expr);
return fn();
}
export function newFunction(args: string, code: string) {
try {
// eslint-disable-next-line no-new-func
return new Function(args, code);
} catch (e) {
console.warn('Caught error, Cant init func');
return null;
}
}

View File

@ -1,75 +0,0 @@
import { createDefer } from './create-defer';
export default class StylePoint {
private lastContent: string | undefined;
private lastUrl: string | undefined;
private placeholder: Element | Text;
constructor(readonly level: number, readonly id?: string) {
let placeholder: any;
if (id) {
placeholder = document.head.querySelector(`style[data-id="${id}"]`);
}
if (!placeholder) {
placeholder = document.createTextNode('');
const meta = document.head.querySelector(`meta[level="${level}"]`);
if (meta) {
document.head.insertBefore(placeholder, meta);
} else {
document.head.appendChild(placeholder);
}
}
this.placeholder = placeholder;
}
applyText(content: string) {
if (this.lastContent === content) {
return;
}
this.lastContent = content;
this.lastUrl = undefined;
const element = document.createElement('style');
element.setAttribute('type', 'text/css');
if (this.id) {
element.setAttribute('data-id', this.id);
}
element.appendChild(document.createTextNode(content));
document.head.insertBefore(element, this.placeholder.parentNode === document.head ? this.placeholder.nextSibling : null);
document.head.removeChild(this.placeholder);
this.placeholder = element;
}
applyUrl(url: string) {
if (this.lastUrl === url) {
return;
}
this.lastContent = undefined;
this.lastUrl = url;
const element = document.createElement('link');
element.onload = onload;
element.onerror = onload;
const i = createDefer();
function onload(e: any) {
element.onload = null;
element.onerror = null;
if (e.type === 'load') {
i.resolve();
} else {
i.reject();
}
}
element.href = url;
element.rel = 'stylesheet';
if (this.id) {
element.setAttribute('data-id', this.id);
}
document.head.insertBefore(element, this.placeholder.parentNode === document.head ? this.placeholder.nextSibling : null);
document.head.removeChild(this.placeholder);
this.placeholder = element;
return i.promise();
}
}

View File

@ -1,74 +0,0 @@
/**
* Parse queryString
* @param {String} str '?q=query&b=test'
* @return {Object}
*/
export function parseQuery(str: string): object {
const ret: any = {};
if (typeof str !== 'string') {
return ret;
}
const s = str.trim().replace(/^(\?|#|&)/, '');
if (!s) {
return ret;
}
s.split('&').forEach((param) => {
const parts = param.replace(/\+/g, ' ').split('=');
let key = parts.shift()!;
let val: any = parts.length > 0 ? parts.join('=') : undefined;
key = decodeURIComponent(key);
val = val === undefined ? null : decodeURIComponent(val);
if (ret[key] === undefined) {
ret[key] = val;
} else if (Array.isArray(ret[key])) {
ret[key].push(val);
} else {
ret[key] = [ret[key], val];
}
});
return ret;
}
/**
* Stringify object to query parammeters
* @param {Object} obj
* @return {String}
*/
export function stringifyQuery(obj: any): string {
const param: string[] = [];
Object.keys(obj).forEach((key) => {
let value = obj[key];
if (value && typeof value === 'object') {
value = JSON.stringify(value);
}
param.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
});
return param.join('&');
}
export function uriEncode(uri: string) {
return encodeURIComponent(uri);
}
export function uriDecode(uri: string) {
return decodeURIComponent(uri);
}
export function withQueryParams(url: string, params?: object) {
const queryStr = params ? stringifyQuery(params) : '';
if (queryStr === '') {
return url;
}
const urlSplit = url.split('#');
const hash = urlSplit[1] ? `#${urlSplit[1]}` : '';
const urlWithoutHash = urlSplit[0];
return `${urlWithoutHash}${~urlWithoutHash.indexOf('?') ? '&' : '?'}${queryStr}${hash}`;
}

View File

@ -2,7 +2,6 @@ import { IRuntime, IRendererModules, IGeneralConstructor } from '../types';
export enum Env {
React = 'react',
Rax = 'rax',
}
class Adapter {
@ -22,22 +21,22 @@ class Adapter {
initRuntime() {
const Component: IGeneralConstructor = class <T = any, S = any> {
setState() {}
forceUpdate() {}
render() {}
state: Readonly<S>;
props: Readonly<T> & Readonly<{ children?: any | undefined }>;
refs: Record<string, unknown>;
context: Record<string, unknown>;
setState() {}
forceUpdate() {}
render() {}
};
const PureComponent = class <T = any, S = any> {
setState() {}
forceUpdate() {}
render() {}
state: Readonly<S>;
props: Readonly<T> & Readonly<{ children?: any | undefined }>;
refs: Record<string, unknown>;
context: Record<string, unknown>;
setState() {}
forceUpdate() {}
render() {}
};
const createElement = () => {};
const createContext = () => {};
@ -85,10 +84,6 @@ class Adapter {
return this.env === Env.React;
}
isRax() {
return this.env === Env.Rax;
}
setRenderers(renderers: IRendererModules) {
this.renderers = renderers;
}

View File

@ -79,15 +79,10 @@ describe('test src/adapter ', () => {
});
it('setEnv/.env/isReact/isRax works', () => {
it('setEnv/.env/isReact works', () => {
adapter.setEnv(Env.React);
expect(adapter.env).toBe(Env.React);
expect(adapter.isReact()).toBeTruthy();
expect(adapter.isRax()).toBeFalsy();
adapter.setEnv(Env.Rax);
expect(adapter.env).toBe(Env.Rax);
expect(adapter.isRax()).toBeTruthy();
expect(adapter.isReact()).toBeFalsy();
});
it('setRenderers/getRenderers works', () => {

View File

@ -41,7 +41,7 @@ export interface IPublicTypeEngineOptions {
/**
* 'react'
*/
renderEnv?: 'react' | 'rax' | string;
renderEnv?: 'react' | string;
/**
* device

View File

@ -9,8 +9,6 @@ lerna run build \
--scope @alilc/lowcode-designer \
--scope @alilc/lowcode-plugin-designer \
--scope @alilc/lowcode-plugin-outline-pane \
--scope @alilc/lowcode-rax-renderer \
--scope @alilc/lowcode-rax-simulator-renderer \
--scope @alilc/lowcode-react-renderer \
--scope @alilc/lowcode-react-simulator-renderer \
--scope @alilc/lowcode-renderer-core \
@ -20,13 +18,9 @@ lerna run build \
lerna run build:umd \
--scope @alilc/lowcode-engine \
--scope @alilc/lowcode-rax-simulator-renderer \
--scope @alilc/lowcode-react-simulator-renderer \
--scope @alilc/lowcode-react-renderer \
--stream
cp ./packages/react-simulator-renderer/dist/js/* ./packages/engine/dist/js/
cp ./packages/react-simulator-renderer/dist/css/* ./packages/engine/dist/css/
cp ./packages/rax-simulator-renderer/dist/js/* ./packages/engine/dist/js/
cp ./packages/rax-simulator-renderer/dist/css/* ./packages/engine/dist/css/

View File

@ -10,8 +10,6 @@ tnpm sync @alilc/lowcode-designer
tnpm sync @alilc/lowcode-plugin-designer
tnpm sync @alilc/lowcode-plugin-outline-pane
tnpm sync @alilc/lowcode-renderer-core
tnpm sync @alilc/lowcode-rax-renderer
tnpm sync @alilc/lowcode-rax-simulator-renderer
tnpm sync @alilc/lowcode-react-renderer
tnpm sync @alilc/lowcode-react-simulator-renderer
tnpm sync @alilc/lowcode-engine