From 73e6e22e577b1bfbff73f8c12560d7ad029e7468 Mon Sep 17 00:00:00 2001 From: kangwei Date: Thu, 16 Apr 2020 17:50:20 +0800 Subject: [PATCH] enhance di --- packages/designer/src/component-meta.ts | 2 + packages/designer/src/designer/designer.ts | 4 +- packages/editor-core/src/editor.ts | 146 ++++++++++-------- packages/globals/src/types/metadata.ts | 15 +- packages/plugin-outline-pane/src/main.ts | 12 +- packages/plugin-sample-preview/src/index.tsx | 8 +- packages/plugin-settings-pane/src/main.ts | 19 +-- packages/plugin-undo-redo/src/index.tsx | 21 +-- .../src/bundle/upgrade-metadata.ts | 73 ++++++--- packages/vision-polyfill/src/editor.ts | 2 +- .../src/skeleton/workbench.less | 6 +- 11 files changed, 172 insertions(+), 136 deletions(-) diff --git a/packages/designer/src/component-meta.ts b/packages/designer/src/component-meta.ts index 4378fe013..e3625c29d 100644 --- a/packages/designer/src/component-meta.ts +++ b/packages/designer/src/component-meta.ts @@ -200,6 +200,7 @@ export class ComponentMeta { } checkNestingUp(my: Node | NodeData, parent: NodeParent) { + // 检查父子关系,直接约束型,在画布中拖拽直接掠过目标容器 if (this.parentWhitelist) { return this.parentWhitelist.includes(parent.componentName); } @@ -207,6 +208,7 @@ export class ComponentMeta { } checkNestingDown(my: Node, target: Node | NodeSchema) { + // 检查父子关系,直接约束型,在画布中拖拽直接掠过目标容器 if (this.childWhitelist) { return this.childWhitelist.includes(target.componentName); } diff --git a/packages/designer/src/designer/designer.ts b/packages/designer/src/designer/designer.ts index 1c2e520b5..4872db718 100644 --- a/packages/designer/src/designer/designer.ts +++ b/packages/designer/src/designer/designer.ts @@ -138,11 +138,11 @@ export class Designer { historyDispose(); historyDispose = undefined; } - this.postEvent('history-change', this.currentHistory); + this.postEvent('history.change', this.currentHistory); if (this.currentHistory) { const currentHistory = this.currentHistory; historyDispose = currentHistory.onStateChange(() => { - this.postEvent('history-change', currentHistory); + this.postEvent('history.change', currentHistory); }); } }; diff --git a/packages/editor-core/src/editor.ts b/packages/editor-core/src/editor.ts index 7cf2f1344..dedb944f7 100644 --- a/packages/editor-core/src/editor.ts +++ b/packages/editor-core/src/editor.ts @@ -82,6 +82,58 @@ export default class Editor extends EventEmitter { instance = this; } + get(keyOrType: KeyOrType, opt?: GetOptions): GetReturnType | undefined { + const x = this.context.get(keyOrType, opt); + if (x === NOT_FOUND) { + return undefined; + } + return x; + } + + has(keyOrType: KeyType): boolean { + return this.context.has(keyOrType); + } + + set(key: KeyType, data: any): void { + if (this.context.has(key)) { + this.context.replace(key, data, undefined, true); + } else { + this.context.register(data, key); + } + this.notifyGot(key); + } + + onceGot(keyOrType: KeyOrType): Promise> { + const x = this.context.get(keyOrType); + if (x !== NOT_FOUND) { + return Promise.resolve(x); + } + return new Promise((resolve) => { + this.setWait(keyOrType, resolve, true); + }); + } + + onGot( + keyOrType: KeyOrType, + fn: (data: GetReturnType) => void, + ): () => void { + const x = this.context.get(keyOrType); + if (x !== NOT_FOUND) { + fn(x); + return () => {}; + } else { + this.setWait(keyOrType, fn); + return () => { + this.delWait(keyOrType, fn); + }; + } + } + + register(data: any, key?: KeyType, options?: RegisterOptions): void { + this.context.register(data, key, options); + this.notifyGot(key || data); + } + async init(): Promise { const { hooks, shortCuts = [], lifeCycles } = this.config || {}; this.locale = store.get('lowcode-editor-locale') || 'zh-CN'; @@ -115,25 +167,31 @@ export default class Editor extends EventEmitter { } } - get(keyOrType: KeyOrType, opt?: GetOptions): GetReturnType | undefined { - const x = this.context.get(keyOrType, opt); - if (x === NOT_FOUND) { - return undefined; + batchOn(events: string[], lisenter: (...args: any[]) => void): void { + if (!Array.isArray(events)) { + return; } - return x; + events.forEach((event): void => { + this.on(event, lisenter); + }); } - has(keyOrType: KeyType): boolean { - return this.context.has(keyOrType); + batchOnce(events: string[], lisenter: (...args: any[]) => void): void { + if (!Array.isArray(events)) { + return; + } + events.forEach((event): void => { + this.once(event, lisenter); + }); } - set(key: KeyType, data: any): void { - if (this.context.has(key)) { - this.context.replace(key, data, undefined, true); - } else { - this.context.register(data, key); + batchOff(events: string[], lisenter: (...args: any[]) => void): void { + if (!Array.isArray(events)) { + return; } - this.notifyGot(key); + events.forEach((event): void => { + this.off(event, lisenter); + }); } private waits = new Map< @@ -172,62 +230,20 @@ export default class Editor extends EventEmitter { } } - onceGot(keyOrType: KeyOrType): Promise> { - const x = this.context.get(keyOrType); - if (x !== NOT_FOUND) { - return Promise.resolve(x); - } - return new Promise((resolve) => { - this.setWait(keyOrType, resolve, true); - }); - } - - onGot( - keyOrType: KeyOrType, - fn: (data: GetReturnType) => void, - ): () => void { - const x = this.context.get(keyOrType); - if (x !== NOT_FOUND) { - fn(x); - return () => {}; - } else { - this.setWait(keyOrType, fn); - return () => { - - }; - } - } - - register(data: any, key?: KeyType, options?: RegisterOptions): void { - this.context.register(data, key, options); - this.notifyGot(key || data); - } - - batchOn(events: string[], lisenter: (...args: any[]) => void): void { - if (!Array.isArray(events)) { + private delWait(key: KeyType, fn: any) { + const waits = this.waits.get(key); + if (!waits) { return; } - events.forEach((event): void => { - this.on(event, lisenter); - }); - } - - batchOnce(events: string[], lisenter: (...args: any[]) => void): void { - if (!Array.isArray(events)) { - return; + let i = waits.length; + while (i--) { + if (waits[i].resolve === fn) { + waits.splice(i, 1); + } } - events.forEach((event): void => { - this.once(event, lisenter); - }); - } - - batchOff(events: string[], lisenter: (...args: any[]) => void): void { - if (!Array.isArray(events)) { - return; + if (waits.length < 1) { + this.waits.delete(key); } - events.forEach((event): void => { - this.off(event, lisenter); - }); } // 销毁hooks中的消息监听 diff --git a/packages/globals/src/types/metadata.ts b/packages/globals/src/types/metadata.ts index d0e36270c..484a607e2 100644 --- a/packages/globals/src/types/metadata.ts +++ b/packages/globals/src/types/metadata.ts @@ -6,11 +6,18 @@ import { PropConfig } from './prop-config'; import { NpmInfo } from './npm'; import { FieldConfig } from './field-config'; +export type NestingFilter = (which: any, my: any) => boolean; export interface NestingRule { - childWhitelist?: string[]; - parentWhitelist?: string[]; - descendantBlacklist?: string[]; - ancestorWhitelist?: string[]; + // 子级白名单 + childWhitelist?: string[] | string | RegExp | NestingFilter; + // 父级白名单 + parentWhitelist?: string[] | string | RegExp | NestingFilter; + // 后裔白名单 + descendantWhitelist?: string[] | string | RegExp | NestingFilter; + // 后裔黑名单 + descendantBlacklist?: string[] | string | RegExp | NestingFilter; + // 祖先白名单 可用来做区域高亮 + ancestorWhitelist?: string[] | string | RegExp | NestingFilter; } export interface ComponentConfigure { diff --git a/packages/plugin-outline-pane/src/main.ts b/packages/plugin-outline-pane/src/main.ts index 4a543c2b0..d603acff7 100644 --- a/packages/plugin-outline-pane/src/main.ts +++ b/packages/plugin-outline-pane/src/main.ts @@ -133,19 +133,13 @@ export class OutlineMain implements ISensor, IScrollBoard, IScrollable { private fixed = false; constructor(readonly editor: Editor, at?: string) { let inited = false; - const setup = () => { + const setup = async () => { if (inited) { return false; } inited = true; - const designer = editor.get(Designer); - if (designer) { - this.setupDesigner(designer); - } else { - editor.once('designer.mount', (designer: Designer) => { - this.setupDesigner(designer); - }); - } + const designer = await editor.onceGot(Designer); + this.setupDesigner(designer); }; // FIXME: dirty connect to others diff --git a/packages/plugin-sample-preview/src/index.tsx b/packages/plugin-sample-preview/src/index.tsx index 75aef5284..ff2c2e06e 100644 --- a/packages/plugin-sample-preview/src/index.tsx +++ b/packages/plugin-sample-preview/src/index.tsx @@ -7,9 +7,11 @@ import './index.scss'; const SamplePreview = ({ editor }: PluginProps) => { const handleClick = () => { const designer = editor.get(Designer); - console.info('save schema:', designer.schema); - localStorage.setItem('lce-dev-store', JSON.stringify(designer.schema)); - window.open('./preview.html', 'preview'); + if (designer) { + console.info('save schema:', designer.schema); + localStorage.setItem('lce-dev-store', JSON.stringify(designer.schema)); + window.open('./preview.html', 'preview'); + } }; return ( diff --git a/packages/plugin-settings-pane/src/main.ts b/packages/plugin-settings-pane/src/main.ts index 8fd66589b..2ce6f55a4 100644 --- a/packages/plugin-settings-pane/src/main.ts +++ b/packages/plugin-settings-pane/src/main.ts @@ -339,21 +339,16 @@ export class SettingsMain implements SettingTarget { } }; editor.on('designer.selection.change', setupSelection); - const connectTree = (designer: any) => { - getTreeMaster(designer).onceEnableBuiltin(() => { - this.emitter.emit('outline-visible'); - }); - } - const designer = editor.get(Designer); - if (designer) { - connectTree(designer); - setupSelection(designer.currentSelection); - } else { - editor.once('designer.mount', connectTree); - } this.disposeListener = () => { editor.removeListener('designer.selection.change', setupSelection); }; + (async () => { + const designer = await editor.onceGot(Designer); + getTreeMaster(designer).onceEnableBuiltin(() => { + this.emitter.emit('outline-visible'); + }); + setupSelection(designer.currentSelection); + })(); } onEffect(action: () => void): () => void { diff --git a/packages/plugin-undo-redo/src/index.tsx b/packages/plugin-undo-redo/src/index.tsx index 358474afb..945b62490 100644 --- a/packages/plugin-undo-redo/src/index.tsx +++ b/packages/plugin-undo-redo/src/index.tsx @@ -30,25 +30,18 @@ export default class UndoRedo extends PureComponent< }; } - componentDidMount(): void { + async componentDidMount() { const { editor } = this.props; - editor.on('designer.history-change', this.handleHistoryChange); + editor.on('designer.history.change', this.handleHistoryChange); - const designer = editor.get(Designer); - if (designer) { - this.history = designer.currentHistory; - this.updateState(this.history?.getState() || 0); - } else { - editor.once('designer.ready', (): void => { - this.history = editor.get(Designer)?.currentHistory; - this.updateState(this.history?.getState() || 0); - }); - } + const designer = await editor.onceGot(Designer); + this.history = designer.currentHistory; + this.updateState(this.history?.getState() || 0); } componentWillUnmount(): void { const { editor } = this.props; - editor.off('designer.history-change', this.handleHistoryChange); + editor.off('designer.history.change', this.handleHistoryChange); } handleHistoryChange = (history: any): void => { @@ -62,7 +55,7 @@ export default class UndoRedo extends PureComponent< this.history = editor.get(Designer)?.currentHistory; this.updateState(this.history?.getState() || 0); - editor.on('designer.history-change', (history: any): void => { + editor.on('designer.history.change', (history: any): void => { this.history = history; this.updateState(this.history?.getState() || 0); }); diff --git a/packages/vision-polyfill/src/bundle/upgrade-metadata.ts b/packages/vision-polyfill/src/bundle/upgrade-metadata.ts index 8472a38ea..8f97ab236 100644 --- a/packages/vision-polyfill/src/bundle/upgrade-metadata.ts +++ b/packages/vision-polyfill/src/bundle/upgrade-metadata.ts @@ -35,11 +35,11 @@ export type HandleState = REJECTED | ALLOWED | LIMITED; * model.locate: (my, transferData, mouseEvent?) => Location | null, 用于非 node 节点任意数据的定位 * * test-RegExp: /^tagName./ - * test-Pattern: 'tagName,tagName2,Field-*' + * test-List: 'tagName,tagName2' | ['tagName', 'tagName2'] * test-Func: (target, my) => boolean - * Tester: RegExp | Pattern | Func | { exclude: Tester, include: Tester } + * Tester: RegExp | Pattern | Func * - * model.accept + * component.accept * accept: '@CHILD',从子节点寻找一个容器,针对 slot,比如 TabsLayout,ColumnsLayout, 大纲树误定位则错误信息透出,拒绝投入 * accept: false|null 表示不是一个容器,是一个端点,比如input,option * accept: true 表示ok,无任何限制,比如 div, @@ -66,7 +66,6 @@ export type HandleState = REJECTED | ALLOWED | LIMITED; * 4. Li 拖拽时高亮所有 UL,根据Li设置的 dropTargetRules 目标规则筛选节点,取并集区域 * 5. 能弹出提示 * - * 父级接受 & 定位:默认值 */ @@ -94,7 +93,7 @@ export interface AcceptControl { * KeyboardEvent: paste a entiy * LocateEvent: drag a entiy from pane */ - accept?: AcceptFunc | AT_CHILD; + handleLocate?: AcceptFunc | AT_CHILD; handleAccept?: (my: ElementNode, locationData: LocationData) => void; } @@ -242,37 +241,35 @@ function upgradeMetadata(oldConfig: OldPrototypeConfig) { icon, packageName, category, - defaultProps, extraActions, view, - initialChildren, configure, + defaultProps, + initialChildren, snippets, transducers, - reducers, isContainer, rectSelector, isModal, isFloating, descriptor, context, - hasSlot, canOperating, - canDraging, - canDragging, - canSelecting, canContain, canDropTo, canDropto, canDropIn, canDroping, - didDropOut, - didDropIn, - canResizing, - onResizeStart, - onResize, - onResizeEnd, - subtreeModified, + // handles + canDraging, canDragging, // handleDragging + canResizing, // handleResizing + // hooks + didDropOut, // onNodeRemove + didDropIn, // onNodeAdd + onResizeStart, // onResizeStart + onResize, // onResize + onResizeEnd, // onResizeEnd + subtreeModified, // onSubtreeModified } = oldConfig; @@ -305,13 +302,42 @@ function upgradeMetadata(oldConfig: OldPrototypeConfig) { if (canOperating === false) { component.disableBehaviors = '*'; } - nestingRule - disableBehaviors - actions + if (extraActions) { + component.actions = extraActions.map((content) => { + return { + name: content.displayName || content.name || 'anonymous', + content, + important: true, + }; + }); + } + const nestingRule: any = {}; + if (canContain) { + nestingRule.descendantWhitelist = canContain; + } + if (canDropTo || canDropto) { + nestingRule.parentWhitelist = canDropTo || canDropto; + } + if (canDropIn || canDroping) { + nestingRule.childWhitelist = canDropIn || canDroping; + } + component.nestingRule = nestingRule; + + if (canDragging || canDraging) { + // hooks|handle + } + + // 未考虑清楚的,放在实验性段落 + const experimental: any = {}; + if (context) { + // for prototype.getContextInfo + experimental.context = context; + } + const props = {}; const styles = {}; const events = {}; - meta.configure = { props, component, styles, events }; + meta.configure = { props, component, styles, events, experimental }; } @@ -341,7 +367,6 @@ export interface OldPrototypeConfig { configure: IPropConfig[]; // => configure.props snippets?: ISnippet[]; // => snippets transducers?: any; // => ? - reducers?: any; // ? /** * Selector expression rectangle of a node, it is usually a querySelector string * @example '.classname > div' diff --git a/packages/vision-polyfill/src/editor.ts b/packages/vision-polyfill/src/editor.ts index ff5fb3447..f3104501e 100644 --- a/packages/vision-polyfill/src/editor.ts +++ b/packages/vision-polyfill/src/editor.ts @@ -5,7 +5,7 @@ import DesignerView from '@ali/lowcode-plugin-designer'; import { registerSetters } from '@ali/lowcode-setters'; import { Skeleton } from './skeleton/skeleton'; import { Designer } from 'designer/src/designer'; -import { globalContext } from 'globals/src/di'; +import { globalContext } from '@ali/lowcode-globals'; registerSetters(); diff --git a/packages/vision-polyfill/src/skeleton/workbench.less b/packages/vision-polyfill/src/skeleton/workbench.less index 9fc2d4da1..49ef86c67 100644 --- a/packages/vision-polyfill/src/skeleton/workbench.less +++ b/packages/vision-polyfill/src/skeleton/workbench.less @@ -17,13 +17,14 @@ --top-area-height: 48px; --toolbar-height: 32px; --dock-pane-width: 372px; + --dock-fixed-pane-width: 220px; } - @media (min-width: 1860px) { :root { --right-area-width: 400px; --dock-pane-width: 452px; + --dock-fixed-pane-width: 350px; } } @@ -188,6 +189,7 @@ body { .lc-workbench-body { flex: 1; display: flex; + min-height: 0; position: relative; .lc-left-float-pane { position: absolute; @@ -212,7 +214,7 @@ body { } } .lc-left-fixed-pane { - width: var(--dock-pane-width); + width: var(--dock-fixed-pane-width); background-color: var(--color-pane-background); height: 100%; display: none;