diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts index eeded1e39..1e4740b80 100644 --- a/packages/designer/src/document/node/node.ts +++ b/packages/designer/src/document/node/node.ts @@ -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 { 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 { 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 { 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 { * @deprecated */ getSuitablePlace(node: Node, ref: any): any { + // TODO: if (this.isRoot()) { return { container: this, ref }; } diff --git a/packages/designer/src/document/node/props/prop-stash.ts b/packages/designer/src/document/node/props/prop-stash.ts index 0cf754f92..1c62617ef 100644 --- a/packages/designer/src/document/node/props/prop-stash.ts +++ b/packages/designer/src/document/node/props/prop-stash.ts @@ -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; diff --git a/packages/designer/src/document/node/props/prop.ts b/packages/designer/src/document/node/props/prop.ts index a96b45b03..fadbdbf8b 100644 --- a/packages/designer/src/document/node/props/prop.ts +++ b/packages/designer/src/document/node/props/prop.ts @@ -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 { diff --git a/packages/editor-preset-vision/src/bundle/upgrade-metadata.ts b/packages/editor-preset-vision/src/bundle/upgrade-metadata.ts index 79adb6db3..8931b7514 100644 --- a/packages/editor-preset-vision/src/bundle/upgrade-metadata.ts +++ b/packages/editor-preset-vision/src/bundle/upgrade-metadata.ts @@ -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) { diff --git a/packages/types/src/metadata.ts b/packages/types/src/metadata.ts index ac3bee227..6603686b5 100644 --- a/packages/types/src/metadata.ts +++ b/packages/types/src/metadata.ts @@ -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;