From 3f041b592b3dabad9a234bc6ce7544bb0953c156 Mon Sep 17 00:00:00 2001 From: "lihao.ylh" Date: Thu, 23 Dec 2021 20:46:04 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=A1=A5=E5=85=85=E4=B8=80=E6=B3=A2=20?= =?UTF-8?q?callbacks=20/=20hooks=20shell=20=E6=A8=A1=E5=9E=8B=E8=BD=AC?= =?UTF-8?q?=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/designer/src/component-meta.ts | 36 ++++++--- .../src/designer/setting/setting-field.ts | 3 +- .../designer/setting/setting-prop-entry.ts | 24 ++++-- .../src/components/settings/settings-pane.tsx | 78 +++++++++---------- packages/engine/src/engine-core.ts | 14 ++-- packages/shell/src/index.ts | 2 + packages/shell/src/node-children.ts | 10 ++- packages/shell/src/node.ts | 11 +++ packages/shell/src/project.ts | 2 +- packages/shell/src/setting-prop-entry.ts | 40 ++++++++++ packages/shell/src/setting-top-entry.ts | 34 ++++++++ packages/shell/src/symbols.ts | 4 +- packages/types/src/setting-target.ts | 5 ++ 13 files changed, 197 insertions(+), 66 deletions(-) create mode 100644 packages/shell/src/setting-prop-entry.ts create mode 100644 packages/shell/src/setting-top-entry.ts diff --git a/packages/designer/src/component-meta.ts b/packages/designer/src/component-meta.ts index d552b7777..f35e8f499 100644 --- a/packages/designer/src/component-meta.ts +++ b/packages/designer/src/component-meta.ts @@ -19,7 +19,16 @@ import EventEmitter from 'events'; import { isNode, Node, ParentalNode } from './document'; import { Designer } from './designer'; import { intlNode } from './locale'; -import { IconLock, IconUnlock, IconContainer, IconPage, IconComponent, IconRemove, IconClone, IconHidden } from './icons'; +import { + IconLock, + IconUnlock, + IconContainer, + IconPage, + IconComponent, + IconRemove, + IconClone, + IconHidden, +} from './icons'; function ensureAList(list?: string | string[]): string[] | null { if (!list) { @@ -183,10 +192,10 @@ export class ComponentMeta { this._title = typeof title === 'string' ? { - type: 'i18n', - 'en-US': this.componentName, - 'zh-CN': title, - } + type: 'i18n', + 'en-US': this.componentName, + 'zh-CN': title, + } : title; } @@ -265,7 +274,8 @@ export class ComponentMeta { // eslint-disable-next-line prefer-const let { disableBehaviors, actions } = this._transformedMetadata?.configure.component || {}; const disabled = - ensureAList(disableBehaviors) || (this.isRootComponent(false) ? ['copy', 'remove', 'lock', 'unlock'] : null); + ensureAList(disableBehaviors) || + (this.isRootComponent(false) ? ['copy', 'remove', 'lock', 'unlock'] : null); actions = builtinComponentActions.concat( this.designer.getGlobalComponentActions() || [], actions || [], @@ -291,7 +301,10 @@ export class ComponentMeta { checkNestingUp(my: Node | NodeData, parent: ParentalNode) { // 检查父子关系,直接约束型,在画布中拖拽直接掠过目标容器 if (this.parentWhitelist) { - return this.parentWhitelist(parent, my); + return this.parentWhitelist( + parent.internalToShellNode(), + isNode(my) ? my.internalToShellNode() : my, + ); } return true; } @@ -302,7 +315,10 @@ export class ComponentMeta { const _target: any = !Array.isArray(target) ? [target] : target; return _target.every((item: Node | NodeSchema) => { const _item = !isNode(item) ? new Node(my.document, item) : item; - return this.childWhitelist && this.childWhitelist(_item, my); + return ( + this.childWhitelist && + this.childWhitelist(_item.internalToShellNode(), my.internalToShellNode()) + ); }); } return true; @@ -484,7 +500,7 @@ const builtinComponentActions: ComponentAction[] = [ }, }, condition: (node: Node) => { - return (engineConfig.get('enableCanvasLock', false) && node.isContainer() && !node.isLocked); + return engineConfig.get('enableCanvasLock', false) && node.isContainer() && !node.isLocked; }, important: true, }, @@ -498,7 +514,7 @@ const builtinComponentActions: ComponentAction[] = [ }, }, condition: (node: Node) => { - return (engineConfig.get('enableCanvasLock', false) && node.isContainer() && node.isLocked); + return engineConfig.get('enableCanvasLock', false) && node.isContainer() && node.isLocked; }, important: true, }, diff --git a/packages/designer/src/designer/setting/setting-field.ts b/packages/designer/src/designer/setting/setting-field.ts index b57646333..95bf030be 100644 --- a/packages/designer/src/designer/setting/setting-field.ts +++ b/packages/designer/src/designer/setting/setting-field.ts @@ -44,7 +44,8 @@ export class SettingField extends SettingPropEntry implements SettingEntry { return null; } if (isDynamicSetter(this._setter)) { - return this._setter.call(this, this); + const shellThis = this.internalToShellPropEntry(); + return this._setter.call(shellThis, shellThis); } return this._setter; } diff --git a/packages/designer/src/designer/setting/setting-prop-entry.ts b/packages/designer/src/designer/setting/setting-prop-entry.ts index ae48bae1a..cd71d9655 100644 --- a/packages/designer/src/designer/setting/setting-prop-entry.ts +++ b/packages/designer/src/designer/setting/setting-prop-entry.ts @@ -1,6 +1,7 @@ import { obx, computed, makeObservable, runInAction } from '@ali/lowcode-editor-core'; import { GlobalEvent, IEditor, isJSExpression } from '@ali/lowcode-types'; import { uniqueId } from '@ali/lowcode-utils'; +import { SettingPropEntry as ShellSettingPropEntry } from '@ali/lowcode-shell'; import { SettingEntry } from './setting-entry'; import { Node } from '../../document'; import { ComponentMeta } from '../../component-meta'; @@ -124,7 +125,11 @@ export class SettingPropEntry implements SettingEntry { return runInAction(() => { if (this.type !== 'field') { const { getValue } = this.extraProps; - return getValue ? (getValue(this, undefined) === undefined ? 0 : 1) : 0; + return getValue + ? getValue(this.internalToShellPropEntry(), undefined) === undefined + ? 0 + : 1 + : 0; } if (this.nodes.length === 1) { return 2; @@ -160,7 +165,7 @@ export class SettingPropEntry implements SettingEntry { } const { getValue } = this.extraProps; try { - return getValue ? getValue(this, val) : val; + return getValue ? getValue(this.internalToShellPropEntry(), val) : val; } catch (e) { console.warn(e); return val; @@ -179,7 +184,7 @@ export class SettingPropEntry implements SettingEntry { const { setValue } = this.extraProps; if (setValue && !extraOptions?.disableMutator) { try { - setValue(this, val); + setValue(this.internalToShellPropEntry(), val); } catch (e) { /* istanbul ignore next */ console.warn(e); @@ -202,7 +207,7 @@ export class SettingPropEntry implements SettingEntry { const { setValue } = this.extraProps; if (setValue) { try { - setValue(this, undefined); + setValue(this.internalToShellPropEntry(), undefined); } catch (e) { /* istanbul ignore next */ console.warn(e); @@ -293,7 +298,12 @@ export class SettingPropEntry implements SettingEntry { } notifyValueChange(oldValue: any, newValue: any) { - this.editor.emit(GlobalEvent.Node.Prop.Change, { node: this.getNode(), prop: this, oldValue, newValue }); + this.editor.emit(GlobalEvent.Node.Prop.Change, { + node: this.getNode(), + prop: this, + oldValue, + newValue, + }); } getDefaultValue() { @@ -352,4 +362,8 @@ export class SettingPropEntry implements SettingEntry { } return v; } + + internalToShellPropEntry() { + return ShellSettingPropEntry.create(this) as any; + } } diff --git a/packages/editor-skeleton/src/components/settings/settings-pane.tsx b/packages/editor-skeleton/src/components/settings/settings-pane.tsx index d1fd3c21f..ee5fcdf78 100644 --- a/packages/editor-skeleton/src/components/settings/settings-pane.tsx +++ b/packages/editor-skeleton/src/components/settings/settings-pane.tsx @@ -40,7 +40,7 @@ class SettingFieldView extends Component<{ field: SettingField }> { let stageName; if (display === 'entry') { runInAction(() => { - stageName = `${field.getNode().id }_${field.name.toString()}`; + stageName = `${field.getNode().id}_${field.name.toString()}`; // 清除原 stage,不然 content 引用的一直是老的 field,导致数据无法得到更新 stages.container.remove(stageName); const stage = stages.add({ @@ -62,7 +62,7 @@ class SettingFieldView extends Component<{ field: SettingField }> { const { condition, defaultValue } = extraProps; let visible; try { - visible = typeof condition === 'function' ? condition(field) !== false : true; + visible = typeof condition === 'function' ? condition(field.internalToShellPropEntry()) !== false : true; } catch (error) { console.error('exception when condition (hidden) is excuted', error); } @@ -86,7 +86,7 @@ class SettingFieldView extends Component<{ field: SettingField }> { if (setter.props) { setterProps = setter.props; if (typeof setterProps === 'function') { - setterProps = setterProps(field); + setterProps = setterProps(field.internalToShellPropEntry()); } } if (setter.initialValue != null) { @@ -150,40 +150,40 @@ class SettingFieldView extends Component<{ field: SettingField }> { ...extraProps, }, !stageName && - createSetterContent(setterType, { - ...shallowIntl(setterProps), - forceInline: extraProps.forceInline, - key: field.id, - // === injection - prop: field, // for compatible vision - selected: field.top?.getNode(), - field, - // === IO - value, // reaction point - onChange: (value: any) => { - this.setState({ - // eslint-disable-next-line react/no-unused-state - value, - }); - field.setValue(value); - if (_onChange) _onChange(value, field); - }, - onInitial: () => { - if (initialValue == null) { - return; - } - const value = typeof initialValue === 'function' ? initialValue(field) : initialValue; - this.setState({ - // eslint-disable-next-line react/no-unused-state - value, - }); - field.setValue(value); - }, + createSetterContent(setterType, { + ...shallowIntl(setterProps), + forceInline: extraProps.forceInline, + key: field.id, + // === injection + prop: field.internalToShellPropEntry(), // for compatible vision + selected: field.top?.getNode()?.internalToShellNode(), + field: field.internalToShellPropEntry(), + // === IO + value, // reaction point + onChange: (value: any) => { + this.setState({ + // eslint-disable-next-line react/no-unused-state + value, + }); + field.setValue(value); + if (_onChange) _onChange(value, field); + }, + onInitial: () => { + if (initialValue == null) { + return; + } + const value = typeof initialValue === 'function' ? initialValue(field.internalToShellPropEntry()) : initialValue; + this.setState({ + // eslint-disable-next-line react/no-unused-state + value, + }); + field.setValue(value); + }, - removeProp: () => { - field.parent.clearPropValue(field.name); - }, - }), + removeProp: () => { + field.parent.clearPropValue(field.name); + }, + }), extraProps.forceInline ? 'plain' : extraProps.display, ); } @@ -200,7 +200,7 @@ class SettingGroupView extends Component { super(props); const { field } = this.props; const { extraProps } = field; - const { condition, display } = extraProps; + const { display } = extraProps; const { stages } = field.editor.get('skeleton') as Skeleton; // const items = field.items; @@ -208,7 +208,7 @@ class SettingGroupView extends Component { let stageName; if (display === 'entry') { runInAction(() => { - stageName = `${field.getNode().id }_${field.name.toString()}`; + stageName = `${field.getNode().id}_${field.name.toString()}`; // 清除原 stage,不然 content 引用的一直是老的 field,导致数据无法得到更新 stages.container.remove(stageName); stages.add({ @@ -228,7 +228,7 @@ class SettingGroupView extends Component { const { field } = this.props; const { extraProps } = field; const { condition, display } = extraProps; - const visible = field.isSingle && typeof condition === 'function' ? condition(field) !== false : true; + const visible = field.isSingle && typeof condition === 'function' ? condition(field.internalToShellPropEntry()) !== false : true; if (!visible) { return null; diff --git a/packages/engine/src/engine-core.ts b/packages/engine/src/engine-core.ts index dde8db223..396283e8f 100644 --- a/packages/engine/src/engine-core.ts +++ b/packages/engine/src/engine-core.ts @@ -24,12 +24,10 @@ import { designerSymbol, skeletonSymbol, } from '@ali/lowcode-shell'; -import { getLogger, Logger } from '@ali/lowcode-utils'; +import { getLogger, Logger, isPlainObject } from '@ali/lowcode-utils'; import './modules/live-editing'; -import { isPlainObject } from '@ali/lowcode-utils'; import utils from './modules/utils'; - export * from './modules/editor-types'; export * from './modules/skeleton-types'; export * from './modules/designer-types'; @@ -71,12 +69,12 @@ const event = new Event(editor, { prefix: 'common' }); const logger = getLogger({ level: 'warn', bizName: 'common' }); export { - editor, - editorCabin, + // editor, + // editorCabin, // skeleton, - skeletonCabin, - designer, - designerCabin, + // skeletonCabin, + // designer, + // designerCabin, plugins, // setters, project, diff --git a/packages/shell/src/index.ts b/packages/shell/src/index.ts index 073b62b8c..3b1338e51 100644 --- a/packages/shell/src/index.ts +++ b/packages/shell/src/index.ts @@ -11,6 +11,7 @@ import Selection from './selection'; import Setters from './setters'; import Hotkey from './hotkey'; import Skeleton from './skeleton'; +import SettingPropEntry from './setting-prop-entry'; export * from './symbols'; /** @@ -33,4 +34,5 @@ export { Setters, Hotkey, Skeleton, + SettingPropEntry, }; \ No newline at end of file diff --git a/packages/shell/src/node-children.ts b/packages/shell/src/node-children.ts index 03733efdf..68c1aba03 100644 --- a/packages/shell/src/node-children.ts +++ b/packages/shell/src/node-children.ts @@ -1,5 +1,5 @@ import { NodeChildren as InnerNodeChildren, Node as InnerNode } from '@ali/lowcode-designer'; -import { NodeSchema } from '@ali/lowcode-types'; +import { NodeSchema, NodeData, TransformStage } from '@ali/lowcode-types'; import Node from './node'; import { nodeSymbol, nodeChildrenSymbol } from './symbols'; @@ -97,6 +97,14 @@ export default class NodeChildren { }, initialValue); } + importSchema(data?: NodeData | NodeData[]) { + this[nodeChildrenSymbol].import(data); + } + + exportSchema(stage?: TransformStage) { + return this[nodeChildrenSymbol].export(stage); + } + mergeChildren( remover: (node: Node, idx: number) => boolean, adder: (children: Node[]) => any, diff --git a/packages/shell/src/node.ts b/packages/shell/src/node.ts index 0fb4e7bd3..267004db8 100644 --- a/packages/shell/src/node.ts +++ b/packages/shell/src/node.ts @@ -146,6 +146,17 @@ export default class Node { return this.children; } + /** + * @deprecated + */ + getDOMNode() { + return this[nodeSymbol].getDOMNode(); + } + + getRect() { + return this[nodeSymbol].getRect(); + } + hasSlots() { return this[nodeSymbol].hasSlots(); } diff --git a/packages/shell/src/project.ts b/packages/shell/src/project.ts index 1a367cd73..dd72bfb6d 100644 --- a/packages/shell/src/project.ts +++ b/packages/shell/src/project.ts @@ -35,7 +35,7 @@ export default class Project { } /** - * @deprecated use simulatorHost instead. + * @deprecated use .simulatorHost instead. */ get simulator() { return this.simulatorHost; diff --git a/packages/shell/src/setting-prop-entry.ts b/packages/shell/src/setting-prop-entry.ts new file mode 100644 index 000000000..8236cf321 --- /dev/null +++ b/packages/shell/src/setting-prop-entry.ts @@ -0,0 +1,40 @@ +import { SettingEntry } from '@ali/lowcode-designer'; +import { CompositeValue, SettingTarget } from '@ali/lowcode-types'; +import { settingPropEntrySymbol } from './symbols'; +import Node from './node'; +import SettingTopEntry from './setting-top-entry'; + +export default class SettingPropEntry { + private readonly [settingPropEntrySymbol]: SettingEntry; + + constructor(prop: SettingEntry) { + this[settingPropEntrySymbol] = prop; + } + + static create(prop: SettingEntry) { + return new SettingPropEntry(prop); + } + + get node(): Node | null { + return Node.create(this[settingPropEntrySymbol].getNode()); + } + + /** + * @deprecated use .node instead + */ + getNode() { + return this.node; + } + + setValue(val: CompositeValue) { + this[settingPropEntrySymbol].setValue(val); + } + + getValue() { + return this[settingPropEntrySymbol].getValue(); + } + + getProps() { + return SettingTopEntry.create(this[settingPropEntrySymbol].getProps() as SettingEntry) as any; + } +} \ No newline at end of file diff --git a/packages/shell/src/setting-top-entry.ts b/packages/shell/src/setting-top-entry.ts new file mode 100644 index 000000000..1d3f57a14 --- /dev/null +++ b/packages/shell/src/setting-top-entry.ts @@ -0,0 +1,34 @@ +import { SettingEntry } from '@ali/lowcode-designer'; +import { settingTopEntrySymbol } from './symbols'; +import Node from './node'; + +export default class SettingTopEntry { + private readonly [settingTopEntrySymbol]: SettingEntry; + + constructor(prop: SettingEntry) { + this[settingTopEntrySymbol] = prop; + } + + static create(prop: SettingEntry) { + return new SettingTopEntry(prop); + } + + get node(): Node | null { + return Node.create(this[settingTopEntrySymbol].getNode()); + } + + /** + * @deprecated use .node instead + */ + getNode() { + return this.node; + } + + getPropValue(propName: string | number) { + return this[settingTopEntrySymbol].getPropValue(propName); + } + + setPropValue(propName: string | number, value: any) { + this[settingTopEntrySymbol].setPropValue(propName, value); + } +} \ No newline at end of file diff --git a/packages/shell/src/symbols.ts b/packages/shell/src/symbols.ts index 94dac51ed..814807a99 100644 --- a/packages/shell/src/symbols.ts +++ b/packages/shell/src/symbols.ts @@ -8,8 +8,10 @@ export const documentSymbol = Symbol('document'); export const editorSymbol = Symbol('editor'); export const nodeSymbol = Symbol('node'); export const nodeChildrenSymbol = Symbol('nodeChildren'); -export const propsSymbol = Symbol('props'); export const propSymbol = Symbol('prop'); +export const settingPropEntrySymbol = Symbol('settingPropEntry'); +export const settingTopEntrySymbol = Symbol('settingTopEntry'); +export const propsSymbol = Symbol('props'); export const detectingSymbol = Symbol('detecting'); export const selectionSymbol = Symbol('selection'); export const historySymbol = Symbol('history'); diff --git a/packages/types/src/setting-target.ts b/packages/types/src/setting-target.ts index 917225eb5..9d2a3b1fa 100644 --- a/packages/types/src/setting-target.ts +++ b/packages/types/src/setting-target.ts @@ -52,6 +52,11 @@ export interface SettingTarget { */ get: (propName: string | number) => SettingTarget | null; + /** + * 取得子项 + */ + getProps?: () => SettingTarget; + /** * 获取子项属性值 */