mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-03-05 17:57:13 +00:00
Merge branch 'develop' into release/1.0.15-beta
This commit is contained in:
commit
f346675e15
116
.github/workflows/ci.yml
vendored
Normal file
116
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,116 @@
|
||||
name: Node CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
upload-designer-codecov:
|
||||
runs-on: ubuntu-latest
|
||||
# if: ${{ github.event.pull_request.head.repo.full_name == 'alibaba/lowcode-engine' }}
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '14'
|
||||
|
||||
- name: install
|
||||
run: npm i && npm run setup:skip-build
|
||||
|
||||
- name: test designer
|
||||
run: cd packages/designer && npm run test:cov && cd ../..
|
||||
|
||||
- name: Upload designer coverage to Codecov
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
# working-directory: packages/designer
|
||||
directory: ./packages/designer/coverage
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
name: designer
|
||||
fail_ci_if_error: true
|
||||
verbose: true
|
||||
|
||||
upload-renderer-core:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '14'
|
||||
|
||||
- name: install
|
||||
run: npm i && npm run setup:skip-build
|
||||
|
||||
- name: test renderer-core
|
||||
run: cd packages/renderer-core && npm run test:cov && cd ../..
|
||||
|
||||
- name: Upload renderer-core coverage to Codecov
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
# working-directory: packages/designer
|
||||
directory: ./packages/renderer-core/coverage
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
name: renderer-core
|
||||
fail_ci_if_error: true
|
||||
verbose: true
|
||||
|
||||
upload-react-simulator-renderer:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '14'
|
||||
|
||||
- name: install
|
||||
run: npm i && npm run setup:skip-build
|
||||
|
||||
- name: test react-simulator-renderer
|
||||
run: cd packages/react-simulator-renderer && npm run test:cov && cd ../..
|
||||
|
||||
- name: Upload react-simulator-renderer coverage to Codecov
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
# working-directory: packages/designer
|
||||
directory: ./packages/react-simulator-renderer/coverage
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
name: react-simulator-renderer
|
||||
fail_ci_if_error: true
|
||||
verbose: true
|
||||
|
||||
upload-code-generator:
|
||||
runs-on: ubuntu-latest
|
||||
# if: ${{ github.event.pull_request.head.repo.full_name == 'alibaba/lowcode-engine' }}
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '14'
|
||||
|
||||
- name: install
|
||||
run: npm i && npm run setup:skip-build
|
||||
|
||||
- name: test code-generator
|
||||
run: cd modules/code-generator && npm i && npm run build && npm run test:cov && cd ../..
|
||||
|
||||
- name: Upload code-generator coverage to Codecov
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
# working-directory: packages/designer
|
||||
directory: ./modules/code-generator/coverage
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
name: code-generator
|
||||
fail_ci_if_error: true
|
||||
verbose: true
|
||||
@ -123,7 +123,7 @@ export class SchemaParser implements ISchemaParser {
|
||||
const schema = this.decodeSchema(schemaSrc);
|
||||
|
||||
// 解析三方组件依赖
|
||||
schema.componentsMap.forEach((info) => {
|
||||
schema.componentsMap.forEach((info: any) => {
|
||||
if (info.componentName) {
|
||||
compDeps[info.componentName] = {
|
||||
...info,
|
||||
|
||||
@ -181,7 +181,7 @@ export function parseExpressionGetKeywords(expr: string | null | undefined): str
|
||||
const fieldValue = node[fieldName as keyof typeof node];
|
||||
if (typeof fieldValue === 'object') {
|
||||
if (Array.isArray(fieldValue)) {
|
||||
fieldValue.forEach((item) => {
|
||||
fieldValue.forEach((item: any) => {
|
||||
addIdentifierIfNeeded(item);
|
||||
});
|
||||
} else {
|
||||
@ -233,7 +233,7 @@ export function parseExpressionGetGlobalVariables(
|
||||
const fieldValue = node[fieldName as keyof typeof node];
|
||||
if (typeof fieldValue === 'object') {
|
||||
if (Array.isArray(fieldValue)) {
|
||||
fieldValue.forEach((item) => {
|
||||
fieldValue.forEach((item: any) => {
|
||||
addUndeclaredIdentifierIfNeeded(item, path);
|
||||
});
|
||||
} else {
|
||||
|
||||
@ -98,7 +98,7 @@ export function createSimulator(
|
||||
doc.close();
|
||||
|
||||
return new Promise((resolve) => {
|
||||
const renderer = win.SimulatorRenderer || host.renderer;
|
||||
const renderer = win.SimulatorRenderer;
|
||||
if (renderer) {
|
||||
return resolve(renderer);
|
||||
}
|
||||
|
||||
@ -232,6 +232,10 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
return engineConfig.get('thisRequiredInJSE') ?? true;
|
||||
}
|
||||
|
||||
get enableStrictNotFoundMode(): any {
|
||||
return engineConfig.get('enableStrictNotFoundMode') ?? false;
|
||||
}
|
||||
|
||||
@computed get componentsAsset(): Asset | undefined {
|
||||
return this.get('componentsAsset');
|
||||
}
|
||||
@ -850,7 +854,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
|
||||
// filter with context
|
||||
return instances.filter((instance) => {
|
||||
return this.getClosestNodeInstance(instance, context.nodeId)?.instance === context.instance;
|
||||
return this.getClosestNodeInstance(instance, context?.nodeId)?.instance === context.instance;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -176,12 +176,29 @@ export class ComponentMeta {
|
||||
}
|
||||
|
||||
private parseMetadata(metadata: ComponentMetadata) {
|
||||
const { componentName, npm } = metadata;
|
||||
const { componentName, npm, ...others } = metadata;
|
||||
let _metadata = metadata;
|
||||
if (!npm && !Object.keys(others).length) {
|
||||
// 没有注册的组件,只能删除,不支持复制、移动等操作
|
||||
_metadata = {
|
||||
componentName,
|
||||
configure: {
|
||||
component: {
|
||||
disableBehaviors: ['copy', 'move', 'lock', 'unlock'],
|
||||
},
|
||||
advanced: {
|
||||
callbacks: {
|
||||
onMoveHook: () => false,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
this._npm = npm || this._npm;
|
||||
this._componentName = componentName;
|
||||
|
||||
// 额外转换逻辑
|
||||
this._transformedMetadata = this.transformMetadata(metadata);
|
||||
this._transformedMetadata = this.transformMetadata(_metadata);
|
||||
|
||||
const { title } = this._transformedMetadata;
|
||||
if (title) {
|
||||
|
||||
@ -23,6 +23,7 @@ import {
|
||||
setShaken,
|
||||
} from '../../src/designer/dragon';
|
||||
import { Project } from '../../src/project/project';
|
||||
import pageMetadata from '../fixtures/component-metadata/page';
|
||||
import { Node } from '../../src/document/node/node';
|
||||
import { Designer } from '../../src/designer/designer';
|
||||
import { DocumentModel } from '../../src/document/document-model';
|
||||
@ -46,6 +47,7 @@ describe('Host 测试', () => {
|
||||
beforeEach(() => {
|
||||
designer = new Designer({ editor });
|
||||
project = designer.project;
|
||||
designer.createComponentMeta(pageMetadata);
|
||||
doc = project.createDocument(formSchema);
|
||||
host = new BuiltinSimulatorHost(designer.project);
|
||||
});
|
||||
@ -373,6 +375,14 @@ describe('Host 测试', () => {
|
||||
},
|
||||
})).toBeNull();
|
||||
});
|
||||
it('notFoundComponent', () => {
|
||||
expect(host.locate({
|
||||
dragObject: {
|
||||
type: DragObjectType.Node,
|
||||
nodes: [doc.getNode('form')],
|
||||
},
|
||||
})).toBeUndefined();
|
||||
})
|
||||
it('locate', () => {
|
||||
host.locate({
|
||||
dragObject: {
|
||||
|
||||
@ -137,6 +137,10 @@ const VALID_ENGINE_OPTIONS = {
|
||||
type: 'boolean',
|
||||
description: 'JSExpression 是否只支持使用 this 来访问上下文变量',
|
||||
},
|
||||
enableStrictNotFoundMode: {
|
||||
type: 'boolean',
|
||||
description: '当开启组件未找到严格模式时,渲染模块不会默认给一个容器组件',
|
||||
},
|
||||
};
|
||||
export interface EngineOptions {
|
||||
/**
|
||||
@ -258,6 +262,12 @@ export interface EngineOptions {
|
||||
* JSExpression 是否只支持使用 this 来访问上下文变量,假如需要兼容原来的 'state.xxx',则设置为 false
|
||||
*/
|
||||
thisRequiredInJSE?: boolean;
|
||||
|
||||
/**
|
||||
* @default false
|
||||
* 当开启组件未找到严格模式时,渲染模块不会默认给一个容器组件
|
||||
*/
|
||||
enableStrictNotFoundMode?: boolean;
|
||||
}
|
||||
|
||||
const getStrictModeValue = (engineOptions: EngineOptions, defaultValue: boolean): boolean => {
|
||||
|
||||
@ -12,7 +12,9 @@
|
||||
|
||||
[![NPM version][npm-image]][npm-url] [![NPM downloads][download-image]][download-url]
|
||||
|
||||
[![][issues-helper-image]][issues-helper-url] [![Issues need help][help-wanted-image]][help-wanted-url]
|
||||
[![][issues-helper-image]][issues-helper-url] [![Issues need help][help-wanted-image]][help-wanted-url]
|
||||
|
||||
[![codecov][codecov-image-url]][codecov-url]
|
||||
|
||||
[npm-image]: https://img.shields.io/npm/v/@alilc/lowcode-engine.svg?style=flat-square
|
||||
[npm-url]: http://npmjs.org/package/@alilc/lowcode-engine
|
||||
@ -25,6 +27,9 @@
|
||||
[issues-helper-image]: https://img.shields.io/badge/using-issues--helper-orange?style=flat-square
|
||||
[issues-helper-url]: https://github.com/actions-cool/issues-helper
|
||||
|
||||
[codecov-image-url]: https://codecov.io/gh/alibaba/lowcode-engine/branch/main/graph/badge.svg
|
||||
[codecov-url]: https://codecov.io/gh/alibaba/lowcode-engine
|
||||
|
||||
</div>
|
||||
|
||||
[](https://lowcode-engine.cn)
|
||||
|
||||
@ -14,6 +14,8 @@ An enterprise-class low-code technology stack with scale-out design
|
||||
|
||||
[![][issues-helper-image]][issues-helper-url] [![Issues need help][help-wanted-image]][help-wanted-url]
|
||||
|
||||
[![codecov][codecov-image-url]][codecov-url]
|
||||
|
||||
[npm-image]: https://img.shields.io/npm/v/@alilc/lowcode-engine.svg?style=flat-square
|
||||
[npm-url]: http://npmjs.org/package/@alilc/lowcode-engine
|
||||
|
||||
@ -25,6 +27,9 @@ An enterprise-class low-code technology stack with scale-out design
|
||||
[issues-helper-image]: https://img.shields.io/badge/using-issues--helper-orange?style=flat-square
|
||||
[issues-helper-url]: https://github.com/actions-cool/issues-helper
|
||||
|
||||
[codecov-image-url]: https://codecov.io/gh/alibaba/lowcode-engine/branch/main/graph/badge.svg
|
||||
[codecov-url]: https://codecov.io/gh/alibaba/lowcode-engine
|
||||
|
||||
</div>
|
||||
|
||||
[](http://lowcode-engine.cn)
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { createElement } from 'react';
|
||||
import { render } from 'react-dom';
|
||||
import { render, unmountComponentAtNode } from 'react-dom';
|
||||
import { globalContext, Editor, engineConfig, EngineOptions } from '@alilc/lowcode-editor-core';
|
||||
import {
|
||||
Designer,
|
||||
@ -16,7 +16,7 @@ import {
|
||||
|
||||
import Outline, { OutlineBackupPane, getTreeMaster } from '@alilc/lowcode-plugin-outline-pane';
|
||||
import DesignerPlugin from '@alilc/lowcode-plugin-designer';
|
||||
import { Hotkey, Project, Skeleton, Setters, Material, Event } from '@alilc/lowcode-shell';
|
||||
import { Hotkey, Project, Skeleton, Setters, Material, Event, DocumentModel } from '@alilc/lowcode-shell';
|
||||
import { getLogger, isPlainObject } from '@alilc/lowcode-utils';
|
||||
import './modules/live-editing';
|
||||
import utils from './modules/utils';
|
||||
@ -184,7 +184,8 @@ engineConfig.set('isOpenSource', isOpenSource);
|
||||
await plugins.register(defaultPanelRegistry);
|
||||
})();
|
||||
|
||||
let engineInited = false;
|
||||
// container which will host LowCodeEngine DOM
|
||||
let engineContainer: HTMLElement;
|
||||
// @ts-ignore webpack Define variable
|
||||
export const version = VERSION_PLACEHOLDER;
|
||||
engineConfig.set('ENGINE_VERSION', version);
|
||||
@ -193,23 +194,22 @@ export async function init(
|
||||
options?: EngineOptions,
|
||||
pluginPreference?: PluginPreference,
|
||||
) {
|
||||
if (engineInited) return;
|
||||
engineInited = true;
|
||||
await destroy();
|
||||
let engineOptions = null;
|
||||
let engineContainer = null;
|
||||
if (isPlainObject(container)) {
|
||||
engineOptions = container;
|
||||
engineContainer = document.createElement('div');
|
||||
engineContainer.id = 'engine';
|
||||
document.body.appendChild(engineContainer);
|
||||
} else {
|
||||
engineOptions = options;
|
||||
engineContainer = container;
|
||||
if (!container) {
|
||||
engineContainer = document.createElement('div');
|
||||
engineContainer.id = 'engine';
|
||||
document.body.appendChild(engineContainer);
|
||||
}
|
||||
}
|
||||
engineContainer.id = 'engine';
|
||||
engineConfig.setEngineOptions(engineOptions as any);
|
||||
|
||||
await plugins.init(pluginPreference as any);
|
||||
@ -222,3 +222,17 @@ export async function init(
|
||||
engineContainer,
|
||||
);
|
||||
}
|
||||
|
||||
export async function destroy() {
|
||||
// remove all documents
|
||||
const { documents } = project;
|
||||
if (Array.isArray(documents) && documents.length > 0) {
|
||||
documents.forEach(((doc: DocumentModel) => project.removeDocument(doc)));
|
||||
}
|
||||
|
||||
// TODO: delete plugins except for core plugins
|
||||
|
||||
// unmount DOM container, this will trigger React componentWillUnmount lifeCycle,
|
||||
// so necessary cleanups will be done.
|
||||
engineContainer && unmountComponentAtNode(engineContainer);
|
||||
}
|
||||
|
||||
@ -152,7 +152,8 @@ export class OutlineMain implements ISensor, ITreeBoard, IScrollable {
|
||||
return canMove;
|
||||
});
|
||||
|
||||
if (!operationalNodes || operationalNodes.length === 0) {
|
||||
// 如果拖拽的是 Node 才需要后面的判断,拖拽 data 不需要
|
||||
if (isDragNodeObject(dragObject) && (!operationalNodes || operationalNodes.length === 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -17,7 +17,7 @@ export default function compFactory(schema, components = {}, componentsMap = {},
|
||||
const AppContext = contextFactory();
|
||||
|
||||
class LNCompView extends Component {
|
||||
static dislayName = 'lce-comp-factory';
|
||||
static displayName = 'LceCompFactory';
|
||||
|
||||
static version = config.version || '0.0.0';
|
||||
|
||||
|
||||
@ -538,6 +538,7 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer {
|
||||
// mock _leaf,减少性能开销
|
||||
const _leaf = {
|
||||
isEmpty: () => false,
|
||||
isMock: true,
|
||||
};
|
||||
viewProps._leaf = _leaf;
|
||||
return createElement(Comp, viewProps, children);
|
||||
|
||||
@ -13,7 +13,8 @@
|
||||
"scripts": {
|
||||
"test": "build-scripts test --config build.test.json",
|
||||
"build": "NODE_OPTIONS=--max_old_space_size=8192 build-scripts build --skip-demo",
|
||||
"build:umd": "NODE_OPTIONS=--max_old_space_size=8192 build-scripts build --config build.umd.json"
|
||||
"build:umd": "NODE_OPTIONS=--max_old_space_size=8192 build-scripts build --config build.umd.json",
|
||||
"test:cov": "build-scripts test --config build.test.json --jest-coverage"
|
||||
},
|
||||
"dependencies": {
|
||||
"@alilc/lowcode-designer": "1.0.15-beta.0",
|
||||
|
||||
@ -8,7 +8,7 @@ import { getClosestNode, isFromVC, isReactComponent } from '@alilc/lowcode-utils
|
||||
import { GlobalEvent } from '@alilc/lowcode-types';
|
||||
import { SimulatorRendererContainer, DocumentInstance } from './renderer';
|
||||
import { host } from './host';
|
||||
|
||||
import { isRendererDetached } from './utils/misc';
|
||||
import './renderer.less';
|
||||
|
||||
// patch cloneElement avoid lost keyProps
|
||||
@ -170,14 +170,12 @@ class Renderer extends Component<{
|
||||
this.startTime = Date.now();
|
||||
this.schemaChangedSymbol = false;
|
||||
|
||||
if (!container.autoRender) return null;
|
||||
if (!container.autoRender || isRendererDetached()) return null;
|
||||
return (
|
||||
<LowCodeRenderer
|
||||
locale={locale}
|
||||
messages={messages}
|
||||
schema={documentInstance.schema}
|
||||
deltaData={documentInstance.deltaData}
|
||||
deltaMode={documentInstance.deltaMode}
|
||||
components={container.components}
|
||||
appHelper={container.context}
|
||||
designMode={designMode}
|
||||
@ -257,6 +255,7 @@ class Renderer extends Component<{
|
||||
onCompGetRef={(schema: any, ref: ReactInstance | null) => {
|
||||
documentInstance.mountInstance(schema.id, ref);
|
||||
}}
|
||||
enableStrictNotFoundMode={host.enableStrictNotFoundMode}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@ -51,24 +51,6 @@ export class DocumentInstance {
|
||||
return this._components;
|
||||
}
|
||||
|
||||
/**
|
||||
* 本次的变更数据
|
||||
*/
|
||||
@obx.ref private _deltaData: any = {};
|
||||
|
||||
@computed get deltaData(): any {
|
||||
return this._deltaData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否使用增量模式
|
||||
*/
|
||||
@obx.ref private _deltaMode: boolean = false;
|
||||
|
||||
@computed get deltaMode(): boolean {
|
||||
return this._deltaMode;
|
||||
}
|
||||
|
||||
// context from: utils、constants、history、location、match
|
||||
@obx.ref private _appContext = {};
|
||||
|
||||
@ -116,7 +98,7 @@ export class DocumentInstance {
|
||||
return this.document.id;
|
||||
}
|
||||
|
||||
private unmountIntance(id: string, instance: ReactInstance) {
|
||||
private unmountInstance(id: string, instance: ReactInstance) {
|
||||
const instances = this.instancesMap.get(id);
|
||||
if (instances) {
|
||||
const i = instances.indexOf(instance);
|
||||
@ -144,11 +126,11 @@ export class DocumentInstance {
|
||||
}
|
||||
return;
|
||||
}
|
||||
const unmountIntance = this.unmountIntance.bind(this);
|
||||
const unmountInstance = this.unmountInstance.bind(this);
|
||||
const origId = (instance as any)[SYMBOL_VNID];
|
||||
if (origId && origId !== id) {
|
||||
// 另外一个节点的 instance 在此被复用了,需要从原来地方卸载
|
||||
unmountIntance(origId, instance);
|
||||
unmountInstance(origId, instance);
|
||||
}
|
||||
if (isElement(instance)) {
|
||||
cacheReactKey(instance);
|
||||
@ -160,7 +142,7 @@ export class DocumentInstance {
|
||||
}
|
||||
// hack! delete instance from map
|
||||
const newUnmount = function (this: any) {
|
||||
unmountIntance(id, instance);
|
||||
unmountInstance(id, instance);
|
||||
origUnmount && origUnmount.call(this);
|
||||
};
|
||||
(newUnmount as any).origUnmount = origUnmount;
|
||||
@ -465,6 +447,7 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer {
|
||||
// mock _leaf,减少性能开销
|
||||
const _leaf = {
|
||||
isEmpty: () => false,
|
||||
isMock: true,
|
||||
};
|
||||
viewProps._leaf = _leaf;
|
||||
return createElement(Comp, viewProps, children);
|
||||
|
||||
@ -24,3 +24,12 @@ export function getProjectUtils(librayMap: LibrayMap, utilsMetadata: UtilsMetada
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* judges if current simulator renderer deteched or not
|
||||
* @returns detached or not
|
||||
*/
|
||||
export function isRendererDetached() {
|
||||
// if current iframe detached from host document, the `window.parent` will be undefined.
|
||||
return !window.parent;
|
||||
}
|
||||
@ -11,7 +11,7 @@ exports[`Base should be render NotFoundComponent 1`] = `
|
||||
<div
|
||||
componentName="Text"
|
||||
>
|
||||
Component Not Found
|
||||
Text Component Not Found
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -32,7 +32,9 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@alib/build-scripts": "^0.1.18",
|
||||
"@alifd/next": "^1.26.0",
|
||||
"@alilc/lowcode-designer": "1.0.15-beta.0",
|
||||
"@alilc/lowcode-designer": "1.0.14",
|
||||
"@alilc/lowcode-test-mate": "^1.0.1",
|
||||
"@babel/plugin-transform-typescript": "^7.16.8",
|
||||
"@testing-library/react": "^11.2.2",
|
||||
|
||||
@ -21,21 +21,21 @@ class Adapter {
|
||||
}
|
||||
|
||||
initRuntime() {
|
||||
const Component: IGeneralConstructor = class {
|
||||
const Component: IGeneralConstructor = class <T = any, S = any> {
|
||||
setState() {}
|
||||
forceUpdate() {}
|
||||
render() {}
|
||||
state: Record<string, unknown>;
|
||||
props: Record<string, unknown>;
|
||||
state: Readonly<S>;
|
||||
props: Readonly<T> & Readonly<{ children?: any | undefined }>;
|
||||
refs: Record<string, unknown>;
|
||||
context: Record<string, unknown>;
|
||||
};
|
||||
const PureComponent: IGeneralConstructor = class {
|
||||
const PureComponent = class <T = any, S = any> {
|
||||
setState() {}
|
||||
forceUpdate() {}
|
||||
render() {}
|
||||
state: Record<string, unknown>;
|
||||
props: Record<string, unknown>;
|
||||
state: Readonly<S>;
|
||||
props: Readonly<T> & Readonly<{ children?: any | undefined }>;
|
||||
refs: Record<string, unknown>;
|
||||
context: Record<string, unknown>;
|
||||
};
|
||||
|
||||
@ -5,7 +5,6 @@ import { EngineOptions } from '@alilc/lowcode-editor-core';
|
||||
import { debounce } from '../utils/common';
|
||||
import adapter from '../adapter';
|
||||
import * as types from '../types/index';
|
||||
import { parseData } from '../utils';
|
||||
|
||||
export interface IComponentHocInfo {
|
||||
schema: any;
|
||||
@ -363,12 +362,12 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, {
|
||||
};
|
||||
|
||||
componentWillReceiveProps(nextProps: any) {
|
||||
let { _leaf, componentId } = nextProps;
|
||||
let { componentId } = nextProps;
|
||||
if (nextProps.__tag === this.props.__tag) {
|
||||
return null;
|
||||
}
|
||||
|
||||
_leaf = _leaf || getNode?.(componentId);
|
||||
const _leaf = getNode?.(componentId);
|
||||
if (_leaf && this.curEventLeaf && _leaf !== this.curEventLeaf) {
|
||||
this.disposeFunctions.forEach((fn) => fn());
|
||||
this.disposeFunctions = [];
|
||||
@ -514,7 +513,12 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, {
|
||||
}
|
||||
|
||||
get leaf(): Node | undefined {
|
||||
return this.props._leaf || getNode?.(componentCacheId);
|
||||
if (this.props._leaf?.isMock) {
|
||||
// 低代码组件作为一个整体更新,其内部的组件不需要监听相关事件
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return getNode?.(componentCacheId);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
@ -6,7 +6,7 @@ import { IRendererAppHelper, IBaseRendererProps, IBaseRenderComponent } from '..
|
||||
export default function addonRendererFactory(): IBaseRenderComponent {
|
||||
const BaseRenderer = baseRendererFactory();
|
||||
return class AddonRenderer extends BaseRenderer {
|
||||
static dislayName = 'addon-renderer';
|
||||
static displayName = 'AddonRenderer';
|
||||
|
||||
__namespace = 'addon';
|
||||
|
||||
@ -69,7 +69,7 @@ export default function addonRendererFactory(): IBaseRenderComponent {
|
||||
return '插件 schema 结构异常!';
|
||||
}
|
||||
|
||||
this.__debug(`${AddonRenderer.dislayName} render - ${__schema.fileName}`);
|
||||
this.__debug(`${AddonRenderer.displayName} render - ${__schema.fileName}`);
|
||||
this.__generateCtx({
|
||||
component: this,
|
||||
});
|
||||
|
||||
@ -104,13 +104,7 @@ export default function baseRendererFactory(): IBaseRenderComponent {
|
||||
return customBaseRenderer;
|
||||
}
|
||||
|
||||
const runtime = adapter.getRuntime();
|
||||
const Component = runtime.Component as IGeneralConstructor<
|
||||
IBaseRendererProps,
|
||||
Record<string, any>,
|
||||
any
|
||||
>;
|
||||
const { createElement } = runtime;
|
||||
const { Component, createElement } = adapter.getRuntime();
|
||||
const Div = divFactory();
|
||||
const VisualDom = visualDomFactory();
|
||||
const AppContext = contextFactory();
|
||||
@ -125,8 +119,8 @@ export default function baseRendererFactory(): IBaseRenderComponent {
|
||||
const DEFAULT_LOOP_ARG_INDEX = 'index';
|
||||
let scopeIdx = 0;
|
||||
|
||||
return class BaseRenderer extends Component {
|
||||
static displayName = 'base-renderer';
|
||||
return class BaseRenderer extends Component<IBaseRendererProps, Record<string, any>> {
|
||||
static displayName = 'BaseRenderer';
|
||||
|
||||
static defaultProps = {
|
||||
__schema: {},
|
||||
@ -533,6 +527,10 @@ export default function baseRendererFactory(): IBaseRenderComponent {
|
||||
{
|
||||
componentName: schema.componentName,
|
||||
componentId: schema.id,
|
||||
enableStrictNotFoundMode: engine.props.enableStrictNotFoundMode,
|
||||
ref: (ref: any) => {
|
||||
ref && engine.props?.onCompGetRef(schema, ref);
|
||||
},
|
||||
},
|
||||
this.__getSchemaChildrenVirtualDom(schema, scope, Comp),
|
||||
);
|
||||
|
||||
@ -4,7 +4,7 @@ import { IBaseRendererProps, IBaseRenderComponent } from '../types';
|
||||
export default function blockRendererFactory(): IBaseRenderComponent {
|
||||
const BaseRenderer = baseRendererFactory();
|
||||
return class BlockRenderer extends BaseRenderer {
|
||||
static dislayName = 'block-renderer';
|
||||
static displayName = 'BlockRenderer';
|
||||
|
||||
__namespace = 'block';
|
||||
|
||||
@ -23,7 +23,7 @@ export default function blockRendererFactory(): IBaseRenderComponent {
|
||||
return '区块 schema 结构异常!';
|
||||
}
|
||||
|
||||
this.__debug(`${BlockRenderer.dislayName} render - ${__schema?.fileName}`);
|
||||
this.__debug(`${BlockRenderer.displayName} render - ${__schema?.fileName}`);
|
||||
this.__generateCtx({});
|
||||
this.__render();
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@ import { IBaseRendererProps, IBaseRenderComponent } from '../types';
|
||||
export default function componentRendererFactory(): IBaseRenderComponent {
|
||||
const BaseRenderer = baseRendererFactory();
|
||||
return class CompRenderer extends BaseRenderer {
|
||||
static dislayName = 'comp-renderer';
|
||||
static displayName = 'CompRenderer';
|
||||
|
||||
__namespace = 'component';
|
||||
|
||||
@ -23,7 +23,7 @@ export default function componentRendererFactory(): IBaseRenderComponent {
|
||||
if (this.__checkSchema(__schema)) {
|
||||
return '自定义组件 schema 结构异常!';
|
||||
}
|
||||
this.__debug(`${CompRenderer.dislayName} render - ${__schema.fileName}`);
|
||||
this.__debug(`${CompRenderer.displayName} render - ${__schema.fileName}`);
|
||||
|
||||
this.__generateCtx({
|
||||
component: this,
|
||||
|
||||
@ -4,7 +4,7 @@ import { IBaseRendererProps, IBaseRenderComponent } from '../types';
|
||||
export default function pageRendererFactory(): IBaseRenderComponent {
|
||||
const BaseRenderer = baseRendererFactory();
|
||||
return class PageRenderer extends BaseRenderer {
|
||||
static dislayName = 'page-renderer';
|
||||
static displayName = 'PageRenderer';
|
||||
|
||||
__namespace = 'page';
|
||||
|
||||
@ -34,7 +34,7 @@ export default function pageRendererFactory(): IBaseRenderComponent {
|
||||
if (this.__checkSchema(__schema)) {
|
||||
return '页面schema结构异常!';
|
||||
}
|
||||
this.__debug(`${PageRenderer.dislayName} render - ${__schema.fileName}`);
|
||||
this.__debug(`${PageRenderer.displayName} render - ${__schema.fileName}`);
|
||||
|
||||
this.__bindCustomMethods(this.props);
|
||||
this.__initDataSource(this.props);
|
||||
|
||||
@ -4,14 +4,11 @@ import contextFactory from '../context';
|
||||
import { isFileSchema, isEmpty } from '../utils';
|
||||
import baseRendererFactory from './base';
|
||||
import divFactory from '../components/Div';
|
||||
import { IGeneralConstructor, IRenderComponent, IRendererProps, IRendererState } from '../types';
|
||||
import { RootSchema } from '@alilc/lowcode-types';
|
||||
import { IRenderComponent, IRendererProps, IRendererState } from '../types';
|
||||
import { NodeSchema, RootSchema } from '@alilc/lowcode-types';
|
||||
|
||||
export default function rendererFactory(): IRenderComponent {
|
||||
const runtime = adapter.getRuntime();
|
||||
const Component = runtime.Component as IGeneralConstructor<IRendererProps, Record<string, any>>;
|
||||
const PureComponent = runtime.PureComponent as IGeneralConstructor<IRendererProps, Record<string, any>>;
|
||||
const { createElement, findDOMNode } = runtime;
|
||||
const { PureComponent, Component, createElement, findDOMNode } = adapter.getRuntime();
|
||||
const RENDERER_COMPS: any = adapter.getRenderers();
|
||||
const BaseRenderer = baseRendererFactory();
|
||||
const AppContext = contextFactory();
|
||||
@ -21,7 +18,7 @@ export default function rendererFactory(): IRenderComponent {
|
||||
|
||||
const debug = Debug('renderer:entry');
|
||||
|
||||
class FaultComponent extends PureComponent {
|
||||
class FaultComponent extends PureComponent<NodeSchema> {
|
||||
render() {
|
||||
// FIXME: errorlog
|
||||
console.error('render error', this.props);
|
||||
@ -35,18 +32,23 @@ export default function rendererFactory(): IRenderComponent {
|
||||
color: '#ff0000',
|
||||
border: '2px solid #ff0000',
|
||||
},
|
||||
}, '组件渲染异常,请查看控制台日志');
|
||||
}, `${this.props.componentName || ''} 组件渲染异常,请查看控制台日志`);
|
||||
}
|
||||
}
|
||||
|
||||
class NotFoundComponent extends PureComponent {
|
||||
class NotFoundComponent extends PureComponent<{
|
||||
componentName: string;
|
||||
} & IRendererProps> {
|
||||
render() {
|
||||
return createElement(Div, this.props, this.props.children || 'Component Not Found');
|
||||
if (this.props.enableStrictNotFoundMode) {
|
||||
return `${this.props.componentName || ''} Component Not Found`;
|
||||
}
|
||||
return createElement(Div, this.props, this.props.children || `${this.props.componentName || ''} Component Not Found`);
|
||||
}
|
||||
}
|
||||
|
||||
return class Renderer extends Component {
|
||||
static dislayName = 'renderer';
|
||||
return class Renderer extends Component<IRendererProps> {
|
||||
static displayName = 'Renderer';
|
||||
|
||||
state: Partial<IRendererState> = {};
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@ export default function tempRendererFactory(): IBaseRenderComponent {
|
||||
const BaseRenderer = baseRendererFactory();
|
||||
|
||||
return class TempRenderer extends BaseRenderer {
|
||||
static dislayName = 'temp-renderer';
|
||||
static displayName = 'TempRenderer';
|
||||
|
||||
__namespace = 'temp';
|
||||
|
||||
@ -51,7 +51,7 @@ export default function tempRendererFactory(): IBaseRenderComponent {
|
||||
return '下钻编辑 schema 结构异常!';
|
||||
}
|
||||
|
||||
this.__debug(`${TempRenderer.dislayName} render - ${__schema?.fileName}`);
|
||||
this.__debug(`${TempRenderer.displayName} render - ${__schema?.fileName}`);
|
||||
|
||||
return this.__renderContent(this.__renderContextProvider({ __ctx }));
|
||||
}
|
||||
|
||||
@ -21,12 +21,12 @@ interface IGeneralComponent<P = {}, S = {}, SS = any> extends ComponentLifecycle
|
||||
}
|
||||
|
||||
export type IGeneralConstructor<
|
||||
P = {
|
||||
T = {
|
||||
[key: string]: any;
|
||||
}, S = {
|
||||
[key: string]: any;
|
||||
}, SS = any
|
||||
> = new (props: any, context: any) => IGeneralComponent<P, S, SS>;
|
||||
}, D = any
|
||||
> = new <TT = T, SS = S, DD = D>(props: TT, context: any) => IGeneralComponent<TT, SS, DD>;
|
||||
|
||||
/**
|
||||
* duck-typed History
|
||||
@ -133,6 +133,11 @@ export interface IRendererProps {
|
||||
* JSExpression 是否只支持使用 this 来访问上下文变量
|
||||
*/
|
||||
thisRequiredInJSE?: boolean;
|
||||
/**
|
||||
* @default false
|
||||
* 当开启组件未找到严格模式时,渲染模块不会默认给一个容器组件
|
||||
*/
|
||||
enableStrictNotFoundMode?: boolean;
|
||||
}
|
||||
|
||||
export interface IRendererState {
|
||||
@ -288,7 +293,7 @@ export interface IRenderComponent {
|
||||
getNotFoundComponent(): any;
|
||||
getFaultComponent(): any;
|
||||
};
|
||||
dislayName: string;
|
||||
displayName: string;
|
||||
defaultProps: IRendererProps;
|
||||
findDOMNode: (...args: any) => any;
|
||||
}
|
||||
|
||||
@ -18,7 +18,9 @@ exports[`children this.props.children is array 1`] = `
|
||||
exports[`lifecycle leaf change and make componentWillReceiveProps 1`] = `
|
||||
<div>
|
||||
<div
|
||||
__id="text6"
|
||||
__tag="222"
|
||||
componentId="text6"
|
||||
content="content new leaf"
|
||||
>
|
||||
content new leaf
|
||||
|
||||
@ -193,9 +193,10 @@ describe('lifecycle', () => {
|
||||
|
||||
it('leaf change and make componentWillReceiveProps', () => {
|
||||
const newTextNodeLeaf = new Node(textSchema);
|
||||
nodeMap.set(textSchema.id, newTextNodeLeaf);
|
||||
component.update((
|
||||
<Div _leaf={DivNode}>
|
||||
<Text _leaf={newTextNodeLeaf} __tag="222" content="content 123"></Text>
|
||||
<Text componentId={textSchema.id} __tag="222" content="content 123"></Text>
|
||||
</Div>
|
||||
));
|
||||
|
||||
@ -232,6 +233,9 @@ describe('mini unit render', () => {
|
||||
parent: MiniRenderDivNode,
|
||||
});
|
||||
|
||||
nodeMap.set(miniRenderSchema.id, MiniRenderDivNode);
|
||||
nodeMap.set(textSchema.id, TextNode);
|
||||
|
||||
component = renderer.create(
|
||||
// @ts-ignore
|
||||
<MiniRenderDiv _leaf={MiniRenderDivNode}>
|
||||
@ -277,6 +281,8 @@ describe('mini unit render', () => {
|
||||
}),
|
||||
});
|
||||
|
||||
nodeMap.set(textSchema.id, TextNode);
|
||||
|
||||
renderer.create(
|
||||
// @ts-ignore
|
||||
<div>
|
||||
@ -319,6 +325,8 @@ describe('mini unit render', () => {
|
||||
isRoot: true,
|
||||
});
|
||||
|
||||
nodeMap.set(textSchema.id, TextNode);
|
||||
|
||||
const component = renderer.create(
|
||||
<Text _leaf={TextNode} content="content"></Text>
|
||||
);
|
||||
@ -351,6 +359,8 @@ describe('mini unit render', () => {
|
||||
})
|
||||
});
|
||||
|
||||
nodeMap.set(textSchema.id, TextNode);
|
||||
|
||||
const component = renderer.create(
|
||||
<Text _leaf={TextNode} content="content"></Text>
|
||||
);
|
||||
@ -370,7 +380,9 @@ describe('mini unit render', () => {
|
||||
});
|
||||
|
||||
it('parent is a mock leaf', () => {
|
||||
const MiniRenderDivNode = {};
|
||||
const MiniRenderDivNode = {
|
||||
isMock: true,
|
||||
};
|
||||
|
||||
const component = renderer.create(
|
||||
// @ts-ignore
|
||||
@ -409,6 +421,9 @@ describe('mini unit render', () => {
|
||||
hasLoop: true,
|
||||
});
|
||||
|
||||
nodeMap.set(textSchema.id, TextNode);
|
||||
nodeMap.set(miniRenderSchema.id, MiniRenderDivNode);
|
||||
|
||||
component = renderer.create(
|
||||
// @ts-ignore
|
||||
<MiniRenderDiv _leaf={MiniRenderDivNode}>
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import {
|
||||
BuiltinSimulatorHost,
|
||||
} from '@alilc/lowcode-designer';
|
||||
import { simulatorHostSymbol } from './symbols';
|
||||
import { simulatorHostSymbol, nodeSymbol } from './symbols';
|
||||
import type Node from './node';
|
||||
|
||||
export default class SimulatorHost {
|
||||
private readonly [simulatorHostSymbol]: BuiltinSimulatorHost;
|
||||
@ -51,6 +52,14 @@ export default class SimulatorHost {
|
||||
return this[simulatorHostSymbol].get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* scroll to specific node
|
||||
* @param node
|
||||
*/
|
||||
scrollToNode(node: Node) {
|
||||
this[simulatorHostSymbol].scrollToNode(node[nodeSymbol]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新渲染画布
|
||||
*/
|
||||
|
||||
@ -617,8 +617,8 @@ component
|
||||
| screenshot | 组件快照 | String | 否 |
|
||||
| icon | 组件的小图标 | String (URL) | 是 |
|
||||
| tags | 组件标签 | String | 是 |
|
||||
| keywards | 组件关键词,用于搜索联想 | String | 是 |
|
||||
| devMode | 组件研发模式 | String (procode,lowcode) | 是 |
|
||||
| keywords | 组件关键词,用于搜索联想 | String | 是 |
|
||||
| devMode | 组件研发模式 | String (proCode,lowCode) | 是 |
|
||||
| npm | npm 源引入完整描述对象 | Object | 否 |
|
||||
| npm.package | 源码组件库名 | String | 否 |
|
||||
| npm.exportName | 源码组件名称 | String | 否 |
|
||||
@ -857,7 +857,7 @@ props 数组下对象字段描述:
|
||||
// 支持条件设置
|
||||
"condition": true,
|
||||
// 支持样式设置
|
||||
"styles": true,
|
||||
"style": true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user