complete transform logic

This commit is contained in:
kangwei 2020-04-24 23:49:37 +08:00
parent 8a768177ce
commit df2362c67d
21 changed files with 416 additions and 140 deletions

View File

@ -1,5 +1,4 @@
import { ComponentType } from 'react';
import { EventEmitter } from 'events';
import {
ProjectSchema,
ComponentMetadata,
@ -9,9 +8,11 @@ import {
computed,
autorun,
IEditor,
CompositeObject,
PropsList,
} from '@ali/lowcode-globals';
import { Project } from '../project';
import { Node, DocumentModel, insertChildren, isRootNode, ParentalNode } from '../document';
import { Node, DocumentModel, insertChildren, isRootNode, ParentalNode, TransformStage } from '../document';
import { ComponentMeta } from '../component-meta';
import { INodeSelector, Component } from '../simulator';
import { Scroller, IScrollable } from './scroller';
@ -24,6 +25,7 @@ import { focusing } from './focusing';
import { SettingTopEntry } from './setting';
export interface DesignerProps {
editor: IEditor;
className?: string;
style?: object;
defaultSchema?: ProjectSchema;
@ -33,7 +35,6 @@ export interface DesignerProps {
dragGhostComponent?: ComponentType<any>;
suspensed?: boolean;
componentMetadatas?: ComponentMetadata[];
eventPipe?: EventEmitter;
globalComponentActions?: ComponentAction[];
onMount?: (designer: Designer) => void;
onDragstart?: (e: LocateEvent) => void;
@ -47,6 +48,7 @@ export class Designer {
readonly activeTracker = new ActiveTracker();
readonly hovering = new Hovering();
readonly project: Project;
readonly editor: IEditor;
get currentDocument() {
return this.project.currentDocument;
@ -61,6 +63,8 @@ export class Designer {
}
constructor(props: DesignerProps) {
const { editor } = props;
this.editor = editor;
this.setProps(props);
this.project = new Project(this, props.defaultSchema);
@ -164,7 +168,7 @@ export class Designer {
}
postEvent(event: string, ...args: any[]) {
this.props?.eventPipe?.emit(`designer.${event}`, ...args);
this.editor.emit(`designer.${event}`, ...args);
}
private _dropLocation?: DropLocation;
@ -312,7 +316,6 @@ export class Designer {
private _lostComponentMetasMap = new Map<string, ComponentMeta>();
private buildComponentMetasMap(metas: ComponentMetadata[]) {
console.info(this._componentMetasMap);
metas.forEach((data) => this.createComponentMeta(data));
}
@ -372,6 +375,30 @@ export class Designer {
return maps;
}
private propsReducers = new Map<TransformStage, PropsReducer[]>();
transformProps(props: CompositeObject | PropsList, node: Node, stage: TransformStage) {
if (Array.isArray(props)) {
// current not support, make this future
return props;
}
const reducers = this.propsReducers.get(stage);
if (!reducers) {
return props;
}
return reducers.reduce((xprops, reducer) => reducer(xprops, node), props);
}
addPropsReducer(reducer: PropsReducer, stage: TransformStage) {
const reducers = this.propsReducers.get(stage);
if (reducers) {
reducers.push(reducer);
} else {
this.propsReducers.set(stage, [reducer]);
}
}
autorun(action: (context: { firstRun: boolean }) => void, sync = false): () => void {
return autorun(action, sync as true);
}
@ -380,3 +407,5 @@ export class Designer {
// todo:
}
}
export type PropsReducer = (props: CompositeObject, node: Node) => CompositeObject;

View File

@ -157,7 +157,7 @@ export class SettingPropEntry implements SettingEntry {
// ======= compatibles for vision ======
getNode() {
return this.top;
return this.nodes[0];
}
getName(): string {

View File

@ -19,7 +19,7 @@ import { isDragNodeDataObject, DragNodeObject, DragNodeDataObject, DropLocation
import { Node, insertChildren, insertChild, isNode, RootNode, ParentalNode } from './node/node';
import { Selection } from './selection';
import { History } from './history';
import { ExportType } from './node';
import { TransformStage } from './node';
export type GetDataType<T, NodeType> = T extends undefined
? NodeType extends {
@ -277,8 +277,8 @@ export class DocumentModel {
// todo: select added and active track added
}
export(exportType: ExportType = ExportType.ForSerilize) {
return this.rootNode.export(exportType);
export(stage: TransformStage = TransformStage.Serilize) {
return this.rootNode.export(stage);
}
/**

View File

@ -1,5 +0,0 @@
export enum ExportType {
ForRender = 1,
ForSerilize = 2,
ForSave = 3,
}

View File

@ -4,4 +4,4 @@ export * from './node-children';
export * from './props/prop';
export * from './props/prop-stash';
export * from './props/props';
export * from './export-type';
export * from './transform-stage';

View File

@ -1,6 +1,6 @@
import { NodeData, isNodeSchema, obx, computed } from '@ali/lowcode-globals';
import { Node, ParentalNode } from './node';
import { ExportType } from './export-type';
import { TransformStage } from './transform-stage';
export class NodeChildren {
@obx.val private children: Node[];
@ -17,10 +17,10 @@ export class NodeChildren {
/**
* schema
*/
export(exportType: ExportType = ExportType.ForSave): NodeData[] {
export(stage: TransformStage = TransformStage.Save): NodeData[] {
return this.children.map(node => {
const data = node.export(exportType);
if (node.isLeaf() && ExportType.ForSave === exportType) {
const data = node.export(stage);
if (node.isLeaf() && TransformStage.Save === stage) {
// FIXME: filter empty
return data.children as NodeData;
}
@ -202,6 +202,46 @@ export class NodeChildren {
});
}
some(fn: (item: Node, index: number) => any): boolean {
return this.children.some((child, index) => fn(child, index));
}
mergeChildren(remover: () => any, adder: (children: Node[]) => NodeData[] | null, sorter: () => any) {
/*
const children = this.children.slice();
children.forEach(child => child.internalSetParent(null));
this.children = children;
this.interalInitParent();
*/
if (remover) {
const willRemove = this.children.filter(remover);
if (willRemove.length > 0) {
willRemove.forEach((node) => {
const i = this.children.indexOf(node);
if (i > -1) {
this.children.splice(i, 1);
node.remove();
}
});
}
}
if (adder) {
const items = adder(this.children);
if (items && items.length > 0) {
items.forEach((child: NodeData) => {
const node = this.owner.document.createNode(child);
this.children.push(node);
node.internalSetParent(this.owner);
});
}
}
if (sorter) {
this.children = this.children.sort(sorter);
}
}
private purged = false;
/**
*

View File

@ -18,7 +18,7 @@ import { NodeChildren } from './node-children';
import { Prop } from './props/prop';
import { ComponentMeta } from '../../component-meta';
import { ExclusiveGroup, isExclusiveGroup } from './exclusive-group';
import { ExportType } from './export-type';
import { TransformStage } from './transform-stage';
/**
*
@ -136,28 +136,31 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
const { componentName, id, children, props, ...extras } = nodeSchema;
this.id = id || `node$${document.nextId()}`;
this.componentName = componentName;
let _props: Props;
if (this.componentName === 'Leaf') {
_props = new Props(this, {
this.props = new Props(this, {
children: isDOMText(children) || isJSExpression(children) ? children : '',
});
} else {
// run initialChildren
this._children = new NodeChildren(this as ParentalNode, children || []);
this.props = new Props(this, props, extras);
this._children = new NodeChildren(this as ParentalNode, this.initialChildren(children));
this._children.interalInitParent();
_props = new Props(this, this.upgradeProps(props), extras);
this.props.import(this.transformProps(props || {}), extras);
}
this.props = _props;
}
private upgradeProps(props: any): any {
// TODO: run componentMeta(initials|initialValue|accessor)
// run transform
return props;
private transformProps(props: any): any {
// FIXME! support PropsList
const x = this.document.designer.transformProps(props, this, TransformStage.Init);
// TODO: run transducers in metadata.experimental
console.info(x);
return x;
}
private transformOut() {
private initialChildren(children: any): NodeData[] {
if (children == null) {
return this.componentMeta.getMetadata().experimental?.initialChildren || [];
}
return children;
}
isContainer(): boolean {
@ -266,7 +269,7 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
if (!this.isParental() || this.componentName === 'Fragment') {
return null;
}
return this.props.export(ExportType.ForSerilize).props || null;
return this.props.export(TransformStage.Serilize).props || null;
}
@computed hasSlots() {
@ -427,7 +430,7 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
* - schema
*/
get schema(): Schema {
return this.export(ExportType.ForSave);
return this.export(TransformStage.Save);
}
set schema(data: Schema) {
@ -448,31 +451,32 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
/**
* schema
*/
export(exportType: ExportType = ExportType.ForSave): Schema {
export(stage: TransformStage = TransformStage.Save): Schema {
// run transducers
// run
const baseSchema: any = {
componentName: this.componentName,
};
if (exportType !== ExportType.ForSave) {
if (stage !== TransformStage.Save) {
baseSchema.id = this.id;
}
if (this.isLeaf()) {
baseSchema.children = this.props.get('children')?.export(exportType);
baseSchema.children = this.props.get('children')?.export(stage);
return baseSchema;
}
const { props = {}, extras } = this.props.export(exportType) || {};
const { props = {}, extras } = this.props.export(stage) || {};
const schema: any = {
...baseSchema,
props,
props: this.document.designer.transformProps(props, this, stage),
...extras,
};
if (this.isParental() && this.children.size > 0) {
schema.children = this.children.export(exportType);
schema.children = this.children.export(stage);
}
return schema;
@ -556,6 +560,13 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
getNode() {
return this;
}
getProps() {
return this.props;
}
mergeChildren(remover: () => any, adder: (children: Node[]) => NodeData[] | null, sorter: () => any) {
this.children?.mergeChildren(remover, adder, sorter);
}
/**
* @deprecated
@ -595,6 +606,9 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
}
return { container: this.parent, ref: this };
}
toString() {
return this.id;
}
}
export interface ParentalNode<T extends NodeSchema = NodeSchema> extends Node<T> {
@ -689,7 +703,7 @@ export function comparePosition(node1: Node, node2: Node): PositionNO {
export function insertChild(container: ParentalNode, thing: Node | NodeData, at?: number | null, copy?: boolean): Node {
let node: Node;
if (isNode(thing) && (copy || thing.isSlot())) {
thing = thing.export(ExportType.ForSave);
thing = thing.export(TransformStage.Save);
}
if (isNode(thing)) {
node = thing;

View File

@ -15,7 +15,7 @@ import { PropStash } from './prop-stash';
import { valueToSource } from './value-to-source';
import { Props } from './props';
import { SlotNode } from '../node';
import { ExportType } from '../export-type';
import { TransformStage } from '../transform-stage';
export const UNSET = Symbol.for('unset');
export type UNSET = typeof UNSET;
@ -46,10 +46,10 @@ export class Prop implements IPropParent {
*
*/
@computed get value(): CompositeValue | UNSET {
return this.export(ExportType.ForSerilize);
return this.export(TransformStage.Serilize);
}
export(exporType: ExportType = ExportType.ForSave): CompositeValue | UNSET {
export(stage: TransformStage = TransformStage.Save): CompositeValue | UNSET {
const type = this._type;
if (type === 'unset') {
@ -61,8 +61,8 @@ export class Prop implements IPropParent {
}
if (type === 'slot') {
const schema = this._slotNode!.export(exporType);
if (exporType === ExportType.ForSave) {
const schema = this._slotNode!.export(stage);
if (stage === TransformStage.Save) {
return {
type: 'JSSlot',
params: schema.params,
@ -82,7 +82,7 @@ export class Prop implements IPropParent {
}
const maps: any = {};
this.items!.forEach((prop, key) => {
const v = prop.export(exporType);
const v = prop.export(stage);
if (v !== UNSET) {
maps[key] = v;
}
@ -95,7 +95,7 @@ export class Prop implements IPropParent {
return this._value;
}
return this.items!.map((prop) => {
const v = prop.export(exporType);
const v = prop.export(stage);
return v === UNSET ? null : v;
});
}
@ -113,7 +113,7 @@ export class Prop implements IPropParent {
}
// todo: JSFunction ...
if (this.type === 'slot') {
return JSON.stringify(this._slotNode!.export(ExportType.ForSave));
return JSON.stringify(this._slotNode!.export(TransformStage.Save));
}
return this._code != null ? this._code : JSON.stringify(this.value);
}
@ -191,7 +191,7 @@ export class Prop implements IPropParent {
}
@computed getValue(): CompositeValue {
const v = this.export(ExportType.ForSerilize);
const v = this.export(TransformStage.Serilize);
if (v === UNSET) {
return null;
}

View File

@ -2,7 +2,7 @@ import { PropsMap, PropsList, CompositeValue, computed, obx, uniqueId } from '@a
import { PropStash } from './prop-stash';
import { Prop, IPropParent, UNSET } from './prop';
import { Node } from '../node';
import { ExportType } from '../export-type';
import { TransformStage } from '../transform-stage';
export const EXTRA_KEY_PREFIX = '__';
@ -80,7 +80,7 @@ export class Props implements IPropParent {
});
}
export(exportType: ExportType = ExportType.ForSave): { props?: PropsMap | PropsList; extras?: object } {
export(stage: TransformStage = TransformStage.Save): { props?: PropsMap | PropsList; extras?: object } {
if (this.items.length < 1) {
return {};
}
@ -89,7 +89,7 @@ export class Props implements IPropParent {
if (this.type === 'list') {
props = [];
this.items.forEach(item => {
let value = item.export(exportType);
let value = item.export(stage);
if (value === UNSET) {
value = null;
}
@ -112,7 +112,7 @@ export class Props implements IPropParent {
// todo ...spread
return;
}
let value = item.export(exportType);
let value = item.export(stage);
if (value === UNSET) {
value = null;
}
@ -296,4 +296,15 @@ export class Props implements IPropParent {
this.stash.purge();
this.items.forEach(item => item.purge());
}
getProp(path: string, stash = true): Prop | null {
return this.query(path, stash as any) || null;
}
/**
*
*/
getPropValue(path: string): any {
return this.getProp(path, false)?.value;
}
}

View File

@ -0,0 +1,6 @@
export enum TransformStage {
Render = 1,
Serilize = 2,
Save = 3,
Init = 4,
}

View File

@ -12,6 +12,9 @@ export interface FieldExtraProps {
* default value of target prop for setter use
*/
defaultValue?: any;
/**
* get value for field
*/
getValue?: (target: SettingTarget, fieldValue: any) => any;
setValue?: (target: SettingTarget, value: any) => void;
/**

View File

@ -5,7 +5,8 @@ import { TitleContent } from './title';
import { PropConfig } from './prop-config';
import { NpmInfo } from './npm';
import { FieldConfig } from './field-config';
import { NodeSchema } from './schema';
import { NodeSchema, NodeData } from './schema';
import { SettingTarget } from './setting-target';
export type NestingFilter = (testNode: any, currentNode: any) => boolean;
export interface NestingRule {
@ -40,12 +41,20 @@ export interface Snippet {
schema: NodeSchema;
}
export interface InitialItem {
name: string;
initial: (target: SettingTarget, currentValue: any) => any;
}
export interface Experimental {
context?: { [contextInfoName: string]: any };
snippets?: Snippet[];
view?: ComponentType<any>;
transducers?: any; // ? should support
initials?: InitialItem[];
callbacks?: Callbacks;
// TODO: thinkof function
initialChildren?: NodeData[];
// 样式 及 位置handle上必须有明确的标识以便事件路由判断或者主动设置事件独占模式
// NWSE 是交给引擎计算放置位置ReactElement 必须自己控制初始位置

View File

@ -21,6 +21,11 @@ export interface JSSlot {
value?: NodeData[] | NodeData;
}
export interface JSBlock {
type: 'JSBlock';
value: NodeSchema;
}
// JSON 基本类型
export type JSONValue = boolean | string | number | null | JSONArray | JSONObject;
export type JSONArray = JSONValue[];
@ -43,3 +48,7 @@ export function isJSExpression(data: any): data is JSExpression {
export function isJSSlot(data: any): data is JSSlot {
return data && data.type === 'JSSlot';
}
export function isJSBlock(data: any): data is JSBlock {
return data && data.type === 'JSBlock'
}

View File

@ -63,13 +63,11 @@ export default class DesignerPlugin extends PureComponent<PluginProps, DesignerP
return null;
}
console.info('metadatas', componentMetadatas);
return (
<DesignerView
onMount={this.handleDesignerMount}
className="lowcode-plugin-designer"
eventPipe={editor}
editor={editor}
designer={editor.get(Designer)}
componentMetadatas={componentMetadatas}
simulatorProps={{

View File

@ -41,7 +41,6 @@ class Renderer extends Component<{ renderer: SimulatorRenderer }> {
}
render() {
const { renderer } = this.props;
console.info(renderer.schema)
return (
<LowCodeRenderer
schema={renderer.schema}

View File

@ -1,4 +1,4 @@
import { registerSetter } from '@ali/lowcode-globals';
import { registerSetter, isJSSlot } from '@ali/lowcode-globals';
import { DatePicker, Input, Radio, Select, Switch, NumberPicker } from '@alifd/next';
import ExpressionSetter from './expression-setter';
import MixinSetter from './mixin-setter';
@ -10,12 +10,7 @@ import EventsSetter from './events-setter';
export const StringSetter = {
component: Input,
defaultProps: { placeholder: '请输入' },
title: 'StringSetter', // TODO
condition: (field: any) => {
const v = field.getValue();
return v == null || typeof v === 'string';
},
initialValue: '',
title: 'StringSetter',
recommend: true,
};
export const NumberSetter = NumberPicker;
@ -43,12 +38,38 @@ export const ClassNameSetter = () => {
return <div className="lc-block-setter"></div>;
};
const builtinSetters = {
export const SlotSetter = () => {
return <div> SlotSetter</div>;
};
const builtinSetters: any = {
StringSetter,
NumberSetter,
BoolSetter,
SelectSetter,
ExpressionSetter: ExpressionSetter as any,
ExpressionSetter: {
component: ExpressionSetter,
defaultProps: { placeholder: '请输入表达式' },
title: '表达式输入',
recommend: true,
},
SlotSetter: {
component: SlotSetter,
title: '插槽输入',
condition: (field: any) => {
return isJSSlot(field.getValue());
},
initialValue: (field: any, value: any) => {
if (isJSSlot(value)) {
return value;
}
return {
type: 'JSSlot',
value: value
};
},
recommend: true,
},
MixinSetter,
RadioGroupSetter,
TextAreaSetter,

View File

@ -1,5 +1,11 @@
import { ComponentType, ReactElement } from 'react';
import { ComponentMetadata, uniqueId, registerMetadataTransducer, FieldConfig } from '@ali/lowcode-globals';
import {
ComponentMetadata,
uniqueId,
registerMetadataTransducer,
FieldConfig,
InitialItem,
} from '@ali/lowcode-globals';
import { ComponentMeta, addBuiltinComponentAction, isComponentMeta } from '@ali/lowcode-designer';
import {
OldPropConfig,
@ -11,25 +17,41 @@ import {
} from './upgrade-metadata';
import { designer } from '../editor';
const GlobalPropsConfigure: Array<FieldConfig & { position: string }> = [];
const Overrides: any = {};
const GlobalPropsConfigure: Array<{ position: string; initials?: InitialItem[]; config: FieldConfig }> = [];
const Overrides: {
[componentName: string]: {
initials?: InitialItem[];
config: any;
};
} = {};
function addGlobalPropsConfigure(config: OldGlobalPropConfig) {
const initials: InitialItem[] = [];
GlobalPropsConfigure.push({
position: config.position,
...upgradePropConfig(config),
position: config.position || 'bottom',
initials,
config: upgradePropConfig(config, (item) => {
initials.push(item);
}),
});
}
function removeGlobalPropsConfigure(name: string) {
let l = GlobalPropsConfigure.length;
while (l-- > 0) {
if (GlobalPropsConfigure[l].name === name) {
if (GlobalPropsConfigure[l].config.name === name) {
GlobalPropsConfigure.splice(l, 1);
}
}
}
function overridePropsConfigure(componentName: string, config: OldPropConfig | OldPropConfig[]) {
Overrides[componentName] = Array.isArray(config) ? upgradeConfigure(config) : upgradePropConfig(config);
const initials: InitialItem[] = [];
const addInitial = (item: InitialItem) => {
initials.push(item);
};
Overrides[componentName] = {
initials,
config: Array.isArray(config) ? upgradeConfigure(config, addInitial) : upgradePropConfig(config, addInitial),
};
}
registerMetadataTransducer(
(metadata) => {
@ -49,28 +71,28 @@ registerMetadataTransducer(
metadata.configure.props = top = bottom = [];
}
GlobalPropsConfigure.forEach((config) => {
const position = config.position || 'bottom';
GlobalPropsConfigure.forEach((item) => {
const position = item.position || 'bottom';
if (position === 'top') {
top.unshift(config);
top.unshift(item.config);
} else if (position === 'bottom') {
bottom.push(config);
bottom.push(item.config);
}
});
const override = Overrides[componentName];
if (override) {
if (Array.isArray(override)) {
metadata.configure.combined = override;
if (Array.isArray(override.config)) {
metadata.configure.combined = override.config;
} else {
let l = top.length;
let item;
while (l-- > 0) {
item = top[l];
if (item.name in override) {
if (override[item.name]) {
top.splice(l, 1, override[item.name]);
if (override.config[item.name]) {
top.splice(l, 1, override.config[item.name]);
} else {
top.splice(l, 1);
}
@ -78,6 +100,8 @@ registerMetadataTransducer(
}
}
}
// TODO FIXME! append override & globalConfigure initials and then unique
return metadata;
},
100,

View File

@ -1,5 +1,5 @@
import { ComponentType, ReactElement, isValidElement, ComponentClass } from 'react';
import { isI18nData, SettingTarget } from '@ali/lowcode-globals';
import { isI18nData, SettingTarget, InitialItem, isPlainObject, isJSSlot, isJSExpression } from '@ali/lowcode-globals';
type Field = SettingTarget;
@ -34,8 +34,8 @@ export interface OldPropConfig {
url?: string;
};
defaultValue?: any; // => extraProps.defaultValue
initialValue?: any | ((value: any, defaultValue: any) => any); // => extraProps.initialValue
initial?: (value: any, defaultValue: any) => any // => extraProps.initialValue
initialValue?: any | ((value: any, defaultValue: any) => any); // => initials.initialValue
initial?: (value: any, defaultValue: any) => any // => initials.initialValue
display?: DISPLAY_TYPE; // => fieldExtraProps
fieldStyle?: DISPLAY_TYPE; // => fieldExtraProps
@ -175,7 +175,7 @@ type SetterGetter = (this: Field, value: any) => ComponentClass;
type ReturnBooleanFunction = (this: Field, value: any) => boolean;
export function upgradePropConfig(config: OldPropConfig) {
export function upgradePropConfig(config: OldPropConfig, addInitial: AddIntial) {
const {
type,
name,
@ -258,6 +258,7 @@ export function upgradePropConfig(config: OldPropConfig) {
extraProps.condition = (field: Field) => !(isHidden(field) || isDisabled(field));
}
if (ignore != null || disabled != null) {
// FIXME! addFilter
extraProps.virtual = (field: Field) => {
if (isDisabled(field)) { return true; }
@ -269,31 +270,7 @@ export function upgradePropConfig(config: OldPropConfig) {
}
if (type === 'group') {
newConfig.items = items ? upgradeConfigure(items) : [];
return newConfig;
}
if (slotName) {
newConfig.name = slotName;
if (!newConfig.title && slotTitle) {
newConfig.title = slotTitle;
}
const slotSetter = {
componentName: 'SlotSetter',
initialValue: () => ({
type: 'JSSlot',
value: initialChildren
}),
}
if (allowTextInput === false) {
newConfig.setter = slotSetter;
} else {
newConfig.setter = [{
componentName: 'StringSetter',
initialValue,
}, slotSetter];
}
newConfig.items = items ? upgradeConfigure(items, addInitial) : [];
return newConfig;
}
@ -303,29 +280,30 @@ export function upgradePropConfig(config: OldPropConfig) {
extraProps.defaultValue = initialValue;
}
let initialFn = initial || initialValue;
let initialFn = (slotName ? null : initial) || initialValue;
if (accessor) {
if (accessor && !slotName) {
extraProps.getValue = (field: Field, fieldValue: any) => {
return accessor.call(field, fieldValue);
};
if (!initialFn) {
// FIXME!
initialFn
initialFn = accessor;
}
}
extraProps.initialValue = (field: Field, currentValue: any, defaultValue?: any) => {
if (defaultValue === undefined) {
defaultValue = extraProps.defaultValue;
}
if (typeof initialFn === 'function') {
// ?
return initialFn.call(field, currentValue, defaultValue);
}
addInitial({
name: slotName || name,
initial: (field: Field, currentValue: any) => {
// FIXME! read from prototype.defaultProps
const defaults = extraProps.defaultValue;
return defaultValue;
};
if (typeof initialFn === 'function') {
return initialFn.call(field, currentValue, defaults);
}
return currentValue == null ? defaults : currentValue;
}
});
if (sync) {
extraProps.autorun = (field: Field) => {
@ -335,15 +313,61 @@ export function upgradePropConfig(config: OldPropConfig) {
}
}
}
if (mutator) {
if (mutator && !slotName) {
extraProps.setValue = (field: Field, value: any) => {
mutator.call(field, value);
};
}
if (slotName) {
newConfig.name = slotName;
if (!newConfig.title && slotTitle) {
newConfig.title = slotTitle;
}
const setters: any[] = [{
componentName: 'SlotSetter',
initialValue: (field: any, value: any) => {
if (isJSSlot(value)) {
return value;
}
return {
type: 'JSSlot',
value: value == null ? initialChildren : value
};
},
}];
if (allowTextInput !== false) {
setters.unshift('StringSetter');
// FIXME: use I18nSetter
}
if (supportVariable) {
setters.push('ExpressionSetter');
}
newConfig.setter = setters.length > 1 ? setters : setters[0];
return newConfig;
}
let primarySetter: any;
if (type === 'composite') {
const objItems = items ? upgradeConfigure(items) : [];
const initials: InitialItem[] = [];
const objItems = items ? upgradeConfigure(items, (item) => {
initials.push(item);
}) : [];
const initial = (target: SettingTarget, value?: any) => {
// TODO:
const defaults = extraProps.defaultValue;
const data: any = {};
initials.forEach(item => {
// FIXME! Target may be a wrong
data[item.name] = item.initial(target, isPlainObject(value) ? value[item.name] : null);
});
return data;
}
addInitial({
name,
initial,
});
primarySetter = {
componentName: 'ObjectSetter',
props: {
@ -352,12 +376,12 @@ export function upgradePropConfig(config: OldPropConfig) {
},
},
initialValue: (field: Field) => {
// FIXME: read from objItems
return extraProps.initialValue(field, {});
return initial(field, field.getValue());
},
};
} else if (setter) {
if (Array.isArray(setter)) {
// FIXME! read initial from setter
primarySetter = setter.map(({ setter, condition }) => {
return {
componentName: setter,
@ -393,7 +417,9 @@ export function upgradePropConfig(config: OldPropConfig) {
return newConfig;
}
export function upgradeConfigure(items: OldPropConfig[]) {
type AddIntial = (initialItem: InitialItem) => void;
export function upgradeConfigure(items: OldPropConfig[], addInitial: AddIntial) {
const configure: any[] = [];
let ignoreSlotName: any = null;
items.forEach((config) => {
@ -406,7 +432,7 @@ export function upgradeConfigure(items: OldPropConfig[]) {
}
ignoreSlotName = null;
}
configure.push(upgradePropConfig(config));
configure.push(upgradePropConfig(config, addInitial));
});
return configure;
}
@ -550,7 +576,10 @@ export function upgradeMetadata(oldConfig: OldPrototypeConfig) {
schema,
};
});
} else if (defaultProps || initialChildren) {
}
// FIXME! defaultProps for initial input
// initialChildren maybe a function
else if (defaultProps || initialChildren) {
const snippet = {
screenshot: icon,
label: title,
@ -566,6 +595,9 @@ export function upgradeMetadata(oldConfig: OldPrototypeConfig) {
experimental.snippets = [snippet];
}
}
if (initialChildren) {
experimental.initialChildren = initialChildren;
}
if (view) {
experimental.view = view;
}
@ -629,11 +661,17 @@ export function upgradeMetadata(oldConfig: OldPrototypeConfig) {
experimental.callbacks = callbacks;
const props = upgradeConfigure(configure || []);
const initials: InitialItem[] = [];
const props = upgradeConfigure(configure || [], (item) => {
initials.push(item);
});
experimental.initials = initials;
const events = {};
const styles = {};
meta.configure = { props, component, events, styles };
meta.experimental = experimental;
console.info(meta);
return meta;
}

View File

@ -1,5 +1,5 @@
import { designer } from './editor';
import { DragObjectType, isNode, ExportType } from '@ali/lowcode-designer';
import { DragObjectType, isNode, TransformStage } from '@ali/lowcode-designer';
const dragon = designer.dragon;
const DragEngine = {
@ -12,7 +12,7 @@ const DragEngine = {
if (isNode(r)) {
return {
type: DragObjectType.NodeData,
data: r.export(ExportType.ForSave),
data: r.export(TransformStage.Save),
};
// FIXME! designer has bug

View File

@ -1,6 +1,6 @@
import { globalContext } from '@ali/lowcode-globals';
import { globalContext, isPlainObject, isJSBlock } from '@ali/lowcode-globals';
import Editor from '@ali/lowcode-editor-core';
import { Designer } from '@ali/lowcode-designer';
import { Designer, TransformStage } from '@ali/lowcode-designer';
import { registerSetters } from '@ali/lowcode-setters';
import Outline from '@ali/lowcode-plugin-outline-pane';
import SettingsPane from '@ali/lowcode-plugin-settings-pane';
@ -10,6 +10,7 @@ import { Skeleton } from './skeleton/skeleton';
import Preview from '@ali/lowcode-plugin-sample-preview';
import SourceEditor from '@ali/lowcode-plugin-source-editor';
import { i18nReducer } from './i18n-reducer';
registerSetters();
@ -19,9 +20,54 @@ globalContext.register(editor, Editor);
export const skeleton = new Skeleton(editor);
editor.set(Skeleton, skeleton);
export const designer = new Designer({ eventPipe: editor });
export const designer = new Designer({ editor: editor });
editor.set(Designer, designer);
designer.addPropsReducer((props, node) => {
// run initials
const initials = node.componentMeta.getMetadata().experimental?.initials;
if (initials) {
const newProps: any = {};
initials.forEach((item) => {
// FIXME! this implements SettingTarget
const v = item.initial(node as any, props[item.name]);
if (v !== undefined) {
newProps[item.name] = v;
}
});
return newProps;
}
return props;
}, TransformStage.Init);
designer.addPropsReducer(i18nReducer, TransformStage.Render);
function upgradePropsReducer(props: any) {
if (!isPlainObject(props)) {
return props;
}
const newProps: any = {};
Object.entries<any>(props).forEach(([key, val]) => {
if (/^__slot__/.test(key) && val === true) {
return;
}
if (isJSBlock(val)) {
if (val.value.componentName === 'Slot') {
val = {
type: 'JSSlot',
title: (val.value.props as any)?.slotTitle,
value: val.value.children
};
} else {
val = val.value;
}
}
newProps[key] = val;
});
return newProps;
}
designer.addPropsReducer(upgradePropsReducer, TransformStage.Init);
skeleton.add({
area: 'mainArea',
name: 'designer',
@ -44,7 +90,6 @@ skeleton.add({
},
});
skeleton.add({
area: 'topArea',
type: 'Dock',

View File

@ -0,0 +1,35 @@
const I18nUtil = require('@ali/ve-i18n-util');
import Env from './env';
interface I18nObject {
type?: string;
use?: string;
key?: string;
[lang: string]: string | undefined;
}
export function i18nReducer(obj?: any): any {
if (!obj) { return obj; }
if (Array.isArray(obj)) {
return obj.map((item) => i18nReducer(item));
}
if (typeof obj === 'object') {
if (obj.type === 'i18n') {
// FIXME! use editor.get
let locale = Env.getLocale();
if (obj.key) {
return I18nUtil.get(obj.key, locale);
}
if (locale !== 'zh_CN' && locale !== 'zh_TW' && !obj[locale]) {
locale = 'en_US';
}
return obj[obj.use || locale] || obj.zh_CN;
}
const out: I18nObject = {};
Object.keys(obj).forEach((key) => {
out[key] = i18nReducer(obj[key]);
});
return out;
}
return obj;
}