mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2025-12-11 18:42:56 +00:00
feat: lowCode components support project schema
This commit is contained in:
parent
fb3aea4f27
commit
f6537f536f
@ -1,12 +1,12 @@
|
||||
import { Component } from '../simulator';
|
||||
import { IPublicTypeNodeSchema, IPublicTypeComponentInstance, IPublicTypeNodeInstance, Asset } from '@alilc/lowcode-types';
|
||||
import { IPublicTypeComponentInstance, IPublicTypeNodeInstance, Asset, IPublicTypeComponentSchema, IPublicTypeProjectSchema, IPublicTypeLowCodeComponent } from '@alilc/lowcode-types';
|
||||
|
||||
export interface BuiltinSimulatorRenderer {
|
||||
readonly isSimulatorRenderer: true;
|
||||
autoRepaintNode?: boolean;
|
||||
components: Record<string, Component>;
|
||||
rerender: () => void;
|
||||
createComponent(schema: IPublicTypeNodeSchema): Component | null;
|
||||
createComponent(schema: IPublicTypeProjectSchema<IPublicTypeComponentSchema>): Component | null;
|
||||
getComponent(componentName: string): Component;
|
||||
getClosestNodeInstance(
|
||||
from: IPublicTypeComponentInstance,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { BuiltinSimulatorRenderer, Component, DocumentModel, Node } from '@alilc/lowcode-designer';
|
||||
import { IPublicTypeComponentSchema, IPublicTypeNodeSchema, IPublicTypeNpmInfo, IPublicEnumTransformStage, IPublicTypeNodeInstance } from '@alilc/lowcode-types';
|
||||
import { Asset, compatibleLegaoSchema, cursor, isElement, isESModule, isPlainObject, isReactComponent, setNativeSelection } from '@alilc/lowcode-utils';
|
||||
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';
|
||||
@ -47,15 +47,23 @@ const builtinComponents = {
|
||||
function buildComponents(
|
||||
libraryMap: LibraryMap,
|
||||
componentsMap: { [componentName: string]: IPublicTypeNpmInfo | ComponentType<any> | IPublicTypeComponentSchema },
|
||||
createComponent: (schema: IPublicTypeComponentSchema) => Component | null,
|
||||
createComponent: (schema: IPublicTypeProjectSchema<IPublicTypeComponentSchema>) => Component | null,
|
||||
) {
|
||||
const components: any = {
|
||||
...builtinComponents,
|
||||
};
|
||||
Object.keys(componentsMap).forEach((componentName) => {
|
||||
let component = componentsMap[componentName];
|
||||
if (component && (component as IPublicTypeComponentSchema).componentName === 'Component') {
|
||||
components[componentName] = createComponent(component as IPublicTypeComponentSchema);
|
||||
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 {
|
||||
@ -110,7 +118,7 @@ export class DocumentInstance {
|
||||
return this.document.export(IPublicEnumTransformStage.Render);
|
||||
}
|
||||
|
||||
constructor(readonly container: SimulatorRendererContainer, readonly document: DocumentModel) {
|
||||
constructor(readonly container: SimulatorRendererContainer, readonly document: IDocumentModel) {
|
||||
makeObservable(this);
|
||||
}
|
||||
|
||||
@ -221,7 +229,7 @@ export class DocumentInstance {
|
||||
return this.instancesMap.get(id) || null;
|
||||
}
|
||||
|
||||
getNode(id: string): Node<IPublicTypeNodeSchema> | null {
|
||||
getNode(id: string): IBaseNode<IPublicTypeNodeSchema> | null {
|
||||
return this.document.getNode(id);
|
||||
}
|
||||
}
|
||||
@ -256,6 +264,8 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer {
|
||||
// sync designMode
|
||||
this._designMode = host.designMode;
|
||||
|
||||
this._locale = host.locale;
|
||||
|
||||
// sync requestHandlersMap
|
||||
this._requestHandlersMap = host.requestHandlersMap;
|
||||
|
||||
@ -343,11 +353,11 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer {
|
||||
// TODO: remove this.createComponent
|
||||
this._components = buildComponents(this._libraryMap, this._componentsMap, this.createComponent.bind(this));
|
||||
}
|
||||
@obx.ref private _components: any = {};
|
||||
@computed get components(): object {
|
||||
@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;
|
||||
return this._components || {};
|
||||
}
|
||||
// context from: utils、constants、history、location、match
|
||||
@obx.ref private _appContext = {};
|
||||
@ -362,6 +372,10 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer {
|
||||
@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;
|
||||
@ -378,12 +392,15 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer {
|
||||
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];
|
||||
const component = this._components?.[componentName];
|
||||
if (component) {
|
||||
return getSubComponent(component, subs);
|
||||
}
|
||||
@ -416,7 +433,7 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer {
|
||||
// if (instance && SYMBOL_VNID in instance) {
|
||||
// const docId = (instance.props as any).schema.docId;
|
||||
return {
|
||||
docId: instance.props._leaf.document.id,
|
||||
docId: instance.props._leaf.document?.id || '',
|
||||
nodeId: instance.props._leaf.getId(),
|
||||
instance,
|
||||
node: instance.props._leaf,
|
||||
@ -497,17 +514,26 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer {
|
||||
this.currentDocumentInstance?.refresh();
|
||||
}
|
||||
|
||||
createComponent(schema: IPublicTypeNodeSchema): Component | null {
|
||||
const _schema: any = {
|
||||
...compatibleLegaoSchema(schema),
|
||||
stopAutoRepaintNode() {
|
||||
}
|
||||
|
||||
enableAutoRepaintNode() {
|
||||
}
|
||||
|
||||
createComponent(schema: IPublicTypeProjectSchema<IPublicTypeComponentSchema>): Component | null {
|
||||
const _schema: IPublicTypeProjectSchema<IPublicTypeComponentSchema> = {
|
||||
...schema,
|
||||
componentsTree: schema.componentsTree.map(compatibleLegaoSchema),
|
||||
};
|
||||
|
||||
if (schema.componentName === 'Component' && (schema as IPublicTypeComponentSchema).css) {
|
||||
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-${schema.id || ''}`);
|
||||
s.appendChild(doc.createTextNode((schema as IPublicTypeComponentSchema).css || ''));
|
||||
s.setAttribute('id', `Component-${componentsTreeSchema.id || ''}`);
|
||||
s.appendChild(doc.createTextNode(componentsTreeSchema.css || ''));
|
||||
doc.getElementsByTagName('head')[0].appendChild(s);
|
||||
}
|
||||
|
||||
@ -520,9 +546,11 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer {
|
||||
// @ts-ignore
|
||||
return createElement(LowCodeRenderer, {
|
||||
...extraProps,
|
||||
schema: _schema,
|
||||
schema: componentsTreeSchema,
|
||||
components,
|
||||
designMode: '',
|
||||
locale: renderer.locale,
|
||||
messages: _schema.i18n || {},
|
||||
device: renderer.device,
|
||||
appHelper: renderer.context,
|
||||
rendererName: 'LowCodeRenderer',
|
||||
|
||||
@ -17,9 +17,9 @@ import {
|
||||
AssetLoader,
|
||||
getProjectUtils,
|
||||
} from '@alilc/lowcode-utils';
|
||||
import { IPublicTypeComponentSchema, IPublicEnumTransformStage, IPublicTypeNodeSchema, IPublicTypeNodeInstance } from '@alilc/lowcode-types';
|
||||
import { IPublicTypeComponentSchema, IPublicEnumTransformStage, IPublicTypeNodeInstance, IPublicTypeProjectSchema } from '@alilc/lowcode-types';
|
||||
// just use types
|
||||
import { BuiltinSimulatorRenderer, Component, DocumentModel, Node } from '@alilc/lowcode-designer';
|
||||
import { BuiltinSimulatorRenderer, Component, IDocumentModel, INode } from '@alilc/lowcode-designer';
|
||||
import LowCodeRenderer from '@alilc/lowcode-react-renderer';
|
||||
import { createMemoryHistory, MemoryHistory } from 'history';
|
||||
import Slot from './builtin-components/slot';
|
||||
@ -94,7 +94,7 @@ export class DocumentInstance {
|
||||
return this.document.id;
|
||||
}
|
||||
|
||||
constructor(readonly container: SimulatorRendererContainer, readonly document: DocumentModel) {
|
||||
constructor(readonly container: SimulatorRendererContainer, readonly document: IDocumentModel) {
|
||||
makeObservable(this);
|
||||
}
|
||||
|
||||
@ -173,7 +173,7 @@ export class DocumentInstance {
|
||||
mountContext() {
|
||||
}
|
||||
|
||||
getNode(id: string): Node | null {
|
||||
getNode(id: string): INode | null {
|
||||
return this.document.getNode(id);
|
||||
}
|
||||
|
||||
@ -207,12 +207,12 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer {
|
||||
|
||||
private _libraryMap: { [key: string]: string } = {};
|
||||
|
||||
private _components: any = {};
|
||||
private _components: Record<string, React.FC | React.ComponentClass> | null = {};
|
||||
|
||||
get components(): object {
|
||||
get components(): Record<string, React.FC | React.ComponentClass> {
|
||||
// 根据 device 选择不同组件,进行响应式
|
||||
// 更好的做法是,根据 device 选择加载不同的组件资源,甚至是 simulatorUrl
|
||||
return this._components;
|
||||
return this._components || {};
|
||||
}
|
||||
// context from: utils、constants、history、location、match
|
||||
@obx.ref private _appContext: any = {};
|
||||
@ -388,7 +388,7 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer {
|
||||
const subs: string[] = [];
|
||||
|
||||
while (true) {
|
||||
const component = this._components[componentName];
|
||||
const component = this._components?.[componentName];
|
||||
if (component) {
|
||||
return getSubComponent(component, subs);
|
||||
}
|
||||
@ -430,17 +430,20 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer {
|
||||
cursor.release();
|
||||
}
|
||||
|
||||
createComponent(schema: IPublicTypeNodeSchema): Component | null {
|
||||
const _schema: any = {
|
||||
...compatibleLegaoSchema(schema),
|
||||
createComponent(schema: IPublicTypeProjectSchema<IPublicTypeComponentSchema>): Component | null {
|
||||
const _schema: IPublicTypeProjectSchema<IPublicTypeComponentSchema> = {
|
||||
...schema,
|
||||
componentsTree: schema.componentsTree.map(compatibleLegaoSchema),
|
||||
};
|
||||
|
||||
if (schema.componentName === 'Component' && (schema as IPublicTypeComponentSchema).css) {
|
||||
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-${schema.id || ''}`);
|
||||
s.appendChild(doc.createTextNode((schema as IPublicTypeComponentSchema).css || ''));
|
||||
s.setAttribute('id', `Component-${componentsTreeSchema.id || ''}`);
|
||||
s.appendChild(doc.createTextNode(componentsTreeSchema.css || ''));
|
||||
doc.getElementsByTagName('head')[0].appendChild(s);
|
||||
}
|
||||
|
||||
@ -452,9 +455,11 @@ export class SimulatorRendererContainer implements BuiltinSimulatorRenderer {
|
||||
return createElement(LowCodeRenderer, {
|
||||
...extraProps, // 防止覆盖下面内置属性
|
||||
// 使用 _schema 为了使低代码组件在页面设计中使用变量,同 react 组件使用效果一致
|
||||
schema: _schema,
|
||||
schema: componentsTreeSchema,
|
||||
components: renderer.components,
|
||||
designMode: '',
|
||||
locale: renderer.locale,
|
||||
messages: _schema.i18n || {},
|
||||
device: renderer.device,
|
||||
appHelper: renderer.context,
|
||||
rendererName: 'LowCodeRenderer',
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { EitherOr } from '../../utils';
|
||||
import { IPublicTypeComponentSchema } from './';
|
||||
import { IPublicTypeComponentSchema, IPublicTypeProjectSchema } from './';
|
||||
|
||||
/**
|
||||
* 定义组件大包及 external 资源的信息
|
||||
@ -51,5 +51,5 @@ export type IPublicTypePackage = EitherOr<{
|
||||
/**
|
||||
* 低代码组件 schema 内容
|
||||
*/
|
||||
schema?: IPublicTypeComponentSchema;
|
||||
schema?: IPublicTypeProjectSchema<IPublicTypeComponentSchema>;
|
||||
}, 'package', 'id'>;
|
||||
|
||||
@ -19,7 +19,7 @@ export type IPublicTypeUtilsMap = IPublicTypeUtilItem[];
|
||||
* 应用描述
|
||||
*/
|
||||
|
||||
export interface IPublicTypeProjectSchema {
|
||||
export interface IPublicTypeProjectSchema<T = IPublicTypeRootSchema> {
|
||||
id?: string;
|
||||
/**
|
||||
* 当前应用协议版本号
|
||||
@ -34,7 +34,7 @@ export interface IPublicTypeProjectSchema {
|
||||
* 低代码业务组件树描述
|
||||
* 是长度固定为 1 的数组,即数组内仅包含根容器的描述(低代码业务组件容器类型)
|
||||
*/
|
||||
componentsTree: IPublicTypeRootSchema[];
|
||||
componentsTree: T[];
|
||||
/**
|
||||
* 国际化语料
|
||||
*/
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
import { ComponentType, forwardRef, createElement, FunctionComponent } from 'react';
|
||||
import { IPublicTypeNpmInfo, IPublicTypeComponentSchema } from '@alilc/lowcode-types';
|
||||
import { IPublicTypeNpmInfo, IPublicTypeComponentSchema, IPublicTypeProjectSchema } from '@alilc/lowcode-types';
|
||||
import { isESModule } from './is-es-module';
|
||||
import { isReactComponent, acceptsRef, wrapReactClass } from './is-react';
|
||||
import { isObject } from './is-object';
|
||||
import { isLowcodeProjectSchema } from './check-types';
|
||||
import { isComponentSchema } from './check-types/is-component-schema';
|
||||
|
||||
type Component = ComponentType<any> | object;
|
||||
interface LibraryMap {
|
||||
@ -95,12 +97,20 @@ function isMixinComponent(components: any) {
|
||||
|
||||
export function buildComponents(libraryMap: LibraryMap,
|
||||
componentsMap: { [componentName: string]: IPublicTypeNpmInfo | ComponentType<any> | IPublicTypeComponentSchema },
|
||||
createComponent: (schema: IPublicTypeComponentSchema) => Component | null) {
|
||||
createComponent: (schema: IPublicTypeProjectSchema<IPublicTypeComponentSchema>) => Component | null) {
|
||||
const components: any = {};
|
||||
Object.keys(componentsMap).forEach((componentName) => {
|
||||
let component = componentsMap[componentName];
|
||||
if (component && (component as IPublicTypeComponentSchema).componentName === 'Component') {
|
||||
components[componentName] = createComponent(component as IPublicTypeComponentSchema);
|
||||
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)) {
|
||||
if (!acceptsRef(component)) {
|
||||
component = wrapReactClass(component as FunctionComponent);
|
||||
|
||||
@ -20,4 +20,7 @@ export * from './is-drag-any-object';
|
||||
export * from './is-location-children-detail';
|
||||
export * from './is-node';
|
||||
export * from './is-location-data';
|
||||
export * from './is-setting-field';
|
||||
export * from './is-setting-field';
|
||||
export * from './is-lowcode-component-type';
|
||||
export * from './is-lowcode-project-schema';
|
||||
export * from './is-component-schema';
|
||||
8
packages/utils/src/check-types/is-component-schema.ts
Normal file
8
packages/utils/src/check-types/is-component-schema.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { IPublicTypeComponentSchema } from "@alilc/lowcode-types";
|
||||
|
||||
export function isComponentSchema(schema: any): schema is IPublicTypeComponentSchema {
|
||||
if (typeof schema === 'object') {
|
||||
return schema.componentName === 'Component';
|
||||
}
|
||||
return false
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
import { isProCodeComponentType } from './is-procode-component-type';
|
||||
import { IPublicTypeComponentMap } from '@alilc/lowcode-types';
|
||||
import { IPublicTypeComponentMap, IPublicTypeLowCodeComponent } from '@alilc/lowcode-types';
|
||||
|
||||
|
||||
export function isLowCodeComponentType(desc: IPublicTypeComponentMap): boolean {
|
||||
export function isLowCodeComponentType(desc: IPublicTypeComponentMap): desc is IPublicTypeLowCodeComponent {
|
||||
return !isProCodeComponentType(desc);
|
||||
}
|
||||
|
||||
@ -0,0 +1,6 @@
|
||||
import { IPublicTypeComponentSchema, IPublicTypeProjectSchema } from "@alilc/lowcode-types";
|
||||
import { isComponentSchema } from "./is-component-schema";
|
||||
|
||||
export function isLowcodeProjectSchema(data: any): data is IPublicTypeProjectSchema<IPublicTypeComponentSchema> {
|
||||
return data && data.componentsTree && data.componentsTree.length && isComponentSchema(data.componentsTree[0]);
|
||||
}
|
||||
@ -1,3 +1,5 @@
|
||||
export function isProjectSchema(data: any): boolean {
|
||||
import { IPublicTypeProjectSchema } from "@alilc/lowcode-types";
|
||||
|
||||
export function isProjectSchema(data: any): data is IPublicTypeProjectSchema {
|
||||
return data && data.componentsTree;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user