mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-01-23 09:58:12 +00:00
complete trunk polyfill
This commit is contained in:
parent
4531562f79
commit
0430bfd219
@ -100,7 +100,7 @@ class Toolbar extends Component<{ observed: OffsetObserver }> {
|
|||||||
// FIXME: need this?
|
// FIXME: need this?
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (important && (typeof condition === 'function' ? condition(node) : condition !== false)) {
|
if (important && (typeof condition === 'function' ? condition(node) !== false : condition !== false)) {
|
||||||
actions.push(createAction(content, name, node));
|
actions.push(createAction(content, name, node));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -120,7 +120,7 @@ function createAction(content: ReactNode | ComponentType<any> | ActionContentObj
|
|||||||
return createElement(content, { key, node });
|
return createElement(content, { key, node });
|
||||||
}
|
}
|
||||||
if (isActionContentObject(content)) {
|
if (isActionContentObject(content)) {
|
||||||
const { action, description, icon } = content;
|
const { action, title, icon } = content;
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={key}
|
key={key}
|
||||||
@ -130,7 +130,7 @@ function createAction(content: ReactNode | ComponentType<any> | ActionContentObj
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{icon && createIcon(icon)}
|
{icon && createIcon(icon)}
|
||||||
<EmbedTip>{description}</EmbedTip>
|
<EmbedTip>{title}</EmbedTip>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,18 +31,18 @@ import clipboard from '../designer/clipboard';
|
|||||||
export interface LibraryItem {
|
export interface LibraryItem {
|
||||||
package: string;
|
package: string;
|
||||||
library: string;
|
library: string;
|
||||||
urls: Asset;
|
urls?: Asset;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BuiltinSimulatorProps {
|
export interface BuiltinSimulatorProps {
|
||||||
// 从 documentModel 上获取
|
// 从 documentModel 上获取
|
||||||
// suspended?: boolean;
|
// suspended?: boolean;
|
||||||
designMode?: 'live' | 'design' | 'mock' | 'extend' | 'border' | 'preview';
|
designMode?: 'live' | 'design' | 'preview' | 'extend' | 'border';
|
||||||
device?: 'mobile' | 'iphone' | string;
|
device?: 'mobile' | 'iphone' | string;
|
||||||
deviceClassName?: string;
|
deviceClassName?: string;
|
||||||
simulatorUrl?: Asset;
|
|
||||||
environment?: Asset;
|
environment?: Asset;
|
||||||
library?: LibraryItem[];
|
library?: LibraryItem[];
|
||||||
|
simulatorUrl?: Asset;
|
||||||
theme?: Asset;
|
theme?: Asset;
|
||||||
componentsAsset?: Asset;
|
componentsAsset?: Asset;
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
@ -79,8 +79,6 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
|||||||
readonly designer = this.document.designer;
|
readonly designer = this.document.designer;
|
||||||
|
|
||||||
@computed get device(): string | undefined {
|
@computed get device(): string | undefined {
|
||||||
// 根据 device 不同来做画布外框样式变化 渲染时可选择不同组件
|
|
||||||
// renderer 依赖
|
|
||||||
return this.get('device') || 'default';
|
return this.get('device') || 'default';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,7 +86,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
|||||||
return this.get('deviceClassName');
|
return this.get('deviceClassName');
|
||||||
}
|
}
|
||||||
|
|
||||||
@computed get designMode(): 'live' | 'design' | 'extend' | 'border' | 'preview' {
|
@computed get designMode(): 'live' | 'design' | 'preview' {
|
||||||
// renderer 依赖
|
// renderer 依赖
|
||||||
// TODO: 需要根据 design mode 不同切换鼠标响应情况
|
// TODO: 需要根据 design mode 不同切换鼠标响应情况
|
||||||
return this.get('designMode') || 'design';
|
return this.get('designMode') || 'design';
|
||||||
@ -180,7 +178,9 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
|||||||
if (library) {
|
if (library) {
|
||||||
library.forEach((item) => {
|
library.forEach((item) => {
|
||||||
this.libraryMap[item.package] = item.library;
|
this.libraryMap[item.package] = item.library;
|
||||||
|
if (item.urls) {
|
||||||
libraryAsset.push(item.urls);
|
libraryAsset.push(item.urls);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -32,44 +32,8 @@ function ensureAList(list?: string | string[]): string[] | null {
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
function npmToURI(npm: {
|
|
||||||
package: string;
|
|
||||||
exportName?: string;
|
|
||||||
subName?: string;
|
|
||||||
destructuring?: boolean;
|
|
||||||
main?: string;
|
|
||||||
version: string;
|
|
||||||
}): string {
|
|
||||||
const pkg = [];
|
|
||||||
if (npm.package) {
|
|
||||||
pkg.push(npm.package);
|
|
||||||
}
|
|
||||||
if (npm.main) {
|
|
||||||
if (npm.main[0] === '/') {
|
|
||||||
pkg.push(npm.main.slice(1));
|
|
||||||
} else if (npm.main.slice(0, 2) === './') {
|
|
||||||
pkg.push(npm.main.slice(2));
|
|
||||||
} else {
|
|
||||||
pkg.push(npm.main);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let uri = pkg.join('/');
|
|
||||||
uri += `:${npm.destructuring && npm.exportName ? npm.exportName : 'default'}`;
|
|
||||||
|
|
||||||
if (npm.subName) {
|
|
||||||
uri += `.${npm.subName}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ComponentMeta {
|
export class ComponentMeta {
|
||||||
readonly isComponentMeta = true;
|
readonly isComponentMeta = true;
|
||||||
private _uri?: string;
|
|
||||||
get uri(): string {
|
|
||||||
return this._uri!;
|
|
||||||
}
|
|
||||||
private _npm?: NpmInfo;
|
private _npm?: NpmInfo;
|
||||||
get npm() {
|
get npm() {
|
||||||
return this._npm;
|
return this._npm;
|
||||||
@ -125,23 +89,27 @@ export class ComponentMeta {
|
|||||||
this.parseMetadata(metadata);
|
this.parseMetadata(metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setNpm(info: NpmInfo) {
|
||||||
|
if (!this._npm) {
|
||||||
|
this._npm = info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private parseMetadata(metadta: ComponentMetadata) {
|
private parseMetadata(metadta: ComponentMetadata) {
|
||||||
const { componentName, uri, npm } = metadta;
|
const { componentName, npm } = metadta;
|
||||||
this._npm = npm;
|
this._npm = npm;
|
||||||
this._uri = uri || (npm ? npmToURI(npm) : componentName);
|
|
||||||
this._componentName = componentName;
|
this._componentName = componentName;
|
||||||
|
|
||||||
metadta.uri = this._uri;
|
|
||||||
// 额外转换逻辑
|
// 额外转换逻辑
|
||||||
this._transformedMetadata = this.transformMetadata(metadta);
|
this._transformedMetadata = this.transformMetadata(metadta);
|
||||||
|
|
||||||
const title = this._transformedMetadata.title;
|
const title = this._transformedMetadata.title;
|
||||||
if (title && typeof title === 'string') {
|
if (title) {
|
||||||
this._title = {
|
this._title = typeof title === 'string' ? {
|
||||||
type: 'i18n',
|
type: 'i18n',
|
||||||
'en-US': this.componentName,
|
'en-US': this.componentName,
|
||||||
'zh-CN': title,
|
'zh-CN': title,
|
||||||
};
|
} : title;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { configure = {} } = this._transformedMetadata;
|
const { configure = {} } = this._transformedMetadata;
|
||||||
@ -181,12 +149,14 @@ export class ComponentMeta {
|
|||||||
|
|
||||||
@computed get availableActions() {
|
@computed get availableActions() {
|
||||||
let { disableBehaviors, actions } = this._transformedMetadata?.configure.component || {};
|
let { disableBehaviors, actions } = this._transformedMetadata?.configure.component || {};
|
||||||
|
const disabled = ensureAList(disableBehaviors) || (this.isRootComponent() ? ['copy', 'remove'] : null);
|
||||||
actions = builtinComponentActions.concat(this.designer.getGlobalComponentActions() || [], actions || []);
|
actions = builtinComponentActions.concat(this.designer.getGlobalComponentActions() || [], actions || []);
|
||||||
if (!disableBehaviors && this.isRootComponent()) {
|
|
||||||
disableBehaviors = ['copy', 'remove'];
|
if (disabled) {
|
||||||
|
if (disabled.includes('*')) {
|
||||||
|
return actions.filter((action) => action.condition === 'always');
|
||||||
}
|
}
|
||||||
if (disableBehaviors) {
|
return actions.filter((action) => disabled.indexOf(action.name) < 0);
|
||||||
return actions.filter(action => disableBehaviors!.indexOf(action.name) < 0);
|
|
||||||
}
|
}
|
||||||
return actions;
|
return actions;
|
||||||
}
|
}
|
||||||
@ -216,6 +186,10 @@ export class ComponentMeta {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isComponentMeta(obj: any): obj is ComponentMeta {
|
||||||
|
return obj && obj.isComponentMeta;
|
||||||
|
}
|
||||||
|
|
||||||
function preprocessMetadata(metadata: ComponentMetadata): TransformedComponentMetadata {
|
function preprocessMetadata(metadata: ComponentMetadata): TransformedComponentMetadata {
|
||||||
if (metadata.configure) {
|
if (metadata.configure) {
|
||||||
if (Array.isArray(metadata.configure)) {
|
if (Array.isArray(metadata.configure)) {
|
||||||
@ -235,7 +209,7 @@ function preprocessMetadata(metadata: ComponentMetadata): TransformedComponentMe
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
registerMetadataTransducer(metadata => {
|
registerMetadataTransducer((metadata) => {
|
||||||
const { configure, componentName } = metadata;
|
const { configure, componentName } = metadata;
|
||||||
const { component = {} } = configure;
|
const { component = {} } = configure;
|
||||||
if (!component.nestingRule) {
|
if (!component.nestingRule) {
|
||||||
@ -280,7 +254,7 @@ const builtinComponentActions: ComponentAction[] = [
|
|||||||
name: 'remove',
|
name: 'remove',
|
||||||
content: {
|
content: {
|
||||||
icon: IconRemove,
|
icon: IconRemove,
|
||||||
description: intl('remove'),
|
title: intl('remove'),
|
||||||
action(node: Node) {
|
action(node: Node) {
|
||||||
node.remove();
|
node.remove();
|
||||||
},
|
},
|
||||||
@ -291,7 +265,7 @@ const builtinComponentActions: ComponentAction[] = [
|
|||||||
name: 'copy',
|
name: 'copy',
|
||||||
content: {
|
content: {
|
||||||
icon: IconClone,
|
icon: IconClone,
|
||||||
description: intl('copy'),
|
title: intl('copy'),
|
||||||
action(node: Node) {
|
action(node: Node) {
|
||||||
// node.remove();
|
// node.remove();
|
||||||
},
|
},
|
||||||
@ -299,3 +273,13 @@ const builtinComponentActions: ComponentAction[] = [
|
|||||||
important: true,
|
important: true,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export function removeBuiltinComponentAction(name: string) {
|
||||||
|
const i = builtinComponentActions.findIndex(action => action.name === name);
|
||||||
|
if (i > -1) {
|
||||||
|
builtinComponentActions.splice(i, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export function addBuiltinComponentAction(action: ComponentAction) {
|
||||||
|
builtinComponentActions.push(action);
|
||||||
|
}
|
||||||
|
|||||||
@ -306,7 +306,10 @@ export class Designer {
|
|||||||
private _lostComponentMetasMap = new Map<string, ComponentMeta>();
|
private _lostComponentMetasMap = new Map<string, ComponentMeta>();
|
||||||
|
|
||||||
private buildComponentMetasMap(metas: ComponentMetadata[]) {
|
private buildComponentMetasMap(metas: ComponentMetadata[]) {
|
||||||
metas.forEach((data) => {
|
metas.forEach((data) => this.createComponentMeta(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
createComponentMeta(data: ComponentMetadata): ComponentMeta {
|
||||||
const key = data.componentName;
|
const key = data.componentName;
|
||||||
let meta = this._componentMetasMap.get(key);
|
let meta = this._componentMetasMap.get(key);
|
||||||
if (meta) {
|
if (meta) {
|
||||||
@ -323,7 +326,7 @@ export class Designer {
|
|||||||
|
|
||||||
this._componentMetasMap.set(key, meta);
|
this._componentMetasMap.set(key, meta);
|
||||||
}
|
}
|
||||||
});
|
return meta;
|
||||||
}
|
}
|
||||||
|
|
||||||
getGlobalComponentActions(): ComponentAction[] | null {
|
getGlobalComponentActions(): ComponentAction[] | null {
|
||||||
|
|||||||
@ -7,8 +7,18 @@ export type RegisteredSetter = {
|
|||||||
component: CustomView;
|
component: CustomView;
|
||||||
defaultProps?: object;
|
defaultProps?: object;
|
||||||
title?: TitleContent;
|
title?: TitleContent;
|
||||||
|
/**
|
||||||
|
* for MixedSetter to check this setter if available
|
||||||
|
*/
|
||||||
|
condition?: (field: any) => boolean;
|
||||||
|
/**
|
||||||
|
* for MixedSetter to manual change to this setter
|
||||||
|
*/
|
||||||
|
initialValue?: any | ((field: any) => any);
|
||||||
};
|
};
|
||||||
const settersMap = new Map<string, RegisteredSetter>();
|
const settersMap = new Map<string, RegisteredSetter & {
|
||||||
|
type: string;
|
||||||
|
}>();
|
||||||
export function registerSetter(
|
export function registerSetter(
|
||||||
typeOrMaps: string | { [key: string]: CustomView | RegisteredSetter },
|
typeOrMaps: string | { [key: string]: CustomView | RegisteredSetter },
|
||||||
setter?: CustomView | RegisteredSetter,
|
setter?: CustomView | RegisteredSetter,
|
||||||
@ -25,15 +35,19 @@ export function registerSetter(
|
|||||||
if (isCustomView(setter)) {
|
if (isCustomView(setter)) {
|
||||||
setter = {
|
setter = {
|
||||||
component: setter,
|
component: setter,
|
||||||
|
// todo: intl
|
||||||
title: (setter as any).displayName || (setter as any).name || 'CustomSetter',
|
title: (setter as any).displayName || (setter as any).name || 'CustomSetter',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
settersMap.set(typeOrMaps, setter);
|
settersMap.set(typeOrMaps, { type: typeOrMaps, ...setter });
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getSetter(type: string): RegisteredSetter | null {
|
export function getSetter(type: string): RegisteredSetter | null {
|
||||||
return settersMap.get(type) || null;
|
return settersMap.get(type) || null;
|
||||||
}
|
}
|
||||||
|
export function getSettersMap() {
|
||||||
|
return settersMap;
|
||||||
|
}
|
||||||
|
|
||||||
export function createSetterContent(setter: any, props: object): ReactNode {
|
export function createSetterContent(setter: any, props: object): ReactNode {
|
||||||
if (typeof setter === 'string') {
|
if (typeof setter === 'string') {
|
||||||
|
|||||||
@ -1,10 +1,29 @@
|
|||||||
import { TransformedComponentMetadata } from '../types';
|
import { TransformedComponentMetadata } from '../types';
|
||||||
|
|
||||||
export type MetadataTransducer = (prev: TransformedComponentMetadata) => TransformedComponentMetadata;
|
export interface MetadataTransducer {
|
||||||
|
(prev: TransformedComponentMetadata): TransformedComponentMetadata;
|
||||||
|
/**
|
||||||
|
* 0 - 9 system
|
||||||
|
* 10 - 99 builtin-plugin
|
||||||
|
* 100 - app & plugin
|
||||||
|
*/
|
||||||
|
level?: number;
|
||||||
|
/**
|
||||||
|
* use to replace TODO
|
||||||
|
*/
|
||||||
|
id?: string;
|
||||||
|
}
|
||||||
const metadataTransducers: MetadataTransducer[] = [];
|
const metadataTransducers: MetadataTransducer[] = [];
|
||||||
|
|
||||||
export function registerMetadataTransducer(transducer: MetadataTransducer) {
|
export function registerMetadataTransducer(transducer: MetadataTransducer, level: number = 100, id?: string) {
|
||||||
|
transducer.level = level;
|
||||||
|
transducer.id = id;
|
||||||
|
const i = metadataTransducers.findIndex(item => item.level != null && item.level > level);
|
||||||
|
if (i < 0) {
|
||||||
metadataTransducers.push(transducer);
|
metadataTransducers.push(transducer);
|
||||||
|
} else {
|
||||||
|
metadataTransducers.splice(i, 0, transducer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getRegisteredMetadataTransducers(): MetadataTransducer[] {
|
export function getRegisteredMetadataTransducers(): MetadataTransducer[] {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { TitleContent } from './title';
|
import { TitleContent } from './title';
|
||||||
import { SetterType } from './setter-config';
|
import { SetterType, DynamicSetter } from './setter-config';
|
||||||
|
|
||||||
|
|
||||||
export interface FieldExtraProps {
|
export interface FieldExtraProps {
|
||||||
@ -18,6 +18,14 @@ export interface FieldExtraProps {
|
|||||||
* @default undefined
|
* @default undefined
|
||||||
*/
|
*/
|
||||||
condition?: (field: any) => boolean;
|
condition?: (field: any) => boolean;
|
||||||
|
/**
|
||||||
|
* autorun when something change
|
||||||
|
*/
|
||||||
|
autorun?: (field: any) => void;
|
||||||
|
/**
|
||||||
|
* is this field is a virtual field that not save to schema
|
||||||
|
*/
|
||||||
|
virtual?: (field: any) => boolean;
|
||||||
/**
|
/**
|
||||||
* default collapsed when display accordion
|
* default collapsed when display accordion
|
||||||
*/
|
*/
|
||||||
@ -46,7 +54,7 @@ export interface FieldConfig extends FieldExtraProps {
|
|||||||
/**
|
/**
|
||||||
* the field body contains when .type = 'field'
|
* the field body contains when .type = 'field'
|
||||||
*/
|
*/
|
||||||
setter?: SetterType;
|
setter?: SetterType | DynamicSetter;
|
||||||
/**
|
/**
|
||||||
* the setting items which group body contains when .type = 'group'
|
* the setting items which group body contains when .type = 'group'
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -1,12 +1,13 @@
|
|||||||
import { ReactNode } from 'react';
|
import { ReactNode, ComponentType, ReactElement } from 'react';
|
||||||
import { IconType } from './icon';
|
import { IconType } from './icon';
|
||||||
import { TipContent } from './tip';
|
import { TipContent } from './tip';
|
||||||
import { TitleContent } from './title';
|
import { TitleContent } from './title';
|
||||||
import { PropConfig } from './prop-config';
|
import { PropConfig } from './prop-config';
|
||||||
import { NpmInfo } from './npm';
|
import { NpmInfo } from './npm';
|
||||||
import { FieldConfig } from './field-config';
|
import { FieldConfig } from './field-config';
|
||||||
|
import { NodeSchema } from './schema';
|
||||||
|
|
||||||
export type NestingFilter = (which: any, my: any) => boolean;
|
export type NestingFilter = (testNode: any, currentNode: any) => boolean;
|
||||||
export interface NestingRule {
|
export interface NestingRule {
|
||||||
// 子级白名单
|
// 子级白名单
|
||||||
childWhitelist?: string[] | string | RegExp | NestingFilter;
|
childWhitelist?: string[] | string | RegExp | NestingFilter;
|
||||||
@ -26,12 +27,46 @@ export interface ComponentConfigure {
|
|||||||
isNullNode?: boolean;
|
isNullNode?: boolean;
|
||||||
descriptor?: string;
|
descriptor?: string;
|
||||||
nestingRule?: NestingRule;
|
nestingRule?: NestingRule;
|
||||||
|
|
||||||
rectSelector?: string;
|
rectSelector?: string;
|
||||||
// copy,move,delete
|
// copy,move,delete | *
|
||||||
disableBehaviors?: string[];
|
disableBehaviors?: string[] | string;
|
||||||
actions?: ComponentAction[];
|
actions?: ComponentAction[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Snippet {
|
||||||
|
screenshot: string;
|
||||||
|
label: string;
|
||||||
|
schema: NodeSchema;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Experimental {
|
||||||
|
context?: { [contextInfoName: string]: any };
|
||||||
|
snippets?: Snippet[];
|
||||||
|
view?: ComponentType<any>;
|
||||||
|
transducers?: any; // ? should support
|
||||||
|
callbacks?: Callbacks;
|
||||||
|
|
||||||
|
// 样式 及 位置,handle上必须有明确的标识以便事件路由判断,或者主动设置事件独占模式
|
||||||
|
// NWSE 是交给引擎计算放置位置,ReactElement 必须自己控制初始位置
|
||||||
|
getResizingHandlers?: (
|
||||||
|
currentNode: any,
|
||||||
|
) =>
|
||||||
|
| Array<{
|
||||||
|
type: 'N' | 'W' | 'S' | 'E' | 'NW' | 'NE' | 'SE' | 'SW';
|
||||||
|
content?: ReactElement;
|
||||||
|
propTarget?: string;
|
||||||
|
appearOn?: 'mouse-enter' | 'mouse-hover' | 'selected' | 'always';
|
||||||
|
}>
|
||||||
|
| ReactElement[];
|
||||||
|
// hover时 控制柄高亮
|
||||||
|
// mousedown 时请求独占
|
||||||
|
// dragstart 请求 通用 resizing 控制
|
||||||
|
// 请求 hud 显示
|
||||||
|
// drag 时 计算 并 设置效果
|
||||||
|
// 更新控制柄位置
|
||||||
|
}
|
||||||
|
|
||||||
export interface Configure {
|
export interface Configure {
|
||||||
props?: FieldConfig[];
|
props?: FieldConfig[];
|
||||||
styles?: object;
|
styles?: object;
|
||||||
@ -43,9 +78,9 @@ export interface ActionContentObject {
|
|||||||
// 图标
|
// 图标
|
||||||
icon?: IconType;
|
icon?: IconType;
|
||||||
// 描述
|
// 描述
|
||||||
description?: TipContent;
|
title?: TipContent;
|
||||||
// 执行动作
|
// 执行动作
|
||||||
action?: (node: any) => void;
|
action?: (currentNode: any) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ComponentAction {
|
export interface ComponentAction {
|
||||||
@ -55,8 +90,8 @@ export interface ComponentAction {
|
|||||||
content: string | ReactNode | ActionContentObject;
|
content: string | ReactNode | ActionContentObject;
|
||||||
// 子集
|
// 子集
|
||||||
items?: ComponentAction[];
|
items?: ComponentAction[];
|
||||||
// 不显示
|
// 显示与否,always: 无法禁用
|
||||||
condition?: boolean | ((node: any) => boolean);
|
condition?: boolean | ((currentNode: any) => boolean) | 'always';
|
||||||
// 显示在工具条上
|
// 显示在工具条上
|
||||||
important?: boolean;
|
important?: boolean;
|
||||||
}
|
}
|
||||||
@ -87,8 +122,52 @@ export interface ComponentMetadata {
|
|||||||
npm?: NpmInfo;
|
npm?: NpmInfo;
|
||||||
props?: PropConfig[];
|
props?: PropConfig[];
|
||||||
configure?: FieldConfig[] | Configure;
|
configure?: FieldConfig[] | Configure;
|
||||||
|
experimental?: Experimental;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TransformedComponentMetadata extends ComponentMetadata {
|
export interface TransformedComponentMetadata extends ComponentMetadata {
|
||||||
configure: Configure & { combined?: FieldConfig[] };
|
configure: Configure & { combined?: FieldConfig[] };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handleResizing
|
||||||
|
|
||||||
|
// hooks & events
|
||||||
|
export interface Callbacks {
|
||||||
|
// hooks
|
||||||
|
onMouseDownHook?: (e: MouseEvent, currentNode: any) => any;
|
||||||
|
onDblClickHook?: (e: MouseEvent, currentNode: any) => any;
|
||||||
|
onClickHook?: (e: MouseEvent, currentNode: any) => any;
|
||||||
|
onLocateHook?: (e: any, currentNode: any) => any;
|
||||||
|
onAcceptHook?: (currentNode: any, locationData: any) => any;
|
||||||
|
onMoveHook?: (currentNode: any) => boolean; // thinkof 限制性拖拽
|
||||||
|
onChildMoveHook?: (childNode: any, currentNode: any) => boolean;
|
||||||
|
|
||||||
|
// events
|
||||||
|
onNodeRemove?: (removedNode: any, currentNode: any) => void;
|
||||||
|
onNodeAdd?: (addedNode: any, currentNode: any) => void;
|
||||||
|
onSubtreeModified?: (currentNode: any, options: any) => void;
|
||||||
|
onResize?: (
|
||||||
|
e: MouseEvent & {
|
||||||
|
trigger: string;
|
||||||
|
deltaX?: number;
|
||||||
|
deltaY?: number;
|
||||||
|
},
|
||||||
|
currentNode: any,
|
||||||
|
) => void;
|
||||||
|
onResizeStart?: (
|
||||||
|
e: MouseEvent & {
|
||||||
|
trigger: string;
|
||||||
|
deltaX?: number;
|
||||||
|
deltaY?: number;
|
||||||
|
},
|
||||||
|
currentNode: any,
|
||||||
|
) => void;
|
||||||
|
onResizeEnd?: (
|
||||||
|
e: MouseEvent & {
|
||||||
|
trigger: string;
|
||||||
|
deltaX?: number;
|
||||||
|
deltaY?: number;
|
||||||
|
},
|
||||||
|
currentNode: any,
|
||||||
|
) => void;
|
||||||
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
export interface NpmInfo {
|
export interface NpmInfo {
|
||||||
componentName?: string;
|
componentName?: string;
|
||||||
package: string;
|
package: string;
|
||||||
version: string;
|
version?: string;
|
||||||
destructuring?: boolean;
|
destructuring?: boolean;
|
||||||
exportName?: string;
|
exportName?: string;
|
||||||
subName?: string;
|
subName?: string;
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
import { isReactComponent } from '../utils';
|
import { isReactComponent } from '../utils';
|
||||||
import { ComponentType, ReactElement, isValidElement } from 'react';
|
import { ComponentType, ReactElement, isValidElement } from 'react';
|
||||||
|
import { TitleContent } from './title';
|
||||||
|
|
||||||
export type CustomView = ReactElement | ComponentType<any>;
|
export type CustomView = ReactElement | ComponentType<any>;
|
||||||
|
|
||||||
export type DynamicProps = (field: any) => object;
|
export type DynamicProps = (field: any) => object;
|
||||||
|
export type DynamicSetter = (field: any) => string | SetterConfig | CustomView;
|
||||||
|
|
||||||
export interface SetterConfig {
|
export interface SetterConfig {
|
||||||
/**
|
/**
|
||||||
@ -17,12 +19,16 @@ export interface SetterConfig {
|
|||||||
children?: any;
|
children?: any;
|
||||||
isRequired?: boolean;
|
isRequired?: boolean;
|
||||||
initialValue?: any | ((field: any) => any);
|
initialValue?: any | ((field: any) => any);
|
||||||
|
/* for MixedSetter */
|
||||||
|
title?: TitleContent;
|
||||||
|
// for MixedSetter check this is available
|
||||||
|
condition?: (field: any) => boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* if *string* passed must be a registered Setter Name, future support blockSchema
|
* if *string* passed must be a registered Setter Name, future support blockSchema
|
||||||
*/
|
*/
|
||||||
export type SetterType = SetterConfig | string | CustomView;
|
export type SetterType = SetterConfig | SetterConfig[] | string | CustomView;
|
||||||
|
|
||||||
|
|
||||||
export function isSetterConfig(obj: any): obj is SetterConfig {
|
export function isSetterConfig(obj: any): obj is SetterConfig {
|
||||||
@ -32,3 +38,7 @@ export function isSetterConfig(obj: any): obj is SetterConfig {
|
|||||||
export function isCustomView(obj: any): obj is CustomView {
|
export function isCustomView(obj: any): obj is CustomView {
|
||||||
return obj && (isValidElement(obj) || isReactComponent(obj));
|
return obj && (isValidElement(obj) || isReactComponent(obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isDynamicSetter(obj: any): obj is DynamicSetter {
|
||||||
|
return obj && typeof obj === 'function' && !obj.displayName;
|
||||||
|
}
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import { IconType } from './icon';
|
|||||||
export interface TitleConfig {
|
export interface TitleConfig {
|
||||||
label?: I18nData | ReactNode;
|
label?: I18nData | ReactNode;
|
||||||
tip?: TipContent;
|
tip?: TipContent;
|
||||||
|
docUrl?: string;
|
||||||
icon?: IconType;
|
icon?: IconType;
|
||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,7 +15,9 @@ export interface JSExpression {
|
|||||||
|
|
||||||
export interface JSSlot {
|
export interface JSSlot {
|
||||||
type: 'JSSlot';
|
type: 'JSSlot';
|
||||||
value: NodeSchema;
|
// 函数的入参
|
||||||
|
params?: string[];
|
||||||
|
value: NodeSchema[];
|
||||||
}
|
}
|
||||||
|
|
||||||
// JSON 基本类型
|
// JSON 基本类型
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
export interface AssetItem {
|
export interface AssetItem {
|
||||||
type: AssetType;
|
type: AssetType;
|
||||||
content?: string | null;
|
content?: string | null;
|
||||||
|
device?: string;
|
||||||
level?: AssetLevel;
|
level?: AssetLevel;
|
||||||
id?: string;
|
id?: string;
|
||||||
}
|
}
|
||||||
@ -68,6 +69,14 @@ export function assetBundle(assets?: Asset | AssetList | null, level?: AssetLeve
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
urls: "view.js,view2 <device selector>, view3 <device selector>",
|
||||||
|
urls: [
|
||||||
|
"view.js",
|
||||||
|
"view.js *",
|
||||||
|
"view1.js mobile|pc",
|
||||||
|
"view2.js <device selector>"
|
||||||
|
]*/
|
||||||
export function assetItem(type: AssetType, content?: string | null, level?: AssetLevel, id?: string): AssetItem | null {
|
export function assetItem(type: AssetType, content?: string | null, level?: AssetLevel, id?: string): AssetItem | null {
|
||||||
if (!content) {
|
if (!content) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@ -20,50 +20,36 @@ export default class DesignerPlugin extends PureComponent<PluginProps, DesignerP
|
|||||||
library: null,
|
library: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
private _lifeState = 0;
|
private _mounted = true;
|
||||||
|
|
||||||
constructor(props: any) {
|
constructor(props: any) {
|
||||||
super(props);
|
super(props);
|
||||||
|
this.setupAssets();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async setupAssets() {
|
||||||
const { editor } = this.props;
|
const { editor } = this.props;
|
||||||
const assets = editor.get('assets');
|
const assets = await editor.onceGot('assets');
|
||||||
|
if (!this._mounted) {
|
||||||
if (assets) {
|
|
||||||
this.setupAssets(assets);
|
|
||||||
} else {
|
|
||||||
editor.once('assets.loaded', this.setupAssets);
|
|
||||||
}
|
|
||||||
this._lifeState = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
setupAssets = (assets: any) => {
|
|
||||||
if (this._lifeState < 0) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { components, packages } = assets;
|
const { components, packages } = assets;
|
||||||
const state = {
|
const state = {
|
||||||
componentMetadatas: components ? Object.values(components) : [],
|
componentMetadatas: components ? components.filter(item => item.type === 'ComponentMetadata') : [],
|
||||||
library: packages ? Object.values(packages) : [],
|
library: packages ? Object.values(packages) : [],
|
||||||
};
|
};
|
||||||
if (this._lifeState === 0) {
|
|
||||||
this.state = state;
|
|
||||||
} else {
|
|
||||||
this.setState(state);
|
this.setState(state);
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
this._lifeState = -1;
|
this._mounted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
handleDesignerMount = (designer: Designer): void => {
|
private handleDesignerMount = (designer: Designer): void => {
|
||||||
const { editor } = this.props;
|
const { editor } = this.props;
|
||||||
editor.set(Designer, designer);
|
editor.set(Designer, designer);
|
||||||
editor.emit('designer.ready', designer);
|
editor.emit('designer.ready', designer);
|
||||||
const schema = editor.get('schema');
|
editor.onGot('schema', (schema) => {
|
||||||
if (schema) {
|
|
||||||
designer.project.open(schema);
|
|
||||||
}
|
|
||||||
editor.on('schema.loaded', (schema) => {
|
|
||||||
designer.project.open(schema);
|
designer.project.open(schema);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
import { uniqueId } from '@ali/lowcode-globals';
|
import { uniqueId, DynamicSetter, isDynamicSetter } from '@ali/lowcode-globals';
|
||||||
import { ComponentMeta, Node, Designer, Selection } from '@ali/lowcode-designer';
|
import { ComponentMeta, Node, Designer, Selection } from '@ali/lowcode-designer';
|
||||||
import { TitleContent, FieldExtraProps, SetterType, CustomView, FieldConfig, isCustomView } from '@ali/lowcode-globals';
|
import { TitleContent, FieldExtraProps, SetterType, CustomView, FieldConfig, isCustomView } from '@ali/lowcode-globals';
|
||||||
import { getTreeMaster } from '@ali/lowcode-plugin-outline-pane';
|
import { getTreeMaster } from '@ali/lowcode-plugin-outline-pane';
|
||||||
@ -73,7 +73,16 @@ export class SettingField implements SettingTarget {
|
|||||||
readonly title: TitleContent;
|
readonly title: TitleContent;
|
||||||
readonly editor: any;
|
readonly editor: any;
|
||||||
readonly extraProps: FieldExtraProps;
|
readonly extraProps: FieldExtraProps;
|
||||||
readonly setter?: SetterType;
|
private _setter?: SetterType | DynamicSetter;
|
||||||
|
get setter(): SetterType | null {
|
||||||
|
if (!this._setter) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (isDynamicSetter(this._setter)) {
|
||||||
|
return this._setter(this);
|
||||||
|
}
|
||||||
|
return this._setter;
|
||||||
|
}
|
||||||
readonly isSame: boolean;
|
readonly isSame: boolean;
|
||||||
readonly isMulti: boolean;
|
readonly isMulti: boolean;
|
||||||
readonly isOne: boolean;
|
readonly isOne: boolean;
|
||||||
@ -107,7 +116,7 @@ export class SettingField implements SettingTarget {
|
|||||||
this._name = name;
|
this._name = name;
|
||||||
// make this reactive
|
// make this reactive
|
||||||
this.title = title || (typeof name === 'number' ? `项目 ${name}` : name);
|
this.title = title || (typeof name === 'number' ? `项目 ${name}` : name);
|
||||||
this.setter = setter;
|
this._setter = setter;
|
||||||
this.extraProps = {
|
this.extraProps = {
|
||||||
...rest,
|
...rest,
|
||||||
...extraProps,
|
...extraProps,
|
||||||
|
|||||||
241
packages/plugin-settings-pane/src/setters/mixed-setter/index.tsx
Normal file
241
packages/plugin-settings-pane/src/setters/mixed-setter/index.tsx
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
import React, { PureComponent, Component } from 'react';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { Dropdown, Button, Menu, Icon } from '@alifd/next';
|
||||||
|
import { getSetter, getSettersMap, SetterConfig, computed, obx, CustomView, DynamicProps, DynamicSetter, TitleContent, isSetterConfig, Title, createSetterContent } from '@ali/lowcode-globals';
|
||||||
|
import { SettingField } from 'plugin-settings-pane/src/main';
|
||||||
|
|
||||||
|
import './index.scss';
|
||||||
|
|
||||||
|
export interface SetterItem {
|
||||||
|
name: string;
|
||||||
|
title: TitleContent;
|
||||||
|
setter: string | DynamicSetter | CustomView;
|
||||||
|
props?: object | DynamicProps;
|
||||||
|
condition?: (field: SettingField) => boolean;
|
||||||
|
initialValue?: (field: SettingField) => any;
|
||||||
|
}
|
||||||
|
|
||||||
|
function nomalizeSetters(setters?: Array<string | SetterConfig | CustomView | DynamicSetter>): SetterItem[] {
|
||||||
|
if (!setters) {
|
||||||
|
const normalized: SetterItem[] = [];
|
||||||
|
getSettersMap().forEach((setter, name) => {
|
||||||
|
if (name === 'MixedSetter') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
normalized.push({
|
||||||
|
name,
|
||||||
|
title: setter.title || name,
|
||||||
|
setter: name,
|
||||||
|
condition: setter.condition,
|
||||||
|
initialValue: setter.initialValue,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
const names: string[] = [];
|
||||||
|
function generateName(n: string) {
|
||||||
|
let idx = 1;
|
||||||
|
let got = n;
|
||||||
|
while (names.indexOf(got) > -1) {
|
||||||
|
got = `${n}:${idx++}`;
|
||||||
|
}
|
||||||
|
names.push(got);
|
||||||
|
return got;
|
||||||
|
}
|
||||||
|
return setters.map(setter => {
|
||||||
|
const config: any = {
|
||||||
|
setter,
|
||||||
|
};
|
||||||
|
if (isSetterConfig(setter)) {
|
||||||
|
config.setter = setter.componentName;
|
||||||
|
config.props = setter.props;
|
||||||
|
config.condition = setter.condition;
|
||||||
|
config.initialValue = setter.initialValue;
|
||||||
|
config.title = setter.title;
|
||||||
|
}
|
||||||
|
if (typeof config.setter === 'string') {
|
||||||
|
config.name = config.setter;
|
||||||
|
names.push(config.name);
|
||||||
|
const info = getSetter(config.setter);
|
||||||
|
if (!config.title) {
|
||||||
|
config.title = info?.title || config.setter;
|
||||||
|
}
|
||||||
|
if (!config.condition) {
|
||||||
|
config.condition = info?.condition;
|
||||||
|
}
|
||||||
|
if (!config.initialValue) {
|
||||||
|
config.initialValue = info?.initialValue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
config.name = generateName((config.setter as any).displayName || (config.setter as any).name || 'CustomSetter');
|
||||||
|
if (!config.title) {
|
||||||
|
config.title = config.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class MixedSetter extends Component<{
|
||||||
|
field: SettingField;
|
||||||
|
setters?: Array<string | SetterConfig | CustomView | DynamicSetter>;
|
||||||
|
onSetterChange: (field: SettingField, name: string) => void;
|
||||||
|
}> {
|
||||||
|
private setters = nomalizeSetters(this.props.setters);
|
||||||
|
@obx.ref private used?: string;
|
||||||
|
@computed private getCurrentSetter() {
|
||||||
|
const { field } = this.props;
|
||||||
|
if (this.used != null) {
|
||||||
|
const selected = this.used;
|
||||||
|
if (selected.condition) {
|
||||||
|
if (selected.condition(field)) {
|
||||||
|
return selected;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return selected;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.setters.find(item => {
|
||||||
|
if (!item.condition) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return item.condition(field);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private checkIsBlockField() {
|
||||||
|
if (this.shell) {
|
||||||
|
const setter = this.shell.lastElementChild!.firstElementChild;
|
||||||
|
if (setter && setter.classList.contains('lc-block-setter')) {
|
||||||
|
this.shell.classList.add('lc-block-setter');
|
||||||
|
} else {
|
||||||
|
this.shell.classList.remove('lc-block-field');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
componentDidUpdate() {
|
||||||
|
this.checkIsBlockField();
|
||||||
|
}
|
||||||
|
componentDidMount() {
|
||||||
|
this.checkIsBlockField();
|
||||||
|
}
|
||||||
|
|
||||||
|
private useSetter: (id: string) => {
|
||||||
|
const { field, onChange } = this.props;
|
||||||
|
const newValue = setter.initialValue?.(field);
|
||||||
|
this.used = setter;
|
||||||
|
onChange && onChange(newValue);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
style = {},
|
||||||
|
className,
|
||||||
|
types = [],
|
||||||
|
defaultType,
|
||||||
|
...restProps
|
||||||
|
} = this.props;
|
||||||
|
this.typeMap = {};
|
||||||
|
let realTypes: any[] = [];
|
||||||
|
types.forEach( (el: { name: any; props: any; }) => {
|
||||||
|
const { name, props } = el;
|
||||||
|
const Setter = getSetter(name);
|
||||||
|
if (Setter) {
|
||||||
|
this.typeMap[name] = {
|
||||||
|
label: name,
|
||||||
|
component: Setter.component,
|
||||||
|
props,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
realTypes.push(name);
|
||||||
|
})
|
||||||
|
let moreBtnNode = null;
|
||||||
|
//如果只有2种,且有变量表达式,则直接展示变量按钮
|
||||||
|
if (realTypes.length > 1) {
|
||||||
|
let isTwoType = !!(realTypes.length === 2 && ~realTypes.indexOf('ExpressionSetter'));
|
||||||
|
let btnProps = {
|
||||||
|
size: 'small',
|
||||||
|
text: true,
|
||||||
|
style: {
|
||||||
|
position: 'absolute',
|
||||||
|
left: '100%',
|
||||||
|
top: 0,
|
||||||
|
bottom: 0,
|
||||||
|
margin: 'auto 0 auto 8px',
|
||||||
|
padding: 0,
|
||||||
|
width: 16,
|
||||||
|
height: 16,
|
||||||
|
lineHeight: '16px',
|
||||||
|
textAlign: 'center'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (isTwoType) {
|
||||||
|
btnProps.onClick = this.changeType.bind(this, realTypes.indexOf(this.state.type) ? realTypes[0] : realTypes[1]);
|
||||||
|
}
|
||||||
|
// 未匹配的 null 值,显示 NullValue 空值
|
||||||
|
// 未匹配的 其它 值,显示 InvalidValue 非法值
|
||||||
|
let triggerNode = (
|
||||||
|
<Button {...btnProps} size={isTwoType ? 'large' : 'small'}>
|
||||||
|
<Icon type={isTwoType ? 'edit' : 'ellipsis'} />
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
if (isTwoType) {
|
||||||
|
moreBtnNode = triggerNode;
|
||||||
|
} else {
|
||||||
|
let MenuItems: {} | null | undefined = [];
|
||||||
|
realTypes.map(type => {
|
||||||
|
if (this.typeMap[type]) {
|
||||||
|
MenuItems.push(<Menu.Item key={type}></Menu.Item>);
|
||||||
|
} else {
|
||||||
|
console.error(
|
||||||
|
this.i18n('typeError', {
|
||||||
|
type
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let MenuNode = (
|
||||||
|
<Menu
|
||||||
|
selectMode="single"
|
||||||
|
hasSelectedIcon={false}
|
||||||
|
selectedKeys={this.used}
|
||||||
|
onItemClick={this.useSetter}
|
||||||
|
>
|
||||||
|
{this.setters.map((setter) => {
|
||||||
|
return <Menu.Item key={setter.name}>
|
||||||
|
<Title title={setter.title} />
|
||||||
|
</Menu.Item>
|
||||||
|
})}
|
||||||
|
</Menu>
|
||||||
|
);
|
||||||
|
|
||||||
|
moreBtnNode = (
|
||||||
|
<Dropdown trigger={triggerNode} triggerType="click">
|
||||||
|
<Menu
|
||||||
|
selectMode="single"
|
||||||
|
hasSelectedIcon={false}
|
||||||
|
selectedKeys={this.used}
|
||||||
|
onItemClick={this.useSetter}
|
||||||
|
>
|
||||||
|
{this.setters.map((setter) => {
|
||||||
|
return <Menu.Item key={setter.name}>
|
||||||
|
<Title title={setter.title} />
|
||||||
|
</Menu.Item>
|
||||||
|
})}
|
||||||
|
</Menu>
|
||||||
|
</Dropdown>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let TargetNode = this.typeMap[this.state.type]?.component || 'div';
|
||||||
|
let targetProps = this.typeMap[this.state.type]?.props || {};
|
||||||
|
let tarStyle = { position: 'relative', ...style };
|
||||||
|
let classes = classNames(className, 'lowcode-setter-mixin');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={tarStyle} className={classes} >
|
||||||
|
{createSetterContent()}
|
||||||
|
{moreBtnNode}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -26,6 +26,10 @@ class SettingFieldView extends Component<{ field: SettingField }> {
|
|||||||
const { field } = this.props;
|
const { field } = this.props;
|
||||||
const { setter } = field;
|
const { setter } = field;
|
||||||
let setterProps: object | DynamicProps = {};
|
let setterProps: object | DynamicProps = {};
|
||||||
|
if (Array.isArray(setter)) {
|
||||||
|
this.setterType = 'MixedSetter';
|
||||||
|
// setterProps =
|
||||||
|
}
|
||||||
if (isSetterConfig(setter)) {
|
if (isSetterConfig(setter)) {
|
||||||
this.setterType = setter.componentName;
|
this.setterType = setter.componentName;
|
||||||
if (setter.props) {
|
if (setter.props) {
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import parseProps from './parse-props';
|
|||||||
import addonCombine from './addon-combine';
|
import addonCombine from './addon-combine';
|
||||||
|
|
||||||
// parseProps
|
// parseProps
|
||||||
registerMetadataTransducer(parseProps);
|
registerMetadataTransducer(parseProps, 10, 'parse-props');
|
||||||
|
|
||||||
// addon/platform custom
|
// addon/platform custom
|
||||||
registerMetadataTransducer(addonCombine);
|
registerMetadataTransducer(addonCombine, 11, 'combine-props');
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent, createElement as reactCreateElement } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import Debug from 'debug';
|
import Debug from 'debug';
|
||||||
import Div from '@ali/iceluna-comp-div';
|
import Div from '@ali/iceluna-comp-div';
|
||||||
@ -41,7 +41,6 @@ export default class BaseEngine extends PureComponent {
|
|||||||
messages: PropTypes.object,
|
messages: PropTypes.object,
|
||||||
__appHelper: PropTypes.object,
|
__appHelper: PropTypes.object,
|
||||||
__components: PropTypes.object,
|
__components: PropTypes.object,
|
||||||
__componentsMap: PropTypes.object,
|
|
||||||
__ctx: PropTypes.object,
|
__ctx: PropTypes.object,
|
||||||
__schema: PropTypes.object,
|
__schema: PropTypes.object,
|
||||||
};
|
};
|
||||||
@ -199,7 +198,7 @@ export default class BaseEngine extends PureComponent {
|
|||||||
// idx 若为循环渲染的循环Index
|
// idx 若为循环渲染的循环Index
|
||||||
__createVirtualDom = (schema, self, parentInfo, idx) => {
|
__createVirtualDom = (schema, self, parentInfo, idx) => {
|
||||||
if (!schema) return null;
|
if (!schema) return null;
|
||||||
const { __appHelper: appHelper, __components: components = {}, __componentsMap: componentsMap = {} } =
|
const { __appHelper: appHelper, __components: components = {} } =
|
||||||
this.props || {};
|
this.props || {};
|
||||||
const { engine } = this.context || {};
|
const { engine } = this.context || {};
|
||||||
if (isJSExpression(schema)) {
|
if (isJSExpression(schema)) {
|
||||||
@ -277,13 +276,12 @@ export default class BaseEngine extends PureComponent {
|
|||||||
__schema: schema,
|
__schema: schema,
|
||||||
__appHelper: appHelper,
|
__appHelper: appHelper,
|
||||||
__components: components,
|
__components: components,
|
||||||
__componentsMap: componentsMap,
|
|
||||||
}
|
}
|
||||||
: {};
|
: {};
|
||||||
if (engine && engine.props.designMode) {
|
if (engine && engine.props.designMode) {
|
||||||
otherProps.__designMode = engine.props.designMode;
|
otherProps.__designMode = engine.props.designMode;
|
||||||
}
|
}
|
||||||
const componentInfo = componentsMap[schema.componentName] || {};
|
const componentInfo = {};
|
||||||
const props = this.__parseProps(schema.props, self, '', {
|
const props = this.__parseProps(schema.props, self, '', {
|
||||||
schema,
|
schema,
|
||||||
Comp,
|
Comp,
|
||||||
@ -314,9 +312,12 @@ export default class BaseEngine extends PureComponent {
|
|||||||
} else if (typeof idx === 'number' && !props.key) {
|
} else if (typeof idx === 'number' && !props.key) {
|
||||||
props.key = idx;
|
props.key = idx;
|
||||||
}
|
}
|
||||||
const renderComp = (props) => (
|
const createElement = engine.props.customCreateElement || reactCreateElement;
|
||||||
<Comp {...props}>
|
const renderComp = (props) => {
|
||||||
{(!isFileSchema(schema) &&
|
return createElement(
|
||||||
|
Comp,
|
||||||
|
props,
|
||||||
|
(!isFileSchema(schema) &&
|
||||||
!!schema.children &&
|
!!schema.children &&
|
||||||
this.__createVirtualDom(
|
this.__createVirtualDom(
|
||||||
isJSExpression(schema.children) ? parseExpression(schema.children, self) : schema.children,
|
isJSExpression(schema.children) ? parseExpression(schema.children, self) : schema.children,
|
||||||
@ -326,9 +327,9 @@ export default class BaseEngine extends PureComponent {
|
|||||||
Comp,
|
Comp,
|
||||||
},
|
},
|
||||||
)) ||
|
)) ||
|
||||||
null}
|
null,
|
||||||
</Comp>
|
|
||||||
);
|
);
|
||||||
|
};
|
||||||
//设计模式下的特殊处理
|
//设计模式下的特殊处理
|
||||||
if (engine && [DESIGN_MODE.EXTEND, DESIGN_MODE.BORDER].includes(engine.props.designMode)) {
|
if (engine && [DESIGN_MODE.EXTEND, DESIGN_MODE.BORDER].includes(engine.props.designMode)) {
|
||||||
//对于overlay,dialog等组件为了使其在设计模式下显示,外层需要增加一个div容器
|
//对于overlay,dialog等组件为了使其在设计模式下显示,外层需要增加一个div容器
|
||||||
|
|||||||
@ -27,17 +27,16 @@ export default class Engine extends PureComponent {
|
|||||||
static propTypes = {
|
static propTypes = {
|
||||||
appHelper: PropTypes.object,
|
appHelper: PropTypes.object,
|
||||||
components: PropTypes.object,
|
components: PropTypes.object,
|
||||||
componentsMap: PropTypes.object,
|
|
||||||
designMode: PropTypes.string,
|
designMode: PropTypes.string,
|
||||||
suspended: PropTypes.bool,
|
suspended: PropTypes.bool,
|
||||||
schema: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
|
schema: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
|
||||||
onCompGetRef: PropTypes.func,
|
onCompGetRef: PropTypes.func,
|
||||||
onCompGetCtx: PropTypes.func,
|
onCompGetCtx: PropTypes.func,
|
||||||
|
customCreateElement: PropTypes.func,
|
||||||
};
|
};
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
appHelper: null,
|
appHelper: null,
|
||||||
components: {},
|
components: {},
|
||||||
componentsMap: {},
|
|
||||||
designMode: '',
|
designMode: '',
|
||||||
suspended: false,
|
suspended: false,
|
||||||
schema: {},
|
schema: {},
|
||||||
@ -87,7 +86,7 @@ export default class Engine extends PureComponent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { schema, designMode, appHelper, components, componentsMap } = this.props;
|
const { schema, designMode, appHelper, components } = this.props;
|
||||||
if (isEmpty(schema)) {
|
if (isEmpty(schema)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -103,7 +102,6 @@ export default class Engine extends PureComponent {
|
|||||||
value={{
|
value={{
|
||||||
appHelper,
|
appHelper,
|
||||||
components: allComponents,
|
components: allComponents,
|
||||||
componentsMap,
|
|
||||||
engine: this,
|
engine: this,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -112,7 +110,6 @@ export default class Engine extends PureComponent {
|
|||||||
ref={this.__getRef}
|
ref={this.__getRef}
|
||||||
__appHelper={appHelper}
|
__appHelper={appHelper}
|
||||||
__components={allComponents}
|
__components={allComponents}
|
||||||
__componentsMap={componentsMap}
|
|
||||||
__schema={schema}
|
__schema={schema}
|
||||||
__designMode={designMode}
|
__designMode={designMode}
|
||||||
{...this.props}
|
{...this.props}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import LowCodeRenderer from '@ali/lowcode-react-renderer';
|
import LowCodeRenderer from '@ali/lowcode-react-renderer';
|
||||||
import { ReactInstance, Fragment, Component } from 'react';
|
import { ReactInstance, Fragment, Component, createElement } from 'react';
|
||||||
import { observer } from '@recore/obx-react';
|
import { observer } from '@recore/obx-react';
|
||||||
import { SimulatorRenderer } from './renderer';
|
import { SimulatorRenderer } from './renderer';
|
||||||
import './renderer.less';
|
import './renderer.less';
|
||||||
@ -48,9 +48,11 @@ class Renderer extends Component<{ renderer: SimulatorRenderer }> {
|
|||||||
appHelper={renderer.context}
|
appHelper={renderer.context}
|
||||||
// context={renderer.context}
|
// context={renderer.context}
|
||||||
designMode={renderer.designMode}
|
designMode={renderer.designMode}
|
||||||
componentsMap={renderer.componentsMap}
|
|
||||||
suspended={renderer.suspended}
|
suspended={renderer.suspended}
|
||||||
self={renderer.scope}
|
self={renderer.scope}
|
||||||
|
customCreateElement={(Component, props, children) => {
|
||||||
|
return createElement(Component, props, children);
|
||||||
|
}}
|
||||||
onCompGetRef={(schema: any, ref: ReactInstance | null) => {
|
onCompGetRef={(schema: any, ref: ReactInstance | null) => {
|
||||||
renderer.mountInstance(schema.id, ref);
|
renderer.mountInstance(schema.id, ref);
|
||||||
}}
|
}}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import MixinSetter from './mixin-setter';
|
|||||||
import ColorSetter from './color-setter';
|
import ColorSetter from './color-setter';
|
||||||
import JsonSetter from './json-setter';
|
import JsonSetter from './json-setter';
|
||||||
import EventsSetter from './events-setter';
|
import EventsSetter from './events-setter';
|
||||||
import StyleSetter from './style-setter';
|
// import StyleSetter from './style-setter';
|
||||||
|
|
||||||
export const StringSetter = {
|
export const StringSetter = {
|
||||||
component: Input,
|
component: Input,
|
||||||
@ -29,7 +29,7 @@ export const DateYearSetter = DatePicker.YearPicker;
|
|||||||
export const DateMonthSetter = DatePicker.MonthPicker;
|
export const DateMonthSetter = DatePicker.MonthPicker;
|
||||||
export const DateRangeSetter = DatePicker.RangePicker;
|
export const DateRangeSetter = DatePicker.RangePicker;
|
||||||
|
|
||||||
export { ExpressionSetter, MixinSetter, EventsSetter, StyleSetter }
|
export { ExpressionSetter, MixinSetter, EventsSetter }
|
||||||
|
|
||||||
// todo:
|
// todo:
|
||||||
export const ClassNameSetter = () => {
|
export const ClassNameSetter = () => {
|
||||||
@ -50,7 +50,7 @@ const builtinSetters = {
|
|||||||
DateMonthSetter,
|
DateMonthSetter,
|
||||||
DateRangeSetter,
|
DateRangeSetter,
|
||||||
EventsSetter,
|
EventsSetter,
|
||||||
StyleSetter,
|
// StyleSetter,
|
||||||
ColorSetter,
|
ColorSetter,
|
||||||
JsonSetter,
|
JsonSetter,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -22,6 +22,8 @@ miniapp view.miniapp.xxx
|
|||||||
view.<device>.xxx
|
view.<device>.xxx
|
||||||
通配 view.xxx
|
通配 view.xxx
|
||||||
|
|
||||||
|
universal
|
||||||
|
|
||||||
规则 2
|
规则 2
|
||||||
urls: "view.js,view2 <device selector>, view3 <device selector>",
|
urls: "view.js,view2 <device selector>, view3 <device selector>",
|
||||||
urls: [
|
urls: [
|
||||||
@ -66,3 +68,15 @@ load simulator resources
|
|||||||
|
|
||||||
|
|
||||||
simulator 中加载资源,根据 componentsMap 构建组件查询字典,
|
simulator 中加载资源,根据 componentsMap 构建组件查询字典,
|
||||||
|
|
||||||
|
|
||||||
|
获取 view 相关的样式、脚本
|
||||||
|
获取 proto 相关的样式
|
||||||
|
在 simulator 中也加载一次
|
||||||
|
|
||||||
|
1. meta 信息构造
|
||||||
|
2. components 字典构造, proto.getView 或者 通过 npm 信息查询
|
||||||
|
3.
|
||||||
|
|
||||||
|
|
||||||
|
componentMeta 段描述的信息,如果包含 x-prototype-urls ,那么这个 meta 信息都可以丢掉
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"entry": {
|
"entry": {
|
||||||
"index": "src/demo.ts"
|
"index": "src/demo/index.ts"
|
||||||
},
|
},
|
||||||
"vendor": false,
|
"vendor": false,
|
||||||
"devServer": {
|
"devServer": {
|
||||||
|
|||||||
@ -13,6 +13,7 @@
|
|||||||
<script src="https://g.alicdn.com/mylib/moment/2.24.0/min/moment.min.js"></script>
|
<script src="https://g.alicdn.com/mylib/moment/2.24.0/min/moment.min.js"></script>
|
||||||
<link rel="stylesheet" href="https://alifd.alicdn.com/npm/@alifd/next/1.11.6/next.min.css" />
|
<link rel="stylesheet" href="https://alifd.alicdn.com/npm/@alifd/next/1.11.6/next.min.css" />
|
||||||
<script src="https://unpkg.alibaba-inc.com/@alifd/next@1.18.17/dist/next.min.js"></script>
|
<script src="https://unpkg.alibaba-inc.com/@alifd/next@1.18.17/dist/next.min.js"></script>
|
||||||
|
<script src="https://g.alicdn.com/vision/visualengine-utils/4.3.1/engine-utils.js"></script>
|
||||||
<!-- lowcode engine globals -->
|
<!-- lowcode engine globals -->
|
||||||
<link rel="stylesheet" href="https://dev.g.alicdn.com/ali-lowcode/ali-lowcode-engine/0.9.0/globals.css" />
|
<link rel="stylesheet" href="https://dev.g.alicdn.com/ali-lowcode/ali-lowcode-engine/0.9.0/globals.css" />
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
@ -365,197 +365,87 @@
|
|||||||
"version": "1.22.0"
|
"version": "1.22.0"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"components": [
|
"x-prototypes": [
|
||||||
{
|
{
|
||||||
"componentName": "AliVcDiv",
|
"urls": ["https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-div/1.0.1/proto.a264564.js"]
|
||||||
"npm": {
|
|
||||||
"package": "@ali/vc-div",
|
|
||||||
"library": "AliVcDiv",
|
|
||||||
"version": "1.0.1",
|
|
||||||
"destructuring": false
|
|
||||||
},
|
|
||||||
"props": [],
|
|
||||||
"x-prototype-urls": ["https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-div/1.0.1/proto.a264564.js"]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"componentName": "AliVcPage",
|
"urls": [
|
||||||
"npm": {
|
|
||||||
"package": "@ali/vc-page",
|
|
||||||
"library": "AliVcPage",
|
|
||||||
"version": "1.0.5",
|
|
||||||
"destructuring": false
|
|
||||||
},
|
|
||||||
"props": [],
|
|
||||||
"x-prototype-urls": [
|
|
||||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-page/1.0.5/proto.899e4b1.css",
|
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-page/1.0.5/proto.899e4b1.css",
|
||||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-page/1.0.5/proto.bfe05a5.js"
|
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-page/1.0.5/proto.bfe05a5.js"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"componentName": "AliVcDeep",
|
"urls": [
|
||||||
"npm": {
|
|
||||||
"package": "@ali/vc-deep",
|
|
||||||
"library": "AliVcDeep",
|
|
||||||
"version": "2.0.11",
|
|
||||||
"destructuring": false
|
|
||||||
},
|
|
||||||
"props": [],
|
|
||||||
"x-prototype-urls": [
|
|
||||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-deep/2.0.11/proto.15be45f.css",
|
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-deep/2.0.11/proto.15be45f.css",
|
||||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-deep/2.0.11/proto.039dc00.js"
|
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-deep/2.0.11/proto.039dc00.js"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"componentName": "AliVcShell",
|
"urls": [
|
||||||
"npm": {
|
|
||||||
"package": "@ali/vc-shell",
|
|
||||||
"library": "AliVcShell",
|
|
||||||
"version": "1.5.6",
|
|
||||||
"destructuring": false
|
|
||||||
},
|
|
||||||
"props": [],
|
|
||||||
"x-prototype-urls": [
|
|
||||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-shell/1.5.6/proto.70bac75.css",
|
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-shell/1.5.6/proto.70bac75.css",
|
||||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-shell/1.5.6/proto.8d105cf.js"
|
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-shell/1.5.6/proto.8d105cf.js"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"componentName": "AliVcSlot",
|
"urls": [
|
||||||
"npm": {
|
|
||||||
"package": "@ali/vc-slot",
|
|
||||||
"library": "AliVcSlot",
|
|
||||||
"version": "2.0.1",
|
|
||||||
"destructuring": false
|
|
||||||
},
|
|
||||||
"props": [],
|
|
||||||
"x-prototype-urls": [
|
|
||||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-slot/2.0.1/proto.0e43387.css",
|
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-slot/2.0.1/proto.0e43387.css",
|
||||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-slot/2.0.1/proto.9e01f34.js"
|
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-slot/2.0.1/proto.9e01f34.js"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"componentName": "AliVcText",
|
"urls": [
|
||||||
"npm": {
|
|
||||||
"package": "@ali/vc-text",
|
|
||||||
"library": "AliVcText",
|
|
||||||
"version": "4.0.1",
|
|
||||||
"destructuring": false
|
|
||||||
},
|
|
||||||
"props": [],
|
|
||||||
"x-prototype-urls": [
|
|
||||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-text/4.0.1/proto.595bd91.css",
|
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-text/4.0.1/proto.595bd91.css",
|
||||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-text/4.0.1/proto.90c4998.js"
|
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-text/4.0.1/proto.90c4998.js"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"componentName": "AliVcLink",
|
"urls": [
|
||||||
"npm": {
|
|
||||||
"package": "@ali/vc-link",
|
|
||||||
"library": "AliVcLink",
|
|
||||||
"version": "5.1.1",
|
|
||||||
"destructuring": false
|
|
||||||
},
|
|
||||||
"props": [],
|
|
||||||
"x-prototype-urls": [
|
|
||||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-link/5.1.1/proto.4828821.css",
|
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-link/5.1.1/proto.4828821.css",
|
||||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-link/5.1.1/proto.91e063a.js"
|
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-link/5.1.1/proto.91e063a.js"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"componentName": "AliVcLinkBlock",
|
"urls": ["https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-link-block/5.1.0/proto.4e9a9d2.js"]
|
||||||
"npm": {
|
|
||||||
"package": "@ali/vc-link-block",
|
|
||||||
"library": "AliVcLinkBlock",
|
|
||||||
"version": "5.1.0",
|
|
||||||
"destructuring": false
|
|
||||||
},
|
|
||||||
"props": [],
|
|
||||||
"x-prototype-urls": ["https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-link-block/5.1.0/proto.4e9a9d2.js"]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"componentName": "AliVcChartColumn",
|
"urls": [
|
||||||
"npm": {
|
|
||||||
"package": "@ali/vc-chart-column",
|
|
||||||
"library": "AliVcChartColumn",
|
|
||||||
"version": "3.0.5",
|
|
||||||
"destructuring": false
|
|
||||||
},
|
|
||||||
"props": [],
|
|
||||||
"x-prototype-urls": [
|
|
||||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-chart-column/3.0.5/proto.5973a33.css",
|
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-chart-column/3.0.5/proto.5973a33.css",
|
||||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-chart-column/3.0.5/proto.df847e6.js"
|
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-chart-column/3.0.5/proto.df847e6.js"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"componentName": "AliVcChartLine",
|
"urls": [
|
||||||
"npm": {
|
|
||||||
"package": "@ali/vc-chart-line",
|
|
||||||
"library": "AliVcChartLine",
|
|
||||||
"version": "3.0.4",
|
|
||||||
"destructuring": false
|
|
||||||
},
|
|
||||||
"props": [],
|
|
||||||
"x-prototype-urls": [
|
|
||||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-chart-line/3.0.4/proto.11e8b2c.css",
|
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-chart-line/3.0.4/proto.11e8b2c.css",
|
||||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-chart-line/3.0.4/proto.bbc1a73.js"
|
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-chart-line/3.0.4/proto.bbc1a73.js"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"componentName": "AliVcChartPie",
|
"urls": [
|
||||||
"npm": {
|
|
||||||
"package": "@ali/vc-chart-pie",
|
|
||||||
"library": "AliVcChartPie",
|
|
||||||
"version": "3.0.2",
|
|
||||||
"destructuring": false
|
|
||||||
},
|
|
||||||
"props": [],
|
|
||||||
"x-prototype-urls": [
|
|
||||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-chart-pie/3.0.2/proto.81a7751.css",
|
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-chart-pie/3.0.2/proto.81a7751.css",
|
||||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-chart-pie/3.0.2/proto.ce342e4.js"
|
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-chart-pie/3.0.2/proto.ce342e4.js"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"componentName": "AliVcChartRadar",
|
"urls": [
|
||||||
"npm": {
|
|
||||||
"package": "@ali/vc-chart-radar",
|
|
||||||
"library": "AliVcChartRadar",
|
|
||||||
"version": "3.0.2",
|
|
||||||
"destructuring": false
|
|
||||||
},
|
|
||||||
"props": [],
|
|
||||||
"x-prototype-urls": [
|
|
||||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-chart-radar/3.0.2/proto.81a7751.css",
|
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-chart-radar/3.0.2/proto.81a7751.css",
|
||||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-chart-radar/3.0.2/proto.638100d.js"
|
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-chart-radar/3.0.2/proto.638100d.js"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"componentName": "AliVcMarkdown",
|
"urls": [
|
||||||
"npm": {
|
|
||||||
"package": "@ali/vc-markdown",
|
|
||||||
"library": "AliVcMarkdown",
|
|
||||||
"version": "2.0.0",
|
|
||||||
"destructuring": false
|
|
||||||
},
|
|
||||||
"props": [],
|
|
||||||
"x-prototype-urls": [
|
|
||||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-markdown/2.0.0/proto.3f91095.css",
|
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-markdown/2.0.0/proto.3f91095.css",
|
||||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-markdown/2.0.0/proto.1bed9e5.js"
|
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-markdown/2.0.0/proto.1bed9e5.js"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"componentName": "AliAcAmdpHomeConsumer",
|
"urls": [
|
||||||
"npm": {
|
|
||||||
"package": "@ali/ac-amdp-home-consumer",
|
|
||||||
"library": "AliAcAmdpHomeConsumer",
|
|
||||||
"version": "1.0.11",
|
|
||||||
"destructuring": false
|
|
||||||
},
|
|
||||||
"props": [],
|
|
||||||
"x-prototype-urls": [
|
|
||||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/ac-amdp-home-consumer/1.0.11/proto.f3f24d5.css",
|
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/ac-amdp-home-consumer/1.0.11/proto.f3f24d5.css",
|
||||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/ac-amdp-home-consumer/1.0.11/proto.f12090f.js"
|
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/ac-amdp-home-consumer/1.0.11/proto.f12090f.js"
|
||||||
]
|
]
|
||||||
},
|
}
|
||||||
|
],
|
||||||
|
"components": [
|
||||||
{
|
{
|
||||||
"componentName": "AliReactJsonView",
|
"componentName": "AliReactJsonView",
|
||||||
"npm": {
|
"npm": {
|
||||||
@ -1,75 +1,63 @@
|
|||||||
import lg from '@ali/vu-logger';
|
import lg from '@ali/vu-logger';
|
||||||
import { camelCase, find, findIndex, upperFirst } from 'lodash';
|
import { ComponentClass, ComponentType } from 'react';
|
||||||
import { ComponentClass, ReactElement, ComponentType } from 'react';
|
|
||||||
|
|
||||||
import { UnknownComponent } from '../../ui/placeholders';
|
|
||||||
import Trunk, { IComponentBundle } from './trunk';
|
|
||||||
import Prototype from './prototype';
|
import Prototype from './prototype';
|
||||||
|
import { ComponentMeta } from '@ali/lowcode-designer';
|
||||||
|
import { designer } from '../editor';
|
||||||
|
|
||||||
function basename(name: string) {
|
function basename(name: string) {
|
||||||
return name ? (/[^\/]+$/.exec(name) || [''])[0] : '';
|
return name ? (/[^\/]+$/.exec(name) || [''])[0] : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCamelName(name: string) {
|
function getCamelName(name: string) {
|
||||||
const words = basename(name).replace(/^((vc)-)?(.+)/, '$3').split('-');
|
const words = basename(name)
|
||||||
|
.replace(/^((vc)-)?(.+)/, '$3')
|
||||||
|
.split('-');
|
||||||
return words.reduce((s, word) => s + word[0].toUpperCase() + word.substring(1), '');
|
return words.reduce((s, word) => s + word[0].toUpperCase() + word.substring(1), '');
|
||||||
}
|
}
|
||||||
|
|
||||||
export declare interface IComponentProto {
|
export interface ComponentProtoBundle {
|
||||||
|
// @ali/vc-xxx
|
||||||
name: string;
|
name: string;
|
||||||
module: Prototype;
|
|
||||||
componentName?: string;
|
componentName?: string;
|
||||||
category?: string;
|
category?: string;
|
||||||
|
module: Prototype | Prototype[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ComponentViewBundle {
|
||||||
|
// @ali/vc-xxx
|
||||||
|
name: string;
|
||||||
|
// alias to property name
|
||||||
|
componentName?: string;
|
||||||
|
category?: string;
|
||||||
|
module: ComponentType<any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class Bundle {
|
export default class Bundle {
|
||||||
public static createPrototype = Prototype.create;
|
static createPrototype = Prototype.create;
|
||||||
public static addGlobalPropsReducer = Prototype.addGlobalPropsReducer;
|
static addGlobalPropsReducer = Prototype.addGlobalPropsReducer;
|
||||||
public static addGlobalPropsConfigure = Prototype.addGlobalPropsConfigure;
|
static addGlobalPropsConfigure = Prototype.addGlobalPropsConfigure;
|
||||||
public static addGlobalExtraActions = Prototype.addGlobalExtraActions;
|
static addGlobalExtraActions = Prototype.addGlobalExtraActions;
|
||||||
public static addGlobalNodeCanDragConfig = Prototype.addGlobalNodeCanDragConfig;
|
static removeGlobalPropsConfigure = Prototype.removeGlobalPropsConfigure;
|
||||||
public static removeGlobalPropsConfigure = Prototype.removeGlobalPropsConfigure;
|
static overridePropsConfigure = Prototype.overridePropsConfigure;
|
||||||
public static overridePropsConfigure = Prototype.overridePropsConfigure;
|
static create(protos: ComponentProtoBundle[], views?: ComponentViewBundle[]) {
|
||||||
public static create = function createBundle(
|
return new Bundle(protos, views);
|
||||||
components: Array<IComponentProto[] | IComponentProto>,
|
}
|
||||||
views: IComponentBundle[], nameSpace: string) {
|
|
||||||
return new Bundle(components, views, nameSpace);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
private viewsMap: { [componentName: string]: ComponentType } = {};
|
||||||
* if all components are packed in a single package
|
private registry: { [componentName: string]: Prototype } = {};
|
||||||
* the compositeBundle property shall be true
|
private prototypeList: Prototype[] = [];
|
||||||
*/
|
|
||||||
public compositeBundle: boolean = false;
|
|
||||||
|
|
||||||
private trunk: Trunk;
|
constructor(protos?: ComponentProtoBundle[], views?: ComponentViewBundle[]) {
|
||||||
private nameSpace: string;
|
// 注册 prototypeView 视图
|
||||||
private registry: { [name: string]: Prototype };
|
if (views && Array.isArray(views)) {
|
||||||
private registryById: { [id: string]: Prototype };
|
|
||||||
private prototypeList: Prototype[];
|
|
||||||
|
|
||||||
private viewMap: { [viewName: string]: ComponentClass } = {};
|
|
||||||
private viewList: ComponentClass[] = [];
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
componentPrototypes: Array<IComponentProto | IComponentProto[]>,
|
|
||||||
views: IComponentBundle[],
|
|
||||||
nameSpace: string,
|
|
||||||
) {
|
|
||||||
this.nameSpace = nameSpace || '';
|
|
||||||
this.registry = {};
|
|
||||||
this.registryById = {};
|
|
||||||
this.prototypeList = [];
|
|
||||||
this.trunk = new Trunk();
|
|
||||||
|
|
||||||
if (Array.isArray(views)) {
|
|
||||||
this.recursivelyRegisterViews(views);
|
this.recursivelyRegisterViews(views);
|
||||||
}
|
}
|
||||||
componentPrototypes.forEach((item: IComponentProto) => {
|
protos?.forEach((item) => {
|
||||||
const prototype = item.module;
|
const prototype = item.module;
|
||||||
if (prototype instanceof Prototype) {
|
if (prototype instanceof Prototype) {
|
||||||
this.revisePrototype(item, prototype);
|
this.revisePrototype(item, prototype);
|
||||||
const matchedView = this.viewMap[item.componentName || prototype.getComponentName()] || null;
|
const componentName = item.componentName || prototype.getComponentName()!;
|
||||||
|
const matchedView = this.viewsMap[componentName] || null;
|
||||||
if (!prototype.getView() && matchedView) {
|
if (!prototype.getView() && matchedView) {
|
||||||
prototype.setView(matchedView);
|
prototype.setView(matchedView);
|
||||||
}
|
}
|
||||||
@ -78,137 +66,46 @@ export default class Bundle {
|
|||||||
this.recursivelyRegisterPrototypes(prototype, item);
|
this.recursivelyRegisterPrototypes(prototype, item);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.prototypeList.forEach((p, idx) => {
|
|
||||||
if (!p.getView()) {
|
|
||||||
p.setView(UnknownComponent);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// invoke prototype mocker while the prototype does not exist
|
|
||||||
Object.keys(this.viewMap).forEach((viewName) => {
|
|
||||||
if (!find(this.prototypeList, (proto) => proto.getComponentName() === viewName)) {
|
|
||||||
const mockedPrototype = this.trunk.mockComponentPrototype(this.viewMap[viewName]);
|
|
||||||
if (mockedPrototype) {
|
|
||||||
if (!mockedPrototype.getPackageName()) {
|
|
||||||
mockedPrototype.setPackageName((this.viewMap[viewName] as any)._packageName_);
|
|
||||||
}
|
|
||||||
this.registry[viewName] = mockedPrototype;
|
|
||||||
this.registryById[mockedPrototype.getId()] = mockedPrototype;
|
|
||||||
this.prototypeList.push(mockedPrototype);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public addComponentBundle(bundles: Array<IComponentProto | IComponentBundle>): void;
|
getFromMeta(componentName: string): Prototype {
|
||||||
public addComponentBundle(bundles: any) {
|
if (this.registry[componentName]) {
|
||||||
/**
|
return this.registry[componentName];
|
||||||
* Normal Component bundle: [ Prototype, PrototypeView ]
|
|
||||||
* Component without Prototype.js: [ View ]
|
|
||||||
*/
|
|
||||||
if (bundles.length >= 2) {
|
|
||||||
const prototype = bundles[0];
|
|
||||||
const prototypeView = bundles[1];
|
|
||||||
prototype.setView(prototypeView);
|
|
||||||
this.registerPrototype(prototype);
|
|
||||||
} else if (bundles.length === 1) {
|
|
||||||
// Mock a Prototype for DIY Component load from async build
|
|
||||||
const proto = this.trunk.mockComponentPrototype(bundles[0]);
|
|
||||||
if (!proto) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!proto.getView()) {
|
|
||||||
proto.setView(bundles[0]);
|
|
||||||
}
|
|
||||||
this.registerPrototype(proto);
|
|
||||||
}
|
}
|
||||||
|
const meta = designer.getComponentMeta(componentName);
|
||||||
|
const prototype = Prototype.create(meta);
|
||||||
|
this.prototypeList.push(prototype);
|
||||||
|
this.registry[componentName] = prototype;
|
||||||
|
return prototype;
|
||||||
}
|
}
|
||||||
|
|
||||||
public removeComponentBundle(componentName: string) {
|
removeComponentBundle(componentName: string) {
|
||||||
const cIndex = findIndex(this.prototypeList, (proto) => proto.getComponentName() === componentName);
|
const cIndex = this.prototypeList.findIndex((proto) => proto.getComponentName() === componentName);
|
||||||
const id = this.prototypeList[cIndex].getId();
|
|
||||||
delete this.registryById[id];
|
|
||||||
delete this.registry[componentName];
|
delete this.registry[componentName];
|
||||||
this.prototypeList.splice(cIndex, 1);
|
this.prototypeList.splice(cIndex, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getNamespace() {
|
getList() {
|
||||||
return this.nameSpace;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getList() {
|
|
||||||
return this.prototypeList;
|
return this.prototypeList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get(componentName: string) {
|
get(componentName: string) {
|
||||||
return this.registry[componentName];
|
return this.registry[componentName];
|
||||||
}
|
}
|
||||||
|
|
||||||
public getById(id: string) {
|
replacePrototype(componentName: string, cp: Prototype) {
|
||||||
return this.registryById[id];
|
|
||||||
}
|
|
||||||
|
|
||||||
public isCompositeBundle() {
|
|
||||||
return this.isCompositeBundle;
|
|
||||||
}
|
|
||||||
|
|
||||||
public filter(fn: (item: Prototype) => boolean) {
|
|
||||||
this.prototypeList = this.prototypeList.filter((item) => {
|
|
||||||
if (fn(item) === false) {
|
|
||||||
if (this.registry[item.getComponentName()] === item) {
|
|
||||||
delete this.registry[item.getComponentName()];
|
|
||||||
}
|
|
||||||
if (this.registryById[item.getId()] === item) {
|
|
||||||
delete this.registryById[item.getId()];
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public replacePrototype(componentName: string, cp: Prototype) {
|
|
||||||
const view: any = this.get(componentName).getView();
|
const view: any = this.get(componentName).getView();
|
||||||
this.removeComponentBundle(componentName);
|
this.removeComponentBundle(componentName);
|
||||||
this.registry[cp.getComponentName()] = cp;
|
this.registry[cp.getComponentName()!] = cp;
|
||||||
this.registryById[cp.getId()] = cp;
|
|
||||||
this.prototypeList.push(cp);
|
this.prototypeList.push(cp);
|
||||||
cp.setView(view);
|
cp.setView(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
private recursivelyRegisterPrototypes(list: any[], cp: IComponentProto) {
|
|
||||||
const propList: IComponentProto[] = list;
|
|
||||||
propList.forEach((proto: IComponentProto, index: number) => {
|
|
||||||
if (Array.isArray(proto)) {
|
|
||||||
this.recursivelyRegisterPrototypes(proto, cp);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (proto instanceof Prototype) {
|
|
||||||
if (!proto.getView() && this.viewMap[proto.getComponentName()]) {
|
|
||||||
proto.setView(this.viewMap[proto.getComponentName()]);
|
|
||||||
}
|
|
||||||
if (index === 0 && cp.componentName) {
|
|
||||||
proto.setComponentName(cp.componentName);
|
|
||||||
}
|
|
||||||
if (cp.name && !proto.getPackageName()) {
|
|
||||||
proto.setPackageName(cp.name);
|
|
||||||
}
|
|
||||||
this.registerPrototype(proto);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* register View
|
|
||||||
* @param list ViewList
|
|
||||||
* @param viewName
|
|
||||||
*/
|
|
||||||
private recursivelyRegisterViews(list: IComponentBundle[], viewName?: string): void;
|
|
||||||
private recursivelyRegisterViews(list: any[], viewName?: string): void {
|
private recursivelyRegisterViews(list: any[], viewName?: string): void {
|
||||||
list.forEach((item: any) => {
|
list.forEach((item: any) => {
|
||||||
if (Array.isArray(item.module)) {
|
if (Array.isArray(item.module)) {
|
||||||
return this.recursivelyRegisterViews(item.module, item.name);
|
return this.recursivelyRegisterViews(item.module, item.name);
|
||||||
} else if (Array.isArray(item)) {
|
} else if (Array.isArray(item)) {
|
||||||
this.compositeBundle = true;
|
|
||||||
return this.recursivelyRegisterViews(item, viewName);
|
return this.recursivelyRegisterViews(item, viewName);
|
||||||
}
|
}
|
||||||
let viewDetail: ComponentClass;
|
let viewDetail: ComponentClass;
|
||||||
@ -220,44 +117,51 @@ export default class Bundle {
|
|||||||
if (!viewDetail.displayName) {
|
if (!viewDetail.displayName) {
|
||||||
lg.log('ERROR_NO_PROTOTYPE_VIEW');
|
lg.log('ERROR_NO_PROTOTYPE_VIEW');
|
||||||
lg.error('WARNING: the package without displayName is', item);
|
lg.error('WARNING: the package without displayName is', item);
|
||||||
viewDetail.displayName = upperFirst(
|
viewDetail.displayName = getCamelName(viewName || item.name);
|
||||||
// mock componentName from packageName
|
|
||||||
camelCase((viewName || item.name).split('-').slice(1).join('-')),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
(viewDetail as any)._packageName_ = viewName || item.name;
|
(viewDetail as any)._packageName_ = viewName || item.name;
|
||||||
this.viewMap[viewDetail.displayName] = viewDetail;
|
this.viewsMap[viewDetail.displayName] = viewDetail;
|
||||||
this.viewList.push(viewDetail);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private revisePrototype(item: IComponentProto, prototype: Prototype) {
|
private recursivelyRegisterPrototypes(list: any[], cp: ComponentProtoBundle) {
|
||||||
const name = item.name || item.componentName;
|
const propList: ComponentProtoBundle[] = list;
|
||||||
|
propList.forEach((proto: ComponentProtoBundle, index: number) => {
|
||||||
|
if (Array.isArray(proto)) {
|
||||||
|
this.recursivelyRegisterPrototypes(proto, cp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (proto instanceof Prototype) {
|
||||||
|
const componentName = proto.getComponentName()!;
|
||||||
|
if (!proto.getView() && this.viewsMap[componentName]) {
|
||||||
|
proto.setView(this.viewsMap[componentName]);
|
||||||
|
}
|
||||||
|
if (cp.name && !proto.getPackageName()) {
|
||||||
|
proto.setPackageName(cp.name);
|
||||||
|
}
|
||||||
|
this.registerPrototype(proto);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private revisePrototype(item: ComponentProtoBundle, prototype: Prototype) {
|
||||||
if (item.category) {
|
if (item.category) {
|
||||||
prototype.setCategory(item.category);
|
prototype.setCategory(item.category);
|
||||||
}
|
}
|
||||||
if (item.name && !prototype.getPackageName()) {
|
if (item.name && !prototype.getPackageName()) {
|
||||||
prototype.setPackageName(item.name);
|
prototype.setPackageName(item.name);
|
||||||
}
|
}
|
||||||
if (item.componentName) {
|
|
||||||
prototype.setComponentName(item.componentName);
|
|
||||||
}
|
|
||||||
if (!prototype.getComponentName()) {
|
|
||||||
prototype.setComponentName(getCamelName(name));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private registerPrototype(prototype: Prototype) {
|
private registerPrototype(prototype: Prototype) {
|
||||||
if (this.registry[prototype.getComponentName()]) {
|
const componentName = prototype.getComponentName()!;
|
||||||
lg.warn('WARN: override prototype', prototype, prototype.getComponentName());
|
if (this.registry[componentName]) {
|
||||||
const idx = findIndex(this.prototypeList, (proto) =>
|
lg.warn('WARN: override prototype', prototype, componentName);
|
||||||
prototype.getComponentName() === proto.getComponentName());
|
const idx = this.prototypeList.findIndex((proto) => componentName === proto.getComponentName());
|
||||||
this.prototypeList[idx] = prototype;
|
this.prototypeList[idx] = prototype;
|
||||||
delete this.registryById[prototype.getId()];
|
|
||||||
} else {
|
} else {
|
||||||
this.prototypeList.push(prototype);
|
this.prototypeList.push(prototype);
|
||||||
}
|
}
|
||||||
this.registry[prototype.getComponentName()] = prototype;
|
this.registry[componentName] = prototype;
|
||||||
this.registryById[prototype.getId()] = prototype;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1,299 +1,47 @@
|
|||||||
import lg from '@ali/vu-logger';
|
import { ReactElement, ComponentType } from 'react';
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
import { ComponentClass } from 'react';
|
import { registerSetter } from '@ali/lowcode-globals';
|
||||||
|
|
||||||
import Bundle from './bundle';
|
import Bundle from './bundle';
|
||||||
import Prototype, { setPackages } from './prototype';
|
|
||||||
import Bus from '../bus';
|
|
||||||
|
|
||||||
interface IComponentInfo {
|
export class Trunk {
|
||||||
image?: string;
|
private trunk: any[] = [];
|
||||||
description?: string;
|
private emitter: EventEmitter = new EventEmitter();
|
||||||
componentDetail?: string;
|
private metaBundle = new Bundle();
|
||||||
newVersion?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IComponentLoader {
|
|
||||||
load: (packageName: string, packageVersion: string, filePath?: string) => Promise<IComponentBundle>;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IComponentPrototypeMocker {
|
|
||||||
mockPrototype: (bundle: ComponentClass) => Prototype;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IComponentBundle {
|
|
||||||
// @ali/vc-xxx
|
|
||||||
name: string;
|
|
||||||
// alias to property name
|
|
||||||
componentName?: string;
|
|
||||||
category?: string;
|
|
||||||
module: ComponentClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IComponentBundleLoadingConfig {
|
|
||||||
isDIYComponent?: boolean;
|
|
||||||
// need to emit 'trunk_change' event
|
|
||||||
isSilence?: boolean;
|
|
||||||
isNpmComponent?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IComponentBundleConfigListItem {
|
|
||||||
name: string;
|
|
||||||
version: string;
|
|
||||||
path?: string;
|
|
||||||
// ac component in LeGao
|
|
||||||
// FIXME: remove this logic out of Trunk in the future
|
|
||||||
isDIYComponent?: boolean;
|
|
||||||
// install comp directly from npm
|
|
||||||
isNpmComponent?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IBeforeLoad extends IComponentBundleLoadingConfig {
|
|
||||||
name: string;
|
|
||||||
version: string;
|
|
||||||
path: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
type beforeLoadFn = (loadingConfig: IBeforeLoad) => IBeforeLoad;
|
|
||||||
type afterLoadFn = (bundle: IComponentBundle, loadingConfig: IBeforeLoad) => IComponentBundle;
|
|
||||||
|
|
||||||
class Trunk {
|
|
||||||
private trunk: any[];
|
|
||||||
private list: any[];
|
|
||||||
private emitter: EventEmitter;
|
|
||||||
private componentBundleLoader: IComponentLoader;
|
|
||||||
private componentPrototypeMocker: IComponentPrototypeMocker;
|
|
||||||
|
|
||||||
private beforeLoad: beforeLoadFn;
|
|
||||||
private afterLoad: afterLoadFn;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.trunk = [];
|
|
||||||
this.emitter = new EventEmitter();
|
|
||||||
this.componentBundleLoader = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
isReady() {
|
isReady() {
|
||||||
return this.getList().length > 0;
|
return this.getList().length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
addBundle(bundle: Bundle, bundleOptions: {
|
addBundle(bundle: Bundle) {
|
||||||
before?: (bundle: Bundle) => Promise<Bundle>;
|
|
||||||
after?: (bundle: Bundle) => any;
|
|
||||||
} = {}) {
|
|
||||||
// filter exsits
|
|
||||||
bundle.filter((item) => {
|
|
||||||
const componentName = item.getComponentName();
|
|
||||||
if (componentName && this.getPrototype(componentName)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
if (bundleOptions.before) {
|
|
||||||
bundleOptions.before.call(this, bundle).then((processedBundle: Bundle) => {
|
|
||||||
this.trunk.push(processedBundle);
|
|
||||||
this.emitter.emit('trunkchange');
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.trunk.push(bundle);
|
this.trunk.push(bundle);
|
||||||
this.emitter.emit('trunkchange');
|
this.emitter.emit('trunkchange');
|
||||||
}
|
}
|
||||||
if (bundleOptions.after) {
|
|
||||||
bundleOptions.after.call(this, bundle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
getBundle(): Bundle {
|
||||||
* 注册组件信息加载器
|
console.warn('Trunk.getBundle is deprecated');
|
||||||
*/
|
|
||||||
registerComponentBundleLoader(loader: IComponentLoader) {
|
|
||||||
// warn replacement method
|
|
||||||
this.componentBundleLoader = loader;
|
|
||||||
}
|
|
||||||
|
|
||||||
registerComponentPrototypeMocker() {
|
|
||||||
console.warn('Trunk.registerComponentPrototypeMocker is deprecated');
|
|
||||||
}
|
|
||||||
|
|
||||||
getBundle(nameSpace?: string): Bundle {
|
|
||||||
console.warn('Trunk.getTrunk is deprecated');
|
|
||||||
if (!nameSpace) {
|
|
||||||
return this.trunk[0];
|
return this.trunk[0];
|
||||||
}
|
}
|
||||||
return find(this.trunk, (b: any) => b.getNamespace() === nameSpace);
|
|
||||||
|
getList(): any[] {
|
||||||
|
return this.trunk.reduceRight((prev, cur) => prev.concat(cur.getList()), []);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getList(): any[] {
|
getPrototype(name: string) {
|
||||||
return this.list || this.trunk.reduceRight((prev, cur) => prev.concat(cur.getList()), []);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 列出所有组件列表
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
listByCategory() {
|
|
||||||
console.warn('Trunk.listByCategory is deprecated');
|
|
||||||
const categories: any[] = [];
|
|
||||||
const categoryMap: any = {};
|
|
||||||
const categoryItems: any[] = [];
|
|
||||||
const defaultCategory = {
|
|
||||||
items: categoryItems,
|
|
||||||
name: '*',
|
|
||||||
};
|
|
||||||
categories.push(defaultCategory);
|
|
||||||
categoryMap['*'] = defaultCategory;
|
|
||||||
this.getList().forEach((prototype) => {
|
|
||||||
const cat = prototype.getCategory();
|
|
||||||
if (!cat) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!categoryMap.hasOwnProperty(cat)) {
|
|
||||||
const categoryMapItems: any[] = [];
|
|
||||||
categoryMap[cat] = {
|
|
||||||
items: categoryMapItems,
|
|
||||||
name: cat,
|
|
||||||
};
|
|
||||||
categories.push(categoryMap[cat]);
|
|
||||||
}
|
|
||||||
categoryMap[cat].items.push(prototype);
|
|
||||||
});
|
|
||||||
return categories;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取仓库
|
|
||||||
*
|
|
||||||
* @returns {Array}
|
|
||||||
*/
|
|
||||||
getTrunk() {
|
|
||||||
// legao-design 中有用
|
|
||||||
console.warn('Trunk.getTrunk is deprecated');
|
|
||||||
return this.trunk;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据 componentName 查找对应的 prototype
|
|
||||||
*
|
|
||||||
* @param {string} componentName
|
|
||||||
* @returns {Prototype}
|
|
||||||
*/
|
|
||||||
getPrototype(componentName: string) {
|
|
||||||
if (!componentName) {
|
|
||||||
lg.error('ERROR: no component name found while get Prototype');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const name = componentName.split('.');
|
|
||||||
const namespace = name.length > 1 ? name[0] : '';
|
|
||||||
let i = this.trunk.length;
|
|
||||||
let bundle;
|
|
||||||
let ns;
|
|
||||||
let prototype;
|
|
||||||
while (i-- > 0) {
|
|
||||||
bundle = this.trunk[i];
|
|
||||||
ns = bundle.getNamespace();
|
|
||||||
if (ns === '' || namespace === ns) {
|
|
||||||
prototype = bundle.get(componentName);
|
|
||||||
if (prototype) {
|
|
||||||
return prototype;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getPrototypeById(id: string) {
|
|
||||||
let i = this.trunk.length;
|
let i = this.trunk.length;
|
||||||
let bundle;
|
let bundle;
|
||||||
let prototype;
|
let prototype;
|
||||||
while (i-- > 0) {
|
while (i-- > 0) {
|
||||||
bundle = this.trunk[i];
|
bundle = this.trunk[i];
|
||||||
prototype = bundle.getById(id);
|
prototype = bundle.get(name);
|
||||||
if (prototype) {
|
if (prototype) {
|
||||||
return prototype;
|
return prototype;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return this.metaBundle.getFromMeta(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getPrototypeView(componentName: string) {
|
getPrototypeView(componentName: string) {
|
||||||
const prototype = this.getPrototype(componentName);
|
return this.getPrototype(componentName)?.getView();
|
||||||
return prototype ? prototype.getView() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public loadComponentBundleList(componentBundleList: IComponentBundleConfigListItem[]) {
|
|
||||||
Promise.all(componentBundleList.map((componentBundle) => {
|
|
||||||
const { name, version, path, ...bundleContextInfo } = componentBundle;
|
|
||||||
return this.loadComponentBundle(name, version, path, {
|
|
||||||
...bundleContextInfo,
|
|
||||||
isDIYComponent: componentBundle.isDIYComponent,
|
|
||||||
isSilence: true,
|
|
||||||
});
|
|
||||||
})).then((results) => {
|
|
||||||
results.forEach((r: any) => this.getBundle().addComponentBundle(r));
|
|
||||||
this.emitter.emit('trunkchange');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public loadComponentBundle(
|
|
||||||
name: string,
|
|
||||||
version: string,
|
|
||||||
path?: string,
|
|
||||||
options?: IComponentBundleLoadingConfig) {
|
|
||||||
const bundleList: IComponentBundle[] = [];
|
|
||||||
return new Promise((resolve: any, reject: any) => {
|
|
||||||
if (options && options.isDIYComponent) {
|
|
||||||
let result: IBeforeLoad = { name, version, path, ...options };
|
|
||||||
if (isFunction(this.beforeLoad)) {
|
|
||||||
result = this.beforeLoad(result);
|
|
||||||
}
|
|
||||||
return this.componentBundleLoader.load(result.name, result.version, result.path)
|
|
||||||
.then((b: IComponentBundle) => {
|
|
||||||
if (isFunction(this.afterLoad)) {
|
|
||||||
this.afterLoad(b, { name, path, version, ...options });
|
|
||||||
}
|
|
||||||
if (!options.isSilence) {
|
|
||||||
this.getBundle().addComponentBundle([b]);
|
|
||||||
this.emitter.emit('trunkchange');
|
|
||||||
}
|
|
||||||
resolve([b]);
|
|
||||||
})
|
|
||||||
.catch((e: Error) => {
|
|
||||||
Bus.emit('ve.error.networkError', e);
|
|
||||||
reject(e);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.componentBundleLoader.load(name, version, 'build/prototype.js')
|
|
||||||
.then((b: IComponentBundle) => {
|
|
||||||
bundleList.push(b);
|
|
||||||
return this.componentBundleLoader.load(name, version, 'build/prototypeView.js');
|
|
||||||
})
|
|
||||||
.then((b: IComponentBundle) => {
|
|
||||||
bundleList.push(b);
|
|
||||||
if (!options.isSilence) {
|
|
||||||
this.getBundle().addComponentBundle(bundleList);
|
|
||||||
this.emitter.emit('trunkchange');
|
|
||||||
}
|
|
||||||
resolve(bundleList);
|
|
||||||
})
|
|
||||||
.catch((e: Error) => {
|
|
||||||
Bus.emit('ve.error.networkError', e);
|
|
||||||
reject(e);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
removeComponentBundle(name: string) {
|
|
||||||
this.getBundle().removeComponentBundle(name);
|
|
||||||
this.emitter.emit('trunkchange');
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeLoadBundle(fn: beforeLoadFn) {
|
|
||||||
this.beforeLoad = fn;
|
|
||||||
}
|
|
||||||
|
|
||||||
afterLoadBundle(fn: afterLoadFn) {
|
|
||||||
this.afterLoad = fn;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onTrunkChange(func: () => any) {
|
onTrunkChange(func: () => any) {
|
||||||
@ -303,8 +51,25 @@ class Trunk {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
setPackages(packages: Array<{ package: string; library: object | string }>) {
|
registerSetter(type: string, setter: ReactElement | ComponentType<any>) {
|
||||||
setPackages(packages);
|
console.warn('Trunk.registerSetter is deprecated');
|
||||||
|
registerSetter(type, setter);
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeLoadBundle() {
|
||||||
|
console.warn('Trunk.beforeLoadBundle is deprecated');
|
||||||
|
}
|
||||||
|
|
||||||
|
afterLoadBundle() {
|
||||||
|
console.warn('Trunk.afterLoadBundle is deprecated');
|
||||||
|
}
|
||||||
|
|
||||||
|
registerComponentPrototypeMocker() {
|
||||||
|
console.warn('Trunk.registerComponentPrototypeMocker is deprecated');
|
||||||
|
}
|
||||||
|
|
||||||
|
setPackages() {
|
||||||
|
console.warn('Trunk.setPackages is deprecated');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,118 +1,20 @@
|
|||||||
/**
|
import { ComponentType, ReactElement, isValidElement, ComponentClass } from 'react';
|
||||||
* 拒绝
|
import { isI18nData } from '@ali/lowcode-globals';
|
||||||
*/
|
|
||||||
export type REJECTED = 0 | false;
|
|
||||||
/**
|
|
||||||
* 限制性的
|
|
||||||
*/
|
|
||||||
export type LIMITED = 2;
|
|
||||||
/**
|
|
||||||
* 允许
|
|
||||||
*/
|
|
||||||
export type ALLOWED = true | 4;
|
|
||||||
|
|
||||||
export type HandleState = REJECTED | ALLOWED | LIMITED;
|
type Field = any;
|
||||||
|
|
||||||
/*
|
|
||||||
* model.editing:(dbclick) 父级优先(捕获过程)
|
|
||||||
* asCode(gotocode) 默认行为 select - option
|
|
||||||
* asRichText (运行值)
|
|
||||||
* asPlainText (运行值) 仅包含
|
|
||||||
* null|undefined 不响应(默认值)
|
|
||||||
* false 禁用 阻止继续捕获
|
|
||||||
* handle-function
|
|
||||||
*
|
|
||||||
* ## 检查与控制 handle
|
|
||||||
*
|
|
||||||
* model.shouldRemoveChild: HandleState | (my, child) => HandleState 移除子节点时(触发时),return false,拒绝移除
|
|
||||||
* model.shouldMoveChild: HandleState | (my, child) => HandleState 移动子节点, return false: 拒绝移动; return 0: 不得改变嵌套关系
|
|
||||||
* model.shouldRemove: HandleState | (my) => HandleState
|
|
||||||
* model.shouldMove: HandleState | (my) => HandleState return false, 拒绝移动 return 0; 不得改变嵌套关系
|
|
||||||
*
|
|
||||||
* ## 类型嵌套检查 (白名单机制)
|
|
||||||
*
|
|
||||||
* 自定义 locate
|
|
||||||
* model.locate: (my, transferData, mouseEvent?) => Location | null, 用于非 node 节点任意数据的定位
|
|
||||||
*
|
|
||||||
* test-RegExp: /^tagName./
|
|
||||||
* test-List: 'tagName,tagName2' | ['tagName', 'tagName2']
|
|
||||||
* test-Func: (target, my) => boolean
|
|
||||||
* Tester: RegExp | Pattern | Func
|
|
||||||
*
|
|
||||||
* component.accept
|
|
||||||
* accept: '@CHILD',从子节点寻找一个容器,针对 slot,比如 TabsLayout,ColumnsLayout, 大纲树误定位则错误信息透出,拒绝投入
|
|
||||||
* accept: false|null 表示不是一个容器,是一个端点,比如input,option
|
|
||||||
* accept: true 表示ok,无任何限制,比如 div,
|
|
||||||
* accept: Tester, 表示限定接受,作为filter条件,比如 select,不接受的主视图跳过定位,大纲树定位进去后红线提示
|
|
||||||
* model.nesting 多级过滤,错误信息透出 (nextTick异步检查),拒绝投入
|
|
||||||
* null | undefined | false | true 未设置 | 无意义值,不作拦截
|
|
||||||
* Tester
|
|
||||||
* model.dropTarget
|
|
||||||
* Tester // 实时约束
|
|
||||||
* {
|
|
||||||
* highlight?: Tester | boolean, // 高亮,默认false,设为true时根据 parent | ancestor 取值
|
|
||||||
* parent?: Tester, // 实时约束,主视图限制定位,大纲树定位进去时红线提示
|
|
||||||
* ancestor?: Tester, // 异步检查,上文检查, 设置此值时,parent 可不设置
|
|
||||||
* }
|
|
||||||
* '@ROOT' 只能放根节点,不高亮,异步检查
|
|
||||||
* null | undefined | boolean 未设置|无意义值,不作拦截,不高亮
|
|
||||||
*
|
|
||||||
* 所有拒绝投放的,在结束时均会检查,并抖动提示原因
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* 1. 分栏容器嵌套栏/UL 嵌套 li 子嵌套约束
|
|
||||||
* 2. Form 嵌套 Button, Input 后裔嵌套约束
|
|
||||||
* 3. 数据实体 拖入 可接受目标,比如变量拖入富文本编辑器(@千緖)
|
|
||||||
* 4. Li 拖拽时高亮所有 UL,根据Li设置的 dropTargetRules 目标规则筛选节点,取并集区域
|
|
||||||
* 5. 能弹出提示
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
export interface BehaviorControl {
|
|
||||||
handleMove?: HandleState | ((my: ElementNode) => HandleState);
|
|
||||||
handleRemove?: HandleState | ((my: ElementNode) => HandleState);
|
|
||||||
handleChildMove?: HandleState | ((my: ElementNode, child: INode) => HandleState);
|
|
||||||
handleChildRemove?: HandleState | ((my: ElementNode, child: INode) => HandleState);
|
|
||||||
}
|
|
||||||
|
|
||||||
export const AT_CHILD = Symbol.for('@CHILD');
|
|
||||||
export const AT_ROOT = Symbol.for('@ROOT');
|
|
||||||
export type AT_ROOT = typeof AT_ROOT;
|
|
||||||
export type AT_CHILD = typeof AT_CHILD;
|
|
||||||
|
|
||||||
export type AcceptFunc = (
|
|
||||||
my: ElementNode,
|
|
||||||
e: LocateEvent | KeyboardEvent | MouseEvent,
|
|
||||||
) => LocationData | INodeParent | AT_CHILD | null;
|
|
||||||
|
|
||||||
// should appear couple
|
|
||||||
export interface AcceptControl {
|
|
||||||
/**
|
|
||||||
* MouseEvent: drag a entiy from browser out
|
|
||||||
* KeyboardEvent: paste a entiy
|
|
||||||
* LocateEvent: drag a entiy from pane
|
|
||||||
*/
|
|
||||||
handleLocate?: AcceptFunc | AT_CHILD;
|
|
||||||
handleAccept?: (my: ElementNode, locationData: LocationData) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ContentEditable {
|
|
||||||
propTarget: string;
|
|
||||||
selector?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum DISPLAY_TYPE {
|
export enum DISPLAY_TYPE {
|
||||||
NONE = 'none',
|
NONE = 'none', // => condition'plain'
|
||||||
PLAIN = 'plain',
|
PLAIN = 'plain',
|
||||||
INLINE = 'inline',
|
INLINE = 'inline',
|
||||||
BLOCK = 'block',
|
BLOCK = 'block',
|
||||||
ACCORDION = 'accordion',
|
ACCORDION = 'accordion',
|
||||||
TAB = 'tab',
|
TAB = 'tab', // => 'accordion'
|
||||||
ENTRY = 'entry',
|
ENTRY = 'entry',
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPropConfig {
|
// from vision 5.4
|
||||||
|
export interface OldPropConfig {
|
||||||
/**
|
/**
|
||||||
* composite share the namespace
|
* composite share the namespace
|
||||||
* group just be tie up together
|
* group just be tie up together
|
||||||
@ -121,32 +23,24 @@ export interface IPropConfig {
|
|||||||
/**
|
/**
|
||||||
* when type is composite or group
|
* when type is composite or group
|
||||||
*/
|
*/
|
||||||
items?: IPropConfig[]; // => items
|
items?: OldPropConfig[]; // => items
|
||||||
/**
|
/**
|
||||||
* property name: the field key in props of schema
|
* property name: the field key in props of schema
|
||||||
*/
|
*/
|
||||||
name: string; // =>
|
name: string; // =>
|
||||||
title?: string; // =>
|
title?: string; // =>
|
||||||
tip?: {
|
tip?: {
|
||||||
// =>
|
|
||||||
title?: string;
|
|
||||||
content?: string;
|
content?: string;
|
||||||
url?: string;
|
url?: string;
|
||||||
};
|
};
|
||||||
initialValue?: any; // => ?
|
defaultValue?: any; // => extraProps.defaultValue
|
||||||
defaultValue?: any; // =>
|
initialValue?: any | ((value: any, defaultValue: any) => any); // => extraProps.initialValue
|
||||||
|
initial?: (value: any, defaultValue: any) => any // => extraProps.initialValue
|
||||||
|
|
||||||
display?: DISPLAY_TYPE; // => fieldExtraProps
|
display?: DISPLAY_TYPE; // => fieldExtraProps
|
||||||
fieldStyle?: DISPLAY_TYPE; // => fieldExtraProps
|
fieldStyle?: DISPLAY_TYPE; // => fieldExtraProps
|
||||||
setter?: ComponentClass | ISetterConfig[] | string | SetterGetter; // =>
|
setter?: ComponentClass | ISetterConfig[] | string | SetterGetter; // =>
|
||||||
/**
|
supportVariable?: boolean; // => use MixedSetter
|
||||||
* if a prop is dynamicProp, every-time while rendering setting field
|
|
||||||
* - getValue() will not include value of getHotValue()
|
|
||||||
* - getValue() will trigger accessor() to calculate a new value
|
|
||||||
* this prop usually work out when we need to generate prop value
|
|
||||||
* from node of current page
|
|
||||||
*/
|
|
||||||
isDynamicProp?: boolean;
|
|
||||||
supportVariable?: boolean; // => use MixinSetter
|
|
||||||
/**
|
/**
|
||||||
* the prop should be collapsed while display value is accordion
|
* the prop should be collapsed while display value is accordion
|
||||||
*/
|
*/
|
||||||
@ -165,75 +59,377 @@ export interface IPropConfig {
|
|||||||
* will not export data to schema
|
* will not export data to schema
|
||||||
*/
|
*/
|
||||||
ignore?: boolean | ReturnBooleanFunction; // => ?virtualProp ? thinkof global transform
|
ignore?: boolean | ReturnBooleanFunction; // => ?virtualProp ? thinkof global transform
|
||||||
/**
|
|
||||||
* if a prop is declared as virtual, it will not be saved in
|
|
||||||
* schema props, instead it will be saved into context field
|
|
||||||
*/
|
|
||||||
virtual?: boolean | ReturnBooleanFunction; // =>?virtualProp
|
|
||||||
hidden?: boolean | ReturnBooleanFunction; // => condition
|
hidden?: boolean | ReturnBooleanFunction; // => condition
|
||||||
/**
|
|
||||||
* if a prop is a lifeCycle function
|
|
||||||
*/
|
|
||||||
lifeCycle?: boolean; // =>?
|
|
||||||
destroy?: () => any; // => x
|
|
||||||
initial?(this: Prop, value: any, initialValue: any): any;
|
|
||||||
/**
|
/**
|
||||||
* when use getValue(), accessor shall be called as initializer
|
* when use getValue(), accessor shall be called as initializer
|
||||||
*/
|
*/
|
||||||
accessor?(this: Prop): any; // => getValue
|
accessor?(this: Field, value: any): any; // => getValue
|
||||||
/**
|
/**
|
||||||
* when current prop value mutate, the mutator function shall be called
|
* when current prop value mutate, the mutator function shall be called
|
||||||
*/
|
*/
|
||||||
mutator?( // => setValue
|
mutator?( // => setValue
|
||||||
this: Prop,
|
this: Field,
|
||||||
value: any,
|
value: any,
|
||||||
|
/*
|
||||||
hotValue: any, // => x
|
hotValue: any, // => x
|
||||||
preValue: any, // => x
|
preValue: any, // => x
|
||||||
preHotValue: any, // => x
|
preHotValue: any, // => x
|
||||||
|
*/
|
||||||
): void;
|
): void;
|
||||||
/**
|
/**
|
||||||
* other values' change will trigger sync function here
|
* other values' change will trigger sync function here
|
||||||
*/
|
*/
|
||||||
sync?(this: Prop, value: any): void; // => ? autorun
|
sync?(this: Field, value: any): void; // => autorun
|
||||||
/**
|
|
||||||
* transform runtime data between view and setter
|
|
||||||
* @param toHotValue hot value for the setter
|
|
||||||
* @param toViewValue static value for the view
|
|
||||||
*/
|
|
||||||
transformer?( // =>?
|
|
||||||
toHotValue: (data: any) => any,
|
|
||||||
toViewValue: (str: string) => any,
|
|
||||||
): any;
|
|
||||||
/**
|
/**
|
||||||
* user click var to change current field to
|
* user click var to change current field to
|
||||||
* variable setting field
|
* variable setting field
|
||||||
*/
|
*/
|
||||||
useVariableChange?(data: { isUseVariable: boolean }): any; // => ?
|
useVariableChange?(this: Field, data: { isUseVariable: boolean }): any; // => as MixinSetter param
|
||||||
|
|
||||||
|
slotName?: string;
|
||||||
|
slotTitle?: string;
|
||||||
|
initialChildren?: any; // schema
|
||||||
|
allowTextInput: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SettingFieldConfig {
|
// from vision 5.4
|
||||||
type?: 'field';
|
export interface OldPrototypeConfig {
|
||||||
title?: string;
|
packageName: string; // => npm.package
|
||||||
name: string;
|
/**
|
||||||
setter: ComponentClass | ISetterConfig[] | string | SetterGetter;
|
* category display in the component pane
|
||||||
extraProps?: {
|
* component will be hidden while the value is: null
|
||||||
[key: string]: any;
|
*/
|
||||||
|
category: string; // => tags
|
||||||
|
componentName: string; // =>
|
||||||
|
docUrl?: string; // =>
|
||||||
|
defaultProps?: any; // => ?
|
||||||
|
/**
|
||||||
|
* extra actions on the outline of current selected node
|
||||||
|
* by default we have: remove / clone
|
||||||
|
*/
|
||||||
|
extraActions?: Array<ComponentType<any> | ReactElement> | (() => ReactElement); // => configure.component.actions
|
||||||
|
title?: string; // =>
|
||||||
|
icon?: ComponentType<any> | ReactElement; // =>
|
||||||
|
view: ComponentType; // => ?
|
||||||
|
initialChildren?: (props: any) => any[]; // => snippets
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Props configurations of node
|
||||||
|
*/
|
||||||
|
configure: OldPropConfig[]; // => configure.props
|
||||||
|
snippets?: any[]; // => snippets
|
||||||
|
transducers?: any; // => ?
|
||||||
|
/**
|
||||||
|
* Selector expression rectangle of a node, it is usually a querySelector string
|
||||||
|
* @example '.classname > div'
|
||||||
|
*/
|
||||||
|
rectSelector?: string; // => configure.component.rectSelector
|
||||||
|
context?: {
|
||||||
|
// => ?
|
||||||
|
[contextInfoName: string]: any;
|
||||||
|
};
|
||||||
|
|
||||||
|
isContainer?: boolean; // => configure.component.isContainer
|
||||||
|
isModal?: boolean; // => configure.component.isModal
|
||||||
|
isFloating?: boolean; // => configure.component.isFloating
|
||||||
|
descriptor?: string; // => configure.component.descriptor
|
||||||
|
|
||||||
|
// alias to canDragging
|
||||||
|
canDraging?: boolean; // => onDrag
|
||||||
|
canDragging?: boolean; // => ?
|
||||||
|
|
||||||
|
canOperating?: boolean; // => disabledActions
|
||||||
|
canSelecting?: boolean;
|
||||||
|
canContain?: (dragment: Node) => boolean; // => nestingRule
|
||||||
|
|
||||||
|
canDropTo?: ((container: Node) => boolean) | string | string[]; // => nestingRule
|
||||||
|
canDropto?: (container: Node) => boolean; // => nestingRule
|
||||||
|
|
||||||
|
canDropIn?: ((dragment: Node) => boolean) | string | string[]; // => nestingRule
|
||||||
|
canDroping?: (dragment: Node) => boolean; // => nestingRule
|
||||||
|
|
||||||
|
didDropOut?: (dragment: any, container: any) => void; // => hooks
|
||||||
|
didDropIn?: (dragment: any, container: any) => void; // => hooks
|
||||||
|
|
||||||
|
/**
|
||||||
|
* when sub-node of the current node changed
|
||||||
|
* including: sub-node insert / remove
|
||||||
|
*/
|
||||||
|
subtreeModified?(this: Node): any; // => ? hooks
|
||||||
|
|
||||||
|
// => ?
|
||||||
|
canResizing?: ((dragment: any, triggerDirection: string) => boolean) | boolean;
|
||||||
|
onResizeStart?: (e: MouseEvent, triggerDirection: string, dragment: Node) => void;
|
||||||
|
onResize?: (e: MouseEvent, triggerDirection: string, dragment: Node, moveX: number, moveY: number) => void;
|
||||||
|
onResizeEnd?: (e: MouseEvent, triggerDirection: string, dragment: Node) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ISetterConfig {
|
||||||
|
setter?: ComponentClass;
|
||||||
|
// use value to decide whether this setter is available
|
||||||
|
condition?: (value: any) => boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
type SetterGetter = (this: Field, value: any) => ComponentClass;
|
||||||
|
|
||||||
|
type ReturnBooleanFunction = (this: Field, value: any) => boolean;
|
||||||
|
|
||||||
|
export function upgradePropConfig(config: OldPropConfig) {
|
||||||
|
const {
|
||||||
|
type,
|
||||||
|
name,
|
||||||
|
title,
|
||||||
|
tip,
|
||||||
|
slotName,
|
||||||
|
slotTitle,
|
||||||
|
initialChildren,
|
||||||
|
allowTextInput,
|
||||||
|
initialValue,
|
||||||
|
defaultValue,
|
||||||
|
display,
|
||||||
|
fieldStyle,
|
||||||
|
collapse,
|
||||||
|
collapsed,
|
||||||
|
fieldCollapsed,
|
||||||
|
hidden,
|
||||||
|
disabled,
|
||||||
|
items,
|
||||||
|
ignore,
|
||||||
|
initial,
|
||||||
|
sync,
|
||||||
|
accessor,
|
||||||
|
mutator,
|
||||||
|
setter,
|
||||||
|
useVariableChange,
|
||||||
|
supportVariable,
|
||||||
|
} = config;
|
||||||
|
|
||||||
|
const extraProps: any = {};
|
||||||
|
const newConfig: any = {
|
||||||
|
type: type === 'group' ? 'group' : 'field',
|
||||||
|
name,
|
||||||
|
title,
|
||||||
|
extraProps,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (tip) {
|
||||||
|
if (typeof title !== 'object' || isI18nData(title) || isValidElement(title)) {
|
||||||
|
newConfig.title = {
|
||||||
|
title,
|
||||||
|
tip: tip.content,
|
||||||
|
docUrl: tip.url
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
newConfig.title = {
|
||||||
|
...(title as any),
|
||||||
|
tip: tip.content,
|
||||||
|
docUrl: tip.url
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (display || fieldStyle) {
|
||||||
|
extraProps.display = display || fieldStyle;
|
||||||
|
if (extraProps.display === DISPLAY_TYPE.TAB) {
|
||||||
|
extraProps.display = DISPLAY_TYPE.ACCORDION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (collapse || collapsed || fieldCollapsed) {
|
||||||
|
extraProps.defaultCollapsed = true;
|
||||||
|
}
|
||||||
|
function isDisabled(field: Field) {
|
||||||
|
if (typeof disabled === 'function') {
|
||||||
|
return disabled.call(field, field.getValue()) === true;
|
||||||
|
}
|
||||||
|
return disabled === true;
|
||||||
|
}
|
||||||
|
function isHidden(field: Field) {
|
||||||
|
if (typeof hidden === 'function') {
|
||||||
|
return hidden.call(field, field.getValue()) === true;
|
||||||
|
}
|
||||||
|
return hidden === true;
|
||||||
|
}
|
||||||
|
if (extraProps.display === DISPLAY_TYPE.NONE) {
|
||||||
|
extraProps.display = undefined;
|
||||||
|
extraProps.condition = () => false;
|
||||||
|
} else if (hidden != null || disabled != null) {
|
||||||
|
extraProps.condition = (field: Field) => !(isHidden(field) || isDisabled(field));
|
||||||
|
}
|
||||||
|
if (ignore != null || disabled != null) {
|
||||||
|
extraProps.virtual = (field: Field) => {
|
||||||
|
if (isDisabled(field)) { return true; }
|
||||||
|
|
||||||
|
if (typeof ignore === 'function') {
|
||||||
|
return ignore.call(field, field.getValue()) === true;
|
||||||
|
}
|
||||||
|
return ignore === true;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SettingGroupConfig {
|
if (type === 'group') {
|
||||||
type: 'group';
|
newConfig.items = items ? upgradeConfigure(items) : [];
|
||||||
title?: string;
|
return newConfig;
|
||||||
items: Array<SettingGroupConfig | SettingFieldConfig>;
|
}
|
||||||
extraProps?: {
|
|
||||||
[key: string]: any;
|
if (slotName) {
|
||||||
|
newConfig.name = slotName;
|
||||||
|
if (!newConfig.title && slotTitle) {
|
||||||
|
newConfig.title = slotTitle;
|
||||||
|
}
|
||||||
|
const slotSetter = {
|
||||||
|
componentName: 'SlotSetter',
|
||||||
|
initialValue: () => ({
|
||||||
|
type: 'JSSlot',
|
||||||
|
// params:
|
||||||
|
value: initialChildren
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
if (allowTextInput === false) {
|
||||||
|
newConfig.setter = slotSetter;
|
||||||
|
} else {
|
||||||
|
newConfig.setter = [{
|
||||||
|
componentName: 'StringSetter',
|
||||||
|
initialValue,
|
||||||
|
}, slotSetter];
|
||||||
|
}
|
||||||
|
|
||||||
|
return newConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (defaultValue !== undefined) {
|
||||||
|
extraProps.defaultValue = defaultValue;
|
||||||
|
} else if (typeof initialValue !== 'function') {
|
||||||
|
extraProps.defaultValue = initialValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialFn = initial || initialValue;
|
||||||
|
extraProps.initialValue = (field: Field, defaultValue?: any) => {
|
||||||
|
if (defaultValue === undefined) {
|
||||||
|
defaultValue = extraProps.defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof initialFn === 'function') {
|
||||||
|
return initialFn(null, defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return defaultValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (sync) {
|
||||||
|
extraProps.autorun = (field: Field) => {
|
||||||
|
const value = sync.call(field, field.getValue());
|
||||||
|
if (value !== undefined) {
|
||||||
|
field.setValue(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (accessor) {
|
||||||
|
extraProps.getValue = (field: Field, fieldValue: any) => {
|
||||||
|
return accessor.call(field, fieldValue);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (mutator) {
|
||||||
|
extraProps.setValue = (field: Field, value: any) => {
|
||||||
|
mutator.call(field, value);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let primarySetter: any;
|
||||||
|
if (type === 'composite') {
|
||||||
|
const objItems = items ? upgradeConfigure(items) : [];
|
||||||
|
primarySetter = {
|
||||||
|
componentName: 'ObjectSetter',
|
||||||
|
props: {
|
||||||
|
config: {
|
||||||
|
items: objItems,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
initialValue: (field: Field) => {
|
||||||
|
// FIXME: read from objItems
|
||||||
|
return extraProps.initialValue(field, {});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
} else if (setter) {
|
||||||
|
if (Array.isArray(setter)) {
|
||||||
|
primarySetter = setter.map(({ setter, condition }) => {
|
||||||
|
return {
|
||||||
|
componentName: setter,
|
||||||
|
condition: condition ? (field: Field) => {
|
||||||
|
return condition.call(field, field.getValue());
|
||||||
|
} : null,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
primarySetter = setter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (supportVariable) {
|
||||||
|
if (primarySetter) {
|
||||||
|
const setters = Array.isArray(primarySetter) ? primarySetter.concat('ExpressionSetter') : [primarySetter, 'ExpressionSetter'];
|
||||||
|
primarySetter = {
|
||||||
|
componentName: 'MixedSetter',
|
||||||
|
setters,
|
||||||
|
onSetterChange: (field: Field, name: string) => {
|
||||||
|
if (useVariableChange) {
|
||||||
|
useVariableChange.call(field, { isUseVariable: name === 'ExpressionSetter' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
primarySetter = 'ExpressionSetter';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newConfig.setter = primarySetter;
|
||||||
|
|
||||||
|
return newConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function upgradeConfigure(items: OldPropConfig[]) {
|
||||||
|
const configure = [];
|
||||||
|
let ignoreSlotName: any = null;
|
||||||
|
return items.forEach((config) => {
|
||||||
|
if (config.slotName) {
|
||||||
|
ignoreSlotName = config.slotName;
|
||||||
|
} else if (ignoreSlotName) {
|
||||||
|
if (config.name === ignoreSlotName) {
|
||||||
|
ignoreSlotName = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ignoreSlotName = null;
|
||||||
|
}
|
||||||
|
configure.push(upgradePropConfig(config));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function upgradeActions(actions?: Array<ComponentType<any> | ReactElement> | (() => ReactElement)) {
|
||||||
|
if (!actions) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!Array.isArray(actions)) {
|
||||||
|
actions = [actions];
|
||||||
|
}
|
||||||
|
return actions.map((content) => {
|
||||||
|
const type: any = isValidElement(content) ? content.type : content;
|
||||||
|
if (typeof content === 'function') {
|
||||||
|
const fn = content as (() => ReactElement);
|
||||||
|
content = (({ node }: any) => {
|
||||||
|
fn.call(node);
|
||||||
|
}) as any;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
name: type.displayName || type.name || 'anonymous',
|
||||||
|
content,
|
||||||
|
important: true,
|
||||||
|
};
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 升级
|
* 升级
|
||||||
*/
|
*/
|
||||||
function upgradeMetadata(oldConfig: OldPrototypeConfig) {
|
export function upgradeMetadata(oldConfig: OldPrototypeConfig) {
|
||||||
const {
|
const {
|
||||||
componentName,
|
componentName,
|
||||||
docUrl,
|
docUrl,
|
||||||
@ -242,11 +438,11 @@ function upgradeMetadata(oldConfig: OldPrototypeConfig) {
|
|||||||
packageName,
|
packageName,
|
||||||
category,
|
category,
|
||||||
extraActions,
|
extraActions,
|
||||||
view,
|
|
||||||
configure,
|
|
||||||
defaultProps,
|
defaultProps,
|
||||||
initialChildren,
|
initialChildren,
|
||||||
snippets,
|
snippets,
|
||||||
|
view,
|
||||||
|
configure,
|
||||||
transducers,
|
transducers,
|
||||||
isContainer,
|
isContainer,
|
||||||
rectSelector,
|
rectSelector,
|
||||||
@ -260,16 +456,18 @@ function upgradeMetadata(oldConfig: OldPrototypeConfig) {
|
|||||||
canDropto,
|
canDropto,
|
||||||
canDropIn,
|
canDropIn,
|
||||||
canDroping,
|
canDroping,
|
||||||
// handles
|
|
||||||
canDraging, canDragging, // handleDragging
|
|
||||||
canResizing, // handleResizing
|
|
||||||
// hooks
|
// hooks
|
||||||
|
canDraging, canDragging, // handleDragging
|
||||||
|
// events
|
||||||
didDropOut, // onNodeRemove
|
didDropOut, // onNodeRemove
|
||||||
didDropIn, // onNodeAdd
|
didDropIn, // onNodeAdd
|
||||||
|
subtreeModified, // onSubtreeModified
|
||||||
|
|
||||||
|
canResizing, // resizing
|
||||||
onResizeStart, // onResizeStart
|
onResizeStart, // onResizeStart
|
||||||
onResize, // onResize
|
onResize, // onResize
|
||||||
onResizeEnd, // onResizeEnd
|
onResizeEnd, // onResizeEnd
|
||||||
subtreeModified, // onSubtreeModified
|
|
||||||
} = oldConfig;
|
} = oldConfig;
|
||||||
|
|
||||||
|
|
||||||
@ -279,7 +477,7 @@ function upgradeMetadata(oldConfig: OldPrototypeConfig) {
|
|||||||
icon,
|
icon,
|
||||||
docUrl,
|
docUrl,
|
||||||
devMode: 'procode',
|
devMode: 'procode',
|
||||||
}
|
};
|
||||||
|
|
||||||
if (category) {
|
if (category) {
|
||||||
meta.tags = [category];
|
meta.tags = [category];
|
||||||
@ -303,13 +501,7 @@ function upgradeMetadata(oldConfig: OldPrototypeConfig) {
|
|||||||
component.disableBehaviors = '*';
|
component.disableBehaviors = '*';
|
||||||
}
|
}
|
||||||
if (extraActions) {
|
if (extraActions) {
|
||||||
component.actions = extraActions.map((content) => {
|
component.actions = upgradeActions(extraActions);
|
||||||
return {
|
|
||||||
name: content.displayName || content.name || 'anonymous',
|
|
||||||
content,
|
|
||||||
important: true,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
const nestingRule: any = {};
|
const nestingRule: any = {};
|
||||||
if (canContain) {
|
if (canContain) {
|
||||||
@ -323,97 +515,98 @@ function upgradeMetadata(oldConfig: OldPrototypeConfig) {
|
|||||||
}
|
}
|
||||||
component.nestingRule = nestingRule;
|
component.nestingRule = nestingRule;
|
||||||
|
|
||||||
if (canDragging || canDraging) {
|
|
||||||
// hooks|handle
|
|
||||||
}
|
|
||||||
|
|
||||||
// 未考虑清楚的,放在实验性段落
|
// 未考虑清楚的,放在实验性段落
|
||||||
const experimental: any = {};
|
const experimental: any = {};
|
||||||
if (context) {
|
if (context) {
|
||||||
// for prototype.getContextInfo
|
// for prototype.getContextInfo
|
||||||
experimental.context = context;
|
experimental.context = context;
|
||||||
}
|
}
|
||||||
|
if (snippets) {
|
||||||
const props = {};
|
experimental.snippets = snippets;
|
||||||
const styles = {};
|
|
||||||
const events = {};
|
|
||||||
meta.configure = { props, component, styles, events, experimental };
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
if (defaultProps || initialChildren) {
|
||||||
export interface OldPrototypeConfig {
|
const snippet = {
|
||||||
packageName: string; // => npm.package
|
screenshot: icon,
|
||||||
/**
|
label: title,
|
||||||
* category display in the component pane
|
schema: {
|
||||||
* component will be hidden while the value is: null
|
componentName,
|
||||||
*/
|
props: defaultProps,
|
||||||
category: string; // => tags
|
children: initialChildren,
|
||||||
componentName: string; // =>
|
},
|
||||||
docUrl?: string; // =>
|
|
||||||
defaultProps?: any; // => ?
|
|
||||||
/**
|
|
||||||
* extra actions on the outline of current selected node
|
|
||||||
* by default we have: remove / clone
|
|
||||||
*/
|
|
||||||
extraActions?: Component[]; // => configure.component.actions
|
|
||||||
title?: string; // =>
|
|
||||||
icon?: Component; // =>
|
|
||||||
view: Component; // => ?
|
|
||||||
initialChildren?: (props: any) => any[]; // => snippets
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Props configurations of node
|
|
||||||
*/
|
|
||||||
configure: IPropConfig[]; // => configure.props
|
|
||||||
snippets?: ISnippet[]; // => snippets
|
|
||||||
transducers?: any; // => ?
|
|
||||||
/**
|
|
||||||
* Selector expression rectangle of a node, it is usually a querySelector string
|
|
||||||
* @example '.classname > div'
|
|
||||||
*/
|
|
||||||
rectSelector?: string; // => configure.component.rectSelector
|
|
||||||
context?: {
|
|
||||||
// => ?
|
|
||||||
[contextInfoName: string]: any;
|
|
||||||
};
|
};
|
||||||
|
if (experimental.snippets) {
|
||||||
isContainer?: boolean; // => configure.component.isContainer
|
experimental.snippets.push(snippet);
|
||||||
isModal?: boolean; // => configure.component.isModal
|
} else {
|
||||||
isFloating?: boolean; // => configure.component.isFloating
|
experimental.snippets = [snippet];
|
||||||
descriptor?: string; // => configure.component.descriptor
|
|
||||||
|
|
||||||
/**
|
|
||||||
* enable slot-mode
|
|
||||||
* @see https://yuque.antfin-inc.com/legao/solutions/atgtdl
|
|
||||||
*/
|
|
||||||
hasSlot?: boolean; // => ?
|
|
||||||
|
|
||||||
// alias to canDragging
|
|
||||||
canDraging?: boolean; // => onDrag
|
|
||||||
canDragging?: boolean; // => ?
|
|
||||||
|
|
||||||
canOperating?: boolean; // => disabledActions
|
|
||||||
canSelecting?: boolean;
|
|
||||||
canContain?: (dragment: Node) => boolean; // => nestingRule
|
|
||||||
|
|
||||||
canDropTo?: ((container: Node) => boolean) | string | string[]; // => nestingRule
|
|
||||||
canDropto?: (container: Node) => boolean; // => nestingRule
|
|
||||||
|
|
||||||
canDropIn?: ((dragment: Node) => boolean) | string | string[]; // => nestingRule
|
|
||||||
canDroping?: (dragment: Node) => boolean; // => nestingRule
|
|
||||||
|
|
||||||
didDropOut?: (container: any | Prototype, dragment: any) => boolean; // => hooks
|
|
||||||
didDropIn?: (container: any | Prototype, dragment: any) => boolean; // => hooks
|
|
||||||
|
|
||||||
// => ?
|
|
||||||
canResizing?: ((dragment: Node, triggerDirection: string) => boolean) | boolean;
|
|
||||||
onResizeStart?: (e: MouseEvent, triggerDirection: string, dragment: Node) => void;
|
|
||||||
onResize?: (e: MouseEvent, triggerDirection: string, dragment: Node, moveX: number, moveY: number) => void;
|
|
||||||
onResizeEnd?: (e: MouseEvent, triggerDirection: string, dragment: Node) => void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* when sub-node of the current node changed
|
|
||||||
* including: sub-node insert / remove
|
|
||||||
*/
|
|
||||||
subtreeModified?(this: Node): any; // => ? hooks
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (view) {
|
||||||
|
experimental.view = view;
|
||||||
|
}
|
||||||
|
if (transducers) {
|
||||||
|
// Array<{ toStatic, toNative }>
|
||||||
|
// ? only twice
|
||||||
|
experimental.transducers = transducers;
|
||||||
|
}
|
||||||
|
if (canResizing) {
|
||||||
|
// TODO: enhance
|
||||||
|
experimental.getResizingHandlers = (currentNode: any) => {
|
||||||
|
const directs = ['n', 'w', 's', 'e'];
|
||||||
|
if (canResizing === true) {
|
||||||
|
return directs;
|
||||||
|
}
|
||||||
|
return directs.filter((d) => canResizing(currentNode, d));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const callbacks: any = {};
|
||||||
|
if (canDragging != null || canDraging != null) {
|
||||||
|
let v = true;
|
||||||
|
if (canDragging === false || canDraging === false) {
|
||||||
|
v = false;
|
||||||
|
}
|
||||||
|
callbacks.onMoveHook = () => v;
|
||||||
|
}
|
||||||
|
if (didDropIn) {
|
||||||
|
callbacks.onNodeAdd = didDropIn;
|
||||||
|
}
|
||||||
|
if (didDropOut) {
|
||||||
|
callbacks.onNodeRemove = didDropOut;
|
||||||
|
}
|
||||||
|
if (subtreeModified) {
|
||||||
|
callbacks.onSubtreeModified = (...args: any[]) => {
|
||||||
|
// FIXME! args not correct
|
||||||
|
subtreeModified.apply(args[0], args as any);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (onResize) {
|
||||||
|
callbacks.onResize = (e: any, currentNode: any) => {
|
||||||
|
// todo: what is trigger?
|
||||||
|
const { trigger, deltaX, deltaY } = e;
|
||||||
|
onResize(e, trigger, currentNode, deltaX, deltaY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (onResizeStart) {
|
||||||
|
callbacks.onResizeStart = (e: any, currentNode: any) => {
|
||||||
|
// todo: what is trigger?
|
||||||
|
const { trigger } = e;
|
||||||
|
onResizeStart(e, trigger, currentNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (onResizeEnd) {
|
||||||
|
callbacks.onResizeEnd = (e: any, currentNode: any) => {
|
||||||
|
// todo: what is trigger?
|
||||||
|
const { trigger } = e;
|
||||||
|
onResizeEnd(e, trigger, currentNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
experimental.callbacks = callbacks;
|
||||||
|
|
||||||
|
const props = upgradeConfigure(configure || []);
|
||||||
|
meta.configure = { props, component };
|
||||||
|
meta.experimental = experimental;
|
||||||
|
return meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { EventEmitter } from 'events';
|
|||||||
/**
|
/**
|
||||||
* Bus class as an EventEmitter
|
* Bus class as an EventEmitter
|
||||||
*/
|
*/
|
||||||
class Bus {
|
export class Bus {
|
||||||
private emitter = new EventEmitter();
|
private emitter = new EventEmitter();
|
||||||
|
|
||||||
getEmitter() {
|
getEmitter() {
|
||||||
|
|||||||
@ -1,16 +0,0 @@
|
|||||||
import { init } from './vision'; // VisualEngine
|
|
||||||
import { editor } from './editor';
|
|
||||||
|
|
||||||
init();
|
|
||||||
|
|
||||||
load();
|
|
||||||
|
|
||||||
async function load() {
|
|
||||||
const assets = await editor.utils.get('./assets.json');
|
|
||||||
editor.set('assets', assets);
|
|
||||||
editor.emit('assets.loaded', assets);
|
|
||||||
|
|
||||||
const schema = await editor.utils.get('./schema.json');
|
|
||||||
editor.set('schema', schema);
|
|
||||||
editor.emit('schema.loaded', schema);
|
|
||||||
}
|
|
||||||
55
packages/vision-polyfill/src/demo/index.ts
Normal file
55
packages/vision-polyfill/src/demo/index.ts
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import Engine from '../vision'; // VisualEngine
|
||||||
|
import { editor } from '../editor';
|
||||||
|
import loadUrls from './loader';
|
||||||
|
|
||||||
|
Engine.init();
|
||||||
|
|
||||||
|
load();
|
||||||
|
|
||||||
|
async function load() {
|
||||||
|
await loadAssets();
|
||||||
|
|
||||||
|
loadSchema();
|
||||||
|
}
|
||||||
|
|
||||||
|
const externals = [
|
||||||
|
'react',
|
||||||
|
'react-dom',
|
||||||
|
'prop-types',
|
||||||
|
'react-router',
|
||||||
|
'react-router-dom',
|
||||||
|
'@ali/recore',
|
||||||
|
];
|
||||||
|
async function loadAssets() {
|
||||||
|
const assets = await editor.utils.get('./legao-assets.json');
|
||||||
|
// Trunk.setPackages(assets.packages);
|
||||||
|
|
||||||
|
if (assets.packages) {
|
||||||
|
assets.packages.forEach((item: any) => {
|
||||||
|
if (item.package.indexOf('@ali/vc-') === 0 && item.urls) {
|
||||||
|
item.urls = item.urls.filter((url: string) => {
|
||||||
|
return url.indexOf('view.mobile') < 0
|
||||||
|
});
|
||||||
|
} else if (item.package && externals.indexOf(item.package) > -1) {
|
||||||
|
item.urls = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (assets['x-prototypes']) {
|
||||||
|
const tasks: Array<Promise<any>> = [];
|
||||||
|
assets['x-prototypes'].forEach((pkg: any) => {
|
||||||
|
tasks.push(loadUrls(pkg?.urls));
|
||||||
|
});
|
||||||
|
await Promise.all(tasks);
|
||||||
|
|
||||||
|
// proccess snippets
|
||||||
|
}
|
||||||
|
|
||||||
|
editor.set('assets', assets);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadSchema() {
|
||||||
|
const schema = await editor.utils.get('./schema.json');
|
||||||
|
editor.set('schema', schema);
|
||||||
|
}
|
||||||
171
packages/vision-polyfill/src/demo/loader.js
Normal file
171
packages/vision-polyfill/src/demo/loader.js
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
function getStylePoint(id, level) {
|
||||||
|
if (stylePointTable[id]) {
|
||||||
|
return stylePointTable[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
const base = getBasePoint();
|
||||||
|
|
||||||
|
if (id === 'base') {
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
|
||||||
|
const point = new StylePoint(id, level || 2000);
|
||||||
|
if (level >= base.level) {
|
||||||
|
let prev = base;
|
||||||
|
let next = prev.next;
|
||||||
|
while (next && level >= next.level) {
|
||||||
|
prev = next;
|
||||||
|
next = prev.next;
|
||||||
|
}
|
||||||
|
prev.next = point;
|
||||||
|
point.prev = prev;
|
||||||
|
if (next) {
|
||||||
|
point.next = next;
|
||||||
|
next.prev = point;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let next = base;
|
||||||
|
let prev = next.prev;
|
||||||
|
while (prev && level < prev.level) {
|
||||||
|
next = prev;
|
||||||
|
prev = next.prev;
|
||||||
|
}
|
||||||
|
next.prev = point;
|
||||||
|
point.next = next;
|
||||||
|
if (prev) {
|
||||||
|
point.prev = prev;
|
||||||
|
prev.next = point;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
point.insert();
|
||||||
|
stylePointTable[id] = point;
|
||||||
|
|
||||||
|
return point;
|
||||||
|
}
|
||||||
|
|
||||||
|
const stylePointTable = {};
|
||||||
|
|
||||||
|
function getBasePoint() {
|
||||||
|
if (!stylePointTable.base) {
|
||||||
|
stylePointTable.base = new StylePoint('base', 1000);
|
||||||
|
stylePointTable.base.insert();
|
||||||
|
}
|
||||||
|
return stylePointTable.base;
|
||||||
|
}
|
||||||
|
|
||||||
|
class StylePoint {
|
||||||
|
constructor(id, level, placeholder) {
|
||||||
|
this.lastContent = null;
|
||||||
|
this.lastUrl = null;
|
||||||
|
this.next = null;
|
||||||
|
this.prev = null;
|
||||||
|
this.id = id;
|
||||||
|
this.level = level;
|
||||||
|
if (placeholder) {
|
||||||
|
this.placeholder = placeholder;
|
||||||
|
} else {
|
||||||
|
this.placeholder = document.createTextNode('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
insert() {
|
||||||
|
if (this.next) {
|
||||||
|
document.head.insertBefore(this.placeholder, this.next.placeholder);
|
||||||
|
} else if (this.prev) {
|
||||||
|
document.head.insertBefore(this.placeholder, this.prev.placeholder.nextSibling);
|
||||||
|
} else {
|
||||||
|
document.head.appendChild(this.placeholder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
applyText(content) {
|
||||||
|
if (this.lastContent === content) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.lastContent = content;
|
||||||
|
this.lastUrl = undefined;
|
||||||
|
const element = document.createElement('style');
|
||||||
|
element.setAttribute('type', 'text/css');
|
||||||
|
element.setAttribute('data-for', this.id);
|
||||||
|
element.appendChild(document.createTextNode(content));
|
||||||
|
document.head.insertBefore(element, this.placeholder);
|
||||||
|
document.head.removeChild(this.placeholder);
|
||||||
|
this.placeholder = element;
|
||||||
|
}
|
||||||
|
|
||||||
|
applyUrl(url) {
|
||||||
|
if (this.lastUrl === url) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.lastContent = undefined;
|
||||||
|
this.lastUrl = url;
|
||||||
|
const element = document.createElement('link');
|
||||||
|
element.href = url;
|
||||||
|
element.rel = 'stylesheet';
|
||||||
|
element.setAttribute('data-for', this.id);
|
||||||
|
document.head.insertBefore(element, this.placeholder);
|
||||||
|
document.head.removeChild(this.placeholder);
|
||||||
|
this.placeholder = element;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadCSS(url) {
|
||||||
|
getStylePoint(url).applyUrl(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isCSSUrl(url) {
|
||||||
|
return /\.css$/.test(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadScript(url) {
|
||||||
|
const node = document.createElement('script');
|
||||||
|
|
||||||
|
// node.setAttribute('crossorigin', 'anonymous');
|
||||||
|
|
||||||
|
node.onload = onload;
|
||||||
|
node.onerror = onload;
|
||||||
|
|
||||||
|
const i = {};
|
||||||
|
const promise = new Promise((resolve, reject) => {
|
||||||
|
i.resolve = resolve;
|
||||||
|
i.reject = reject;
|
||||||
|
});
|
||||||
|
|
||||||
|
function onload(e) {
|
||||||
|
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 promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function loadUrls(urls) {
|
||||||
|
if (!urls || urls.length < 1) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
let promise = null;
|
||||||
|
urls.forEach((url) => {
|
||||||
|
if (isCSSUrl(url)) {
|
||||||
|
loadCSS(url);
|
||||||
|
} else if (!promise) {
|
||||||
|
promise = loadScript(url);
|
||||||
|
} else {
|
||||||
|
promise = promise.then(() => loadScript(url));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return promise || Promise.resolve();
|
||||||
|
}
|
||||||
@ -1,11 +1,11 @@
|
|||||||
|
import { globalContext } from '@ali/lowcode-globals';
|
||||||
import Editor from '@ali/lowcode-editor-core';
|
import Editor from '@ali/lowcode-editor-core';
|
||||||
|
import { Designer } from '@ali/lowcode-designer';
|
||||||
|
import { registerSetters } from '@ali/lowcode-setters';
|
||||||
import OutlinePane from '@ali/lowcode-plugin-outline-pane';
|
import OutlinePane from '@ali/lowcode-plugin-outline-pane';
|
||||||
import SettingsPane from '@ali/lowcode-plugin-settings-pane';
|
import SettingsPane from '@ali/lowcode-plugin-settings-pane';
|
||||||
import DesignerView from '@ali/lowcode-plugin-designer';
|
import DesignerView from '@ali/lowcode-plugin-designer';
|
||||||
import { registerSetters } from '@ali/lowcode-setters';
|
|
||||||
import { Skeleton } from './skeleton/skeleton';
|
import { Skeleton } from './skeleton/skeleton';
|
||||||
import { Designer } from 'designer/src/designer';
|
|
||||||
import { globalContext } from '@ali/lowcode-globals';
|
|
||||||
|
|
||||||
registerSetters();
|
registerSetters();
|
||||||
|
|
||||||
@ -41,11 +41,3 @@ skeleton.leftArea.add({
|
|||||||
area: 'leftFixedArea',
|
area: 'leftFixedArea',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// editor-core
|
|
||||||
// 1. di 实现
|
|
||||||
// 2. general bus: pub/sub
|
|
||||||
// editor-skeleton/workbench 视图实现
|
|
||||||
// 1. skeleton 区域划分 panes
|
|
||||||
// provide fixed left pane
|
|
||||||
// provide float left pane
|
|
||||||
|
|||||||
@ -6,12 +6,15 @@ import { createElement } from 'react';
|
|||||||
import { VE_EVENTS as EVENTS, VE_HOOKS as HOOKS } from './const';
|
import { VE_EVENTS as EVENTS, VE_HOOKS as HOOKS } from './const';
|
||||||
import Bus from './bus';
|
import Bus from './bus';
|
||||||
import Symbols from './symbols';
|
import Symbols from './symbols';
|
||||||
import { editor, skeleton } from './editor';
|
import { skeleton } from './editor';
|
||||||
import { VisionWorkbench } from './skeleton/workbench';
|
import { VisionWorkbench } from './skeleton/workbench';
|
||||||
import Panes from './panes';
|
import Panes from './panes';
|
||||||
import Exchange from './exchange';
|
import Exchange from './exchange';
|
||||||
import VisualEngineContext from './context';
|
import VisualEngineContext from './context';
|
||||||
import VisualManager from './base/visualManager';
|
import VisualManager from './base/visualManager';
|
||||||
|
import Trunk from './bundle/trunk';
|
||||||
|
import Prototype from './bundle/prototype';
|
||||||
|
import Bundle from './bundle/bundle';
|
||||||
|
|
||||||
function init(container?: Element) {
|
function init(container?: Element) {
|
||||||
if (!container) {
|
if (!container) {
|
||||||
@ -40,7 +43,7 @@ const modules = {
|
|||||||
|
|
||||||
const context = new VisualEngineContext();
|
const context = new VisualEngineContext();
|
||||||
|
|
||||||
export {
|
const VisualEngine = {
|
||||||
/**
|
/**
|
||||||
* VE.Popup
|
* VE.Popup
|
||||||
*/
|
*/
|
||||||
@ -68,9 +71,14 @@ export {
|
|||||||
ui,
|
ui,
|
||||||
Panes,
|
Panes,
|
||||||
modules,
|
modules,
|
||||||
|
Trunk,
|
||||||
|
Prototype,
|
||||||
|
Bundle,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default VisualEngine;
|
||||||
|
|
||||||
|
(window as any).VisualEngine = VisualEngine;
|
||||||
/*
|
/*
|
||||||
console.log(
|
console.log(
|
||||||
`%cLowcodeEngine %cv${VERSION}`,
|
`%cLowcodeEngine %cv${VERSION}`,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user