feat: support prop.autorun

This commit is contained in:
kangwei 2020-05-28 17:35:17 +08:00
parent 8f1a9de33b
commit c0a523584e
5 changed files with 100 additions and 35 deletions

View File

@ -1,4 +1,4 @@
import { obx, computed } from '@ali/lowcode-editor-core';
import { obx, computed, autorun } from '@ali/lowcode-editor-core';
import {
isDOMText,
isJSExpression,
@ -155,17 +155,29 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
this._children = new NodeChildren(this as ParentalNode, this.initialChildren(children));
this._children.interalInitParent();
this.props.import(this.transformProps(props || {}), extras);
this.setupAutoruns();
}
}
private transformProps(props: any): any {
// FIXME! support PropsList
const x = this.document.designer.transformProps(props, this, TransformStage.Init);
return x;
return this.document.designer.transformProps(props, this, TransformStage.Init);
// TODO: run transducers in metadata.experimental
}
private autoruns?: Array<() => void>;
private setupAutoruns() {
const autoruns = this.componentMeta.getMetadata().experimental?.autoruns;
if (!autoruns || autoruns.length < 1) {
return;
}
this.autoruns = autoruns.map(item => {
return autorun(() => {
item.autorun(this.props.get(item.name, true) as any)
}, true);
});
}
private initialChildren(children: any): NodeData[] {
// FIXME! this is dirty code
if (children == null) {
@ -591,6 +603,7 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
if (this.isParental()) {
this.children.purge();
}
this.autoruns?.forEach(dispose => dispose());
this.props.purge();
this.document.internalRemoveAndPurgeNode(this);
}
@ -608,7 +621,16 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
insertBefore(node: Node, ref?: Node) {
this.children?.insert(node, ref ? ref.index : null);
}
insertAfter(node: Node, ref?: Node) {
insertAfter(node: any, ref?: Node) {
if (!isNode(node)) {
if (node.getComponentName) {
node = this.document.createNode({
componentName: node.getComponentName(),
});
} else {
node = this.document.createNode(node);
}
}
this.children?.insert(node, ref ? ref.index + 1 : null);
}
getParent() {
@ -687,6 +709,7 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
* @deprecated
*/
getSuitablePlace(node: Node, ref: any): any {
// TODO:
if (this.isRoot()) {
return { container: this, ref };
}

View File

@ -1,6 +1,7 @@
import { obx, autorun, untracked, computed } from '@ali/lowcode-editor-core';
import { Prop, IPropParent, UNSET } from './prop';
import { Props } from './props';
import { Node } from '../node';
export type PendingItem = Prop[];
export class PropStash implements IPropParent {
@ -15,8 +16,10 @@ export class PropStash implements IPropParent {
return maps;
}
private willPurge: () => void;
readonly owner: Node;
constructor(readonly props: Props, write: (item: Prop) => void) {
this.owner = props.owner;
this.willPurge = autorun(() => {
if (this.space.size < 1) {
return;

View File

@ -4,7 +4,7 @@ import { uniqueId, isPlainObject, hasOwnProperty } from '@ali/lowcode-utils';
import { PropStash } from './prop-stash';
import { valueToSource } from './value-to-source';
import { Props } from './props';
import { SlotNode } from '../node';
import { SlotNode, Node } from '../node';
import { TransformStage } from '../transform-stage';
export const UNSET = Symbol.for('unset');
@ -13,12 +13,14 @@ export type UNSET = typeof UNSET;
export interface IPropParent {
delete(prop: Prop): void;
readonly props: Props;
readonly owner: Node;
}
export type ValueTypes = 'unset' | 'literal' | 'map' | 'list' | 'expression' | 'slot';
export class Prop implements IPropParent {
readonly isProp = true;
readonly owner: Node;
/**
* @see SettingTarget
@ -350,6 +352,7 @@ export class Prop implements IPropParent {
key?: string | number,
spread = false,
) {
this.owner = parent.owner;
this.props = parent.props;
if (value !== UNSET) {
this.setValue(value);
@ -613,6 +616,10 @@ export class Prop implements IPropParent {
getProps() {
return this.parent;
}
getNode() {
return this.owner;
}
}
export function isProp(obj: any): obj is Prop {

View File

@ -1,6 +1,7 @@
import { ComponentType, ReactElement, isValidElement, ComponentClass } from 'react';
import { isPlainObject } from '@ali/lowcode-utils';
import { isI18nData, SettingTarget, InitialItem, FilterItem, isJSSlot, isJSExpression } from '@ali/lowcode-types';
import { isI18nData, SettingTarget, InitialItem, FilterItem, isJSSlot, isJSExpression, AutorunItem } from '@ali/lowcode-types';
import { untracked } from '@ali/lowcode-editor-core';
type Field = SettingTarget;
@ -290,19 +291,44 @@ export function upgradePropConfig(config: OldPropConfig, collector: ConfigCollec
};
}
if (accessor && !slotName) {
extraProps.getValue = (field: Field, fieldValue: any) => {
return accessor.call(field, fieldValue);
};
if (!initialFn) {
initialFn = accessor;
if (!slotName) {
if (accessor) {
extraProps.getValue = (field: Field, fieldValue: any) => {
return accessor.call(field, fieldValue);
};
}
if (sync || accessor) {
collector.addAutorun({
name,
autorun: (field: Field) => {
let fieldValue = untracked(() => field.getValue());
if (accessor) {
fieldValue = accessor.call(field, fieldValue)
}
if (sync) {
fieldValue = sync.call(field, fieldValue);
if (fieldValue !== undefined) {
field.setValue(fieldValue);
}
} else {
field.setValue(fieldValue);
}
}
});
}
if (mutator) {
extraProps.setValue = (field: Field, value: any) => {
mutator.call(field, value, value);
};
}
}
const setterInitial = getInitialFromSetter(setter);
collector.addInitial({
// FIXME! name should be "xxx.xxx"
// FIXME! name could be "xxx.xxx"
name: slotName || name,
initial: (field: Field, currentValue: any) => {
// FIXME! read from prototype.defaultProps
@ -345,20 +371,6 @@ export function upgradePropConfig(config: OldPropConfig, collector: ConfigCollec
});
}
if (sync) {
extraProps.autorun = (field: Field) => {
const value = sync.call(field, field.getValue());
if (value !== undefined) {
field.setValue(value);
}
};
}
if (mutator && !slotName) {
extraProps.setValue = (field: Field, value: any) => {
mutator.call(field, value, value);
};
}
if (slotName) {
newConfig.name = slotName;
if (!newConfig.title && slotTitle) {
@ -396,7 +408,6 @@ export function upgradePropConfig(config: OldPropConfig, collector: ConfigCollec
let primarySetter: any;
if (type === 'composite') {
const initials: InitialItem[] = [];
const filters: FilterItem[] = [];
const objItems = items
? upgradeConfigure(items,
{
@ -404,8 +415,17 @@ export function upgradePropConfig(config: OldPropConfig, collector: ConfigCollec
initials.push(item);
},
addFilter: (item) => {
filters.push(item);
}
collector.addFilter({
name: `${name}.${item.name}`,
filter: item.filter,
});
},
addAutorun: (item) => {
collector.addAutorun({
name: `${name}.${item.name}`,
autorun: item.autorun,
});
},
}
)
: [];
@ -481,10 +501,12 @@ export function upgradePropConfig(config: OldPropConfig, collector: ConfigCollec
type AddInitial = (initialItem: InitialItem) => void;
type AddFilter = (filterItem: FilterItem) => void;
type AddAutorun = (autorunItem: AutorunItem) => void;
type ConfigCollector = {
addInitial: AddInitial,
addFilter: AddFilter,
addInitial: AddInitial;
addFilter: AddFilter;
addAutorun: AddAutorun;
}
function getInitialFromSetter(setter: any) {
@ -750,6 +772,7 @@ export function upgradeMetadata(oldConfig: OldPrototypeConfig) {
const initials: InitialItem[] = [];
const filters: FilterItem[] = [];
const autoruns: AutorunItem[] = [];
const props = upgradeConfigure(configure || [],
{
addInitial: (item) => {
@ -758,10 +781,14 @@ export function upgradeMetadata(oldConfig: OldPrototypeConfig) {
addFilter: (item) => {
filters.push(item);
},
addAutorun: (item) => {
autoruns.push(item);
}
}
);
experimental.initials = initials;
experimental.filters = filters;
experimental.autoruns = autoruns;
const supports: any = {};
if (canUseCondition != null) {

View File

@ -49,6 +49,11 @@ export interface FilterItem {
name: string;
filter: (target: SettingTarget, currentValue: any) => any;
}
export interface AutorunItem {
name: string;
autorun: (target: SettingTarget) => any;
}
export interface Experimental {
context?: { [contextInfoName: string]: any };
@ -57,8 +62,8 @@ export interface Experimental {
transducers?: any; // ? should support
initials?: InitialItem[];
filters?: FilterItem[];
autoruns?: AutorunItem[];
callbacks?: Callbacks;
// TODO: thinkof function
initialChildren?: NodeData[] | ((target: SettingTarget) => NodeData[]);
// 样式 及 位置handle上必须有明确的标识以便事件路由判断或者主动设置事件独占模式
@ -85,7 +90,7 @@ export interface Experimental {
liveTextEditing?: LiveTextEditingConfig[];
}
// thinkof Array
// thinkof Array
export interface LiveTextEditingConfig {
propTarget: string;
selector?: string;