From 0b0015c3685ad05f11e138596f9bc7c2faf89833 Mon Sep 17 00:00:00 2001 From: JackLian Date: Mon, 16 Jan 2023 10:37:56 +0800 Subject: [PATCH 01/11] refactor: remove dependecy of designer.focusing for refactoring of hotkey plugin as a standalone one --- packages/designer/src/designer/designer.ts | 5 +- packages/designer/src/designer/focusing.ts | 8 --- packages/designer/src/designer/index.ts | 1 - packages/designer/src/document/node/node.ts | 14 ++--- .../src/inner-plugins/builtin-hotkey.ts | 63 ++++++++++++++++--- 5 files changed, 63 insertions(+), 28 deletions(-) delete mode 100644 packages/designer/src/designer/focusing.ts diff --git a/packages/designer/src/designer/designer.ts b/packages/designer/src/designer/designer.ts index 6ade5fea0..0e3559e0a 100644 --- a/packages/designer/src/designer/designer.ts +++ b/packages/designer/src/designer/designer.ts @@ -30,7 +30,6 @@ import { ActiveTracker, IActiveTracker } from './active-tracker'; import { Detecting } from './detecting'; import { DropLocation } from './location'; import { OffsetObserver, createOffsetObserver } from './offset-observer'; -import { focusing } from './focusing'; import { SettingTopEntry } from './setting'; import { BemToolsManager } from '../builtin-simulator/bem-tools/manager'; import { ComponentActions } from '../component-actions'; @@ -241,9 +240,6 @@ export class Designer implements IDesigner { this.postEvent('init', this); this.setupSelection(); setupHistory(); - - // TODO: 先简单实现,后期通过焦点赋值 - focusing.focusDesigner = this; } setupSelection = () => { @@ -341,6 +337,7 @@ export class Designer implements IDesigner { /** * 获得合适的插入位置 + * @deprecated */ getSuitableInsertion( insertNode?: INode | IPublicTypeNodeSchema | IPublicTypeNodeSchema[], diff --git a/packages/designer/src/designer/focusing.ts b/packages/designer/src/designer/focusing.ts deleted file mode 100644 index 66816bc03..000000000 --- a/packages/designer/src/designer/focusing.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Designer } from './designer'; - -// TODO: use focus-tracker replace -class Focusing { - focusDesigner?: Designer; -} - -export const focusing = new Focusing(); diff --git a/packages/designer/src/designer/index.ts b/packages/designer/src/designer/index.ts index 105291885..34d7a8c09 100644 --- a/packages/designer/src/designer/index.ts +++ b/packages/designer/src/designer/index.ts @@ -7,6 +7,5 @@ export * from './offset-observer'; export * from './scroller'; export * from './setting'; export * from './active-tracker'; -export * from './focusing'; export * from '../document'; export * from './clipboard'; diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts index 5525493a1..2b5433b00 100644 --- a/packages/designer/src/document/node/node.ts +++ b/packages/designer/src/document/node/node.ts @@ -1396,11 +1396,11 @@ export function comparePosition(node1: Node, node2: Node): PositionNO { export function insertChild( container: INode, - thing: Node | IPublicTypeNodeData, + thing: INode | IPublicTypeNodeData, at?: number | null, copy?: boolean, -): Node { - let node: Node; +): INode { + let node: INode; if (isNode(thing) && (copy || thing.isSlot())) { thing = thing.export(IPublicEnumTransformStage.Clone); } @@ -1410,20 +1410,20 @@ export function insertChild( node = container.document.createNode(thing); } - container.children.internalInsert(node, at); + container.children.insert(node, at); return node; } export function insertChildren( container: INode, - nodes: Node[] | IPublicTypeNodeData[], + nodes: INode[] | IPublicTypeNodeData[], at?: number | null, copy?: boolean, -): Node[] { +): INode[] { let index = at; let node: any; - const results: Node[] = []; + const results: INode[] = []; // eslint-disable-next-line no-cond-assign while ((node = nodes.pop())) { node = insertChild(container, node, index, copy); diff --git a/packages/engine/src/inner-plugins/builtin-hotkey.ts b/packages/engine/src/inner-plugins/builtin-hotkey.ts index 3ee79831b..d0165d89f 100644 --- a/packages/engine/src/inner-plugins/builtin-hotkey.ts +++ b/packages/engine/src/inner-plugins/builtin-hotkey.ts @@ -1,7 +1,6 @@ /* eslint-disable max-len */ -import { isFormEvent } from '@alilc/lowcode-utils'; +import { isFormEvent, isNodeSchema } from '@alilc/lowcode-utils'; import { - focusing, insertChildren, clipboard, } from '@alilc/lowcode-designer'; @@ -9,11 +8,60 @@ import { IPublicModelPluginContext, IPublicEnumTransformStage, IPublicModelNode, + IPublicTypeNodeSchema, } from '@alilc/lowcode-types'; import symbols from '../modules/symbols'; const { nodeSymbol, documentSymbol } = symbols; +/** + * 获得合适的插入位置 + */ +function getSuitableInsertion( + pluginContext: IPublicModelPluginContext, + insertNode?: IPublicModelNode | IPublicTypeNodeSchema | IPublicTypeNodeSchema[], +): { target: IPublicModelNode; index?: number } | null { + const { project, material } = pluginContext; + const activeDoc = project.currentDocument; + if (!activeDoc) { + return null; + } + if ( + Array.isArray(insertNode) && + isNodeSchema(insertNode[0]) && + material.getComponentMeta(insertNode[0].componentName)?.isModal + ) { + if (!activeDoc.root) { + return null; + } + + return { + target: activeDoc.root, + }; + } + + const focusNode = activeDoc.focusNode!; + const nodes = activeDoc.selection.getNodes(); + const refNode = nodes.find((item) => focusNode.contains(item)); + let target; + let index: number | undefined; + if (!refNode || refNode === focusNode) { + target = focusNode; + } else if (refNode.componentMeta?.isContainer) { + target = refNode; + } else { + // FIXME!!, parent maybe null + target = refNode.parent!; + index = refNode.index + 1; + } + + if (target && insertNode && !target.componentMeta?.checkNestingDown(target, insertNode)) { + return null; + } + + return { target, index }; +} + /* istanbul ignore next */ function getNextForSelect(next: IPublicModelNode | null, head?: any, parent?: IPublicModelNode | null): any { if (next) { @@ -108,11 +156,11 @@ export const builtinHotkey = (ctx: IPublicModelPluginContext) => { hotkey.bind('escape', (e: KeyboardEvent, action) => { logger.info(`action ${action} is triggered`); - // const currentFocus = focusing.current; + if (canvas.isInLiveEditing) { return; } - const sel = focusing.focusDesigner?.currentDocument?.selection; + const sel = project.currentDocument?.selection; if (isFormEvent(e) || !sel) { return; } @@ -168,15 +216,14 @@ export const builtinHotkey = (ctx: IPublicModelPluginContext) => { return; } // TODO - const designer = focusing.focusDesigner; const doc = project?.currentDocument; - if (isFormEvent(e) || !designer || !doc) { + if (isFormEvent(e) || !doc) { return; } /* istanbul ignore next */ clipboard.waitPasteData(e, ({ componentsTree }) => { if (componentsTree) { - const { target, index } = designer.getSuitableInsertion(componentsTree) || {}; + const { target, index } = getSuitableInsertion(ctx, componentsTree) || {}; if (!target) { return; } @@ -187,7 +234,7 @@ export const builtinHotkey = (ctx: IPublicModelPluginContext) => { const nodes = insertChildren(target, canAddComponentsTree, index); if (nodes) { doc.selection.selectAll(nodes.map((o) => o.id)); - setTimeout(() => designer.activeTracker.track(nodes[0]), 10); + setTimeout(() => canvas.activeTracker?.track(nodes[0]), 10); } } }); From 852977c0914a119ffcc42afddb7a4cb658a1f5bc Mon Sep 17 00:00:00 2001 From: JackLian Date: Mon, 16 Jan 2023 16:09:26 +0800 Subject: [PATCH 02/11] refactor: add clipboard to canvas for refactoring of hotkey plugin as a standalone one --- docs/docs/api/canvas.md | 6 +++ docs/docs/api/model/clipboard.md | 43 +++++++++++++++++++ docs/docs/api/model/resource.md | 2 +- packages/designer/src/designer/clipboard.ts | 22 +++++++--- .../src/inner-plugins/builtin-hotkey.ts | 2 +- packages/shell/src/api/canvas.ts | 10 +++++ packages/shell/src/index.ts | 2 + packages/shell/src/model/clipboard.ts | 22 ++++++++++ packages/shell/src/model/index.ts | 3 +- packages/shell/src/symbols.ts | 3 +- packages/types/src/shell/api/canvas.ts | 10 ++++- packages/types/src/shell/model/clipboard.ts | 25 +++++++++++ packages/types/src/shell/model/index.ts | 3 +- 13 files changed, 140 insertions(+), 13 deletions(-) create mode 100644 docs/docs/api/model/clipboard.md create mode 100644 packages/shell/src/model/clipboard.ts create mode 100644 packages/types/src/shell/model/clipboard.ts diff --git a/docs/docs/api/canvas.md b/docs/docs/api/canvas.md index b6af6680e..c16ba62c5 100644 --- a/docs/docs/api/canvas.md +++ b/docs/docs/api/canvas.md @@ -36,6 +36,12 @@ sidebar_position: 12 `@type {boolean}` +### clipboard +全局剪贴板实例 + +`@type {IPublicModelClipboard}` + +相关类型:[IPublicModelClipboard](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/clipboard.ts) ## 方法 diff --git a/docs/docs/api/model/clipboard.md b/docs/docs/api/model/clipboard.md new file mode 100644 index 000000000..15d9e280c --- /dev/null +++ b/docs/docs/api/model/clipboard.md @@ -0,0 +1,43 @@ +--- +title: Clipboard +sidebar_position: 14 +--- + +> **@types** [IPublicModelClipboard](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/clipboard.ts)
+> **@since** v1.1.0 + +## 方法 + +### setData + +给剪贴板赋值 + +```typescript +/** + * 给剪贴板赋值 + * set data to clipboard + * + * @param {*} data + * @since v1.1.0 + */ +setData(data: any): void; +``` + +### waitPasteData + +设置剪贴板数据设置的回调 + +```typescript +/** + * 设置剪贴板数据设置的回调 + * set callback for clipboard provide paste data + * + * @param {KeyboardEvent} keyboardEvent + * @param {(data: any, clipboardEvent: ClipboardEvent) => void} cb + * @since v1.1.0 + */ +waitPasteData( + keyboardEvent: KeyboardEvent, + cb: (data: any, clipboardEvent: ClipboardEvent) => void, + ): void; +``` \ No newline at end of file diff --git a/docs/docs/api/model/resource.md b/docs/docs/api/model/resource.md index 30b1e9f41..74f8d8f71 100644 --- a/docs/docs/api/model/resource.md +++ b/docs/docs/api/model/resource.md @@ -1,6 +1,6 @@ --- title: Resource -sidebar_position: 12 +sidebar_position: 13 --- > **[@experimental](./#experimental)**
diff --git a/packages/designer/src/designer/clipboard.ts b/packages/designer/src/designer/clipboard.ts index a43b51b0e..941f91442 100644 --- a/packages/designer/src/designer/clipboard.ts +++ b/packages/designer/src/designer/clipboard.ts @@ -1,3 +1,5 @@ +import { IPublicModelClipboard } from '@alilc/lowcode-types'; + function getDataFromPasteEvent(event: ClipboardEvent) { const { clipboardData } = event; if (!clipboardData) { @@ -23,7 +25,13 @@ function getDataFromPasteEvent(event: ClipboardEvent) { } } -class Clipboard { +export interface IClipboard extends IPublicModelClipboard { + + initCopyPaster(el: HTMLTextAreaElement): void; + + injectCopyPaster(document: Document): void; +} +class Clipboard implements IClipboard { private copyPasters: HTMLTextAreaElement[] = []; private waitFn?: (data: any, e: ClipboardEvent) => void; @@ -56,7 +64,7 @@ class Clipboard { } injectCopyPaster(document: Document) { - if (this.copyPasters.find(x => x.ownerDocument === document)) { + if (this.copyPasters.find((x) => x.ownerDocument === document)) { return; } const copyPaster = document.createElement<'textarea'>('textarea'); @@ -69,8 +77,8 @@ class Clipboard { }; } - setData(data: any) { - const copyPaster = this.copyPasters.find(x => x.ownerDocument); + setData(data: any): void { + const copyPaster = this.copyPasters.find((x) => x.ownerDocument); if (!copyPaster) { return; } @@ -81,12 +89,12 @@ class Clipboard { copyPaster.blur(); } - waitPasteData(e: KeyboardEvent, cb: (data: any, e: ClipboardEvent) => void) { - const win = e.view; + waitPasteData(keyboardEvent: KeyboardEvent, cb: (data: any, e: ClipboardEvent) => void) { + const win = keyboardEvent.view; if (!win) { return; } - const copyPaster = this.copyPasters.find(cp => cp.ownerDocument === win.document); + const copyPaster = this.copyPasters.find((cp) => cp.ownerDocument === win.document); if (copyPaster) { copyPaster.select(); this.waitFn = cb; diff --git a/packages/engine/src/inner-plugins/builtin-hotkey.ts b/packages/engine/src/inner-plugins/builtin-hotkey.ts index d0165d89f..03d559a9a 100644 --- a/packages/engine/src/inner-plugins/builtin-hotkey.ts +++ b/packages/engine/src/inner-plugins/builtin-hotkey.ts @@ -2,7 +2,6 @@ import { isFormEvent, isNodeSchema } from '@alilc/lowcode-utils'; import { insertChildren, - clipboard, } from '@alilc/lowcode-designer'; import { IPublicModelPluginContext, @@ -129,6 +128,7 @@ export const builtinHotkey = (ctx: IPublicModelPluginContext) => { return { init() { const { hotkey, project, logger, canvas } = ctx; + const { clipboard } = canvas; // hotkey binding hotkey.bind(['backspace', 'del'], (e: KeyboardEvent, action) => { logger.info(`action ${action} is triggered`); diff --git a/packages/shell/src/api/canvas.ts b/packages/shell/src/api/canvas.ts index 5489a8b75..444894452 100644 --- a/packages/shell/src/api/canvas.ts +++ b/packages/shell/src/api/canvas.ts @@ -8,6 +8,7 @@ import { IPublicModelEditor, IPublicModelDragon, IPublicModelActiveTracker, + IPublicModelClipboard, } from '@alilc/lowcode-types'; import { ScrollTarget as InnerScrollTarget, @@ -18,10 +19,14 @@ import { Dragon as ShellDragon, DropLocation as ShellDropLocation, ActiveTracker as ShellActiveTracker, + Clipboard as ShellClipboard, } from '../model'; +const clipboardInstanceSymbol = Symbol('clipboardInstace'); + export class Canvas implements IPublicApiCanvas { private readonly [editorSymbol]: IPublicModelEditor; + private readonly [clipboardInstanceSymbol]: IPublicModelClipboard; private get [designerSymbol](): IDesigner { return this[editorSymbol].get('designer') as IDesigner; @@ -40,8 +45,13 @@ export class Canvas implements IPublicApiCanvas { return Boolean(this[editorSymbol].get('designer')?.project?.simulator?.liveEditing?.editing); } + get clipboard(): IPublicModelClipboard { + return this[clipboardInstanceSymbol]; + } + constructor(editor: IPublicModelEditor, readonly workspaceMode: boolean = false) { this[editorSymbol] = editor; + this[clipboardInstanceSymbol] = new ShellClipboard(); } createScrollTarget(shell: HTMLDivElement): IPublicModelScrollTarget { diff --git a/packages/shell/src/index.ts b/packages/shell/src/index.ts index 92d616945..0307349ab 100644 --- a/packages/shell/src/index.ts +++ b/packages/shell/src/index.ts @@ -9,6 +9,7 @@ import { Dragon, SettingPropEntry, SettingTopEntry, + Clipboard, } from './model'; import { Project, @@ -57,4 +58,5 @@ export { Logger, Canvas, Workspace, + Clipboard, }; \ No newline at end of file diff --git a/packages/shell/src/model/clipboard.ts b/packages/shell/src/model/clipboard.ts new file mode 100644 index 000000000..9c4b30945 --- /dev/null +++ b/packages/shell/src/model/clipboard.ts @@ -0,0 +1,22 @@ +import { IPublicModelClipboard } from '@alilc/lowcode-types'; +import { clipboardSymbol } from '../symbols'; +import { IClipboard, clipboard } from '@alilc/lowcode-designer'; + +export class Clipboard implements IPublicModelClipboard { + private readonly [clipboardSymbol]: IClipboard; + + constructor() { + this[clipboardSymbol] = clipboard; + } + + setData(data: any): void { + this[clipboardSymbol].setData(data); + } + + waitPasteData( + keyboardEvent: KeyboardEvent, + cb: (data: any, clipboardEvent: ClipboardEvent) => void, + ): void { + this[clipboardSymbol].waitPasteData(keyboardEvent, cb); + } +} \ No newline at end of file diff --git a/packages/shell/src/model/index.ts b/packages/shell/src/model/index.ts index d20120c3e..f2805342e 100644 --- a/packages/shell/src/model/index.ts +++ b/packages/shell/src/model/index.ts @@ -17,4 +17,5 @@ export * from './setting-top-entry'; export * from './resource'; export * from './active-tracker'; export * from './plugin-instance'; -export * from './window'; \ No newline at end of file +export * from './window'; +export * from './clipboard'; \ No newline at end of file diff --git a/packages/shell/src/symbols.ts b/packages/shell/src/symbols.ts index cd164f62a..dac981e96 100644 --- a/packages/shell/src/symbols.ts +++ b/packages/shell/src/symbols.ts @@ -30,4 +30,5 @@ export const workspaceSymbol = Symbol('workspace'); export const windowSymbol = Symbol('window'); export const pluginInstanceSymbol = Symbol('plugin-instance'); export const resourceTypeSymbol = Symbol('resourceType'); -export const resourceSymbol = Symbol('resource'); \ No newline at end of file +export const resourceSymbol = Symbol('resource'); +export const clipboardSymbol = Symbol('clipboard'); \ No newline at end of file diff --git a/packages/types/src/shell/api/canvas.ts b/packages/types/src/shell/api/canvas.ts index f7983e094..33fbc7781 100644 --- a/packages/types/src/shell/api/canvas.ts +++ b/packages/types/src/shell/api/canvas.ts @@ -1,4 +1,4 @@ -import { IPublicModelDragon, IPublicModelDropLocation, IPublicModelScrollTarget, IPublicModelScrollable, IPublicModelScroller, IPublicModelActiveTracker } from '../model'; +import { IPublicModelDragon, IPublicModelDropLocation, IPublicModelScrollTarget, IPublicModelScrollable, IPublicModelScroller, IPublicModelActiveTracker, IPublicModelClipboard } from '../model'; import { IPublicTypeLocationData } from '../type'; /** @@ -54,4 +54,12 @@ export interface IPublicApiCanvas { * @since v1.1.0 */ get isInLiveEditing(): boolean; + + /** + * 获取全局剪贴板实例 + * get clipboard instance + * + * @since v1.1.0 + */ + get clipboard(): IPublicModelClipboard; } diff --git a/packages/types/src/shell/model/clipboard.ts b/packages/types/src/shell/model/clipboard.ts new file mode 100644 index 000000000..7fdcc4b1c --- /dev/null +++ b/packages/types/src/shell/model/clipboard.ts @@ -0,0 +1,25 @@ + +export interface IPublicModelClipboard { + + /** + * 给剪贴板赋值 + * set data to clipboard + * + * @param {*} data + * @since v1.1.0 + */ + setData(data: any): void; + + /** + * 设置剪贴板数据设置的回调 + * set callback for clipboard provide paste data + * + * @param {KeyboardEvent} keyboardEvent + * @param {(data: any, clipboardEvent: ClipboardEvent) => void} cb + * @since v1.1.0 + */ + waitPasteData( + keyboardEvent: KeyboardEvent, + cb: (data: any, clipboardEvent: ClipboardEvent) => void, + ): void; +} diff --git a/packages/types/src/shell/model/index.ts b/packages/types/src/shell/model/index.ts index e59216faa..8f48f68f1 100644 --- a/packages/types/src/shell/model/index.ts +++ b/packages/types/src/shell/model/index.ts @@ -28,4 +28,5 @@ export * from './editor'; export * from './preference'; export * from './plugin-instance'; export * from './sensor'; -export * from './resource'; \ No newline at end of file +export * from './resource'; +export * from './clipboard'; \ No newline at end of file From e6e5ea8a104534eb6300641b6b6d0be035db37f0 Mon Sep 17 00:00:00 2001 From: haoziqaq <357229046@qq.com> Date: Tue, 17 Jan 2023 15:55:54 +0800 Subject: [PATCH 03/11] fix(plugin-outline-pane): fix text display errors and improve internationalization --- packages/plugin-outline-pane/src/locale/en-US.json | 7 +++++++ packages/plugin-outline-pane/src/locale/zh-CN.json | 7 +++++++ packages/plugin-outline-pane/src/views/filter-tree.ts | 8 ++++---- packages/plugin-outline-pane/src/views/filter.tsx | 9 +++++---- packages/plugin-outline-pane/src/views/pane.tsx | 3 +-- packages/plugin-outline-pane/src/views/tree-node.tsx | 2 +- 6 files changed, 25 insertions(+), 11 deletions(-) diff --git a/packages/plugin-outline-pane/src/locale/en-US.json b/packages/plugin-outline-pane/src/locale/en-US.json index 8bb4221f7..b0f3d3e4a 100644 --- a/packages/plugin-outline-pane/src/locale/en-US.json +++ b/packages/plugin-outline-pane/src/locale/en-US.json @@ -11,5 +11,12 @@ "Slots": "Slots", "Slot for {prop}": "Slot for {prop}", "Outline Tree": "Outline Tree", + "Filter Node": "Filter Node", + "Check All": "Check All", + "Conditional rendering": "Conditional rendering", + "Loop rendering": "Loop rendering", + "Locked": "Locked", + "Hidden": "Hidden", + "Modal View": "Modal View", "Rename": "Rename" } diff --git a/packages/plugin-outline-pane/src/locale/zh-CN.json b/packages/plugin-outline-pane/src/locale/zh-CN.json index 822bf9e94..8036688f2 100644 --- a/packages/plugin-outline-pane/src/locale/zh-CN.json +++ b/packages/plugin-outline-pane/src/locale/zh-CN.json @@ -11,5 +11,12 @@ "Slots": "插槽", "Slot for {prop}": "属性 {prop} 的插槽", "Outline Tree": "大纲树", + "Filter Node": "过滤节点", + "Check All": "全选", + "Conditional rendering": "条件渲染", + "Loop rendering": "循环渲染", + "Locked": "已锁定", + "Hidden": "已隐藏", + "Modal View": "模态视图层", "Rename": "重命名" } diff --git a/packages/plugin-outline-pane/src/views/filter-tree.ts b/packages/plugin-outline-pane/src/views/filter-tree.ts index 61ecb9c02..2a07e15c6 100644 --- a/packages/plugin-outline-pane/src/views/filter-tree.ts +++ b/packages/plugin-outline-pane/src/views/filter-tree.ts @@ -9,16 +9,16 @@ export const FilterType = { export const FILTER_OPTIONS = [{ value: FilterType.CONDITION, - label: '条件渲染', + label: 'Conditional rendering', }, { value: FilterType.LOOP, - label: '循环渲染', + label: 'Loop rendering', }, { value: FilterType.LOCKED, - label: '已锁定', + label: 'Locked', }, { value: FilterType.HIDDEN, - label: '已隐藏', + label: 'Hidden', }]; export const matchTreeNode = ( diff --git a/packages/plugin-outline-pane/src/views/filter.tsx b/packages/plugin-outline-pane/src/views/filter.tsx index 223a4eab0..d4fa792ae 100644 --- a/packages/plugin-outline-pane/src/views/filter.tsx +++ b/packages/plugin-outline-pane/src/views/filter.tsx @@ -5,10 +5,11 @@ import { Search, Checkbox, Balloon, Divider } from '@alifd/next'; import TreeNode from '../controllers/tree-node'; import { Tree } from '../controllers/tree'; import { matchTreeNode, FILTER_OPTIONS } from './filter-tree'; - +import { IPublicModelPluginContext } from '@alilc/lowcode-types'; export default class Filter extends Component<{ tree: Tree; + pluginContext: IPublicModelPluginContext; }, { keywords: string; filterOps: string[]; @@ -55,7 +56,7 @@ export default class Filter extends Component<{ - 全选 + {this.props.pluginContext.intlNode('Check All')} - {op.label} + {this.props.pluginContext.intlNode(op.label)} ))} diff --git a/packages/plugin-outline-pane/src/views/pane.tsx b/packages/plugin-outline-pane/src/views/pane.tsx index 1ed4c74ba..4cee54a51 100644 --- a/packages/plugin-outline-pane/src/views/pane.tsx +++ b/packages/plugin-outline-pane/src/views/pane.tsx @@ -6,7 +6,6 @@ import { IPublicModelPluginContext } from '@alilc/lowcode-types'; import Filter from './filter'; import { TreeMaster } from '../controllers/tree-master'; - export class Pane extends Component<{ config: any; pluginContext: IPublicModelPluginContext; @@ -40,7 +39,7 @@ export class Pane extends Component<{ return (
- +
this.controller.mount(shell)} className="lc-outline-tree-container">
diff --git a/packages/plugin-outline-pane/src/views/tree-node.tsx b/packages/plugin-outline-pane/src/views/tree-node.tsx index a6dc03f08..789068c18 100644 --- a/packages/plugin-outline-pane/src/views/tree-node.tsx +++ b/packages/plugin-outline-pane/src/views/tree-node.tsx @@ -38,7 +38,7 @@ class ModalTreeNodeView extends Component<{ return (
- 模态视图层 + {this.pluginContext.intlNode('Modal View')}
Date: Mon, 16 Jan 2023 16:57:20 +0800 Subject: [PATCH 04/11] refactor: use insertChildren from hotkey plugin instead of from designer --- .../src/inner-plugins/builtin-hotkey.ts | 46 +++++++++++++++++-- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/packages/engine/src/inner-plugins/builtin-hotkey.ts b/packages/engine/src/inner-plugins/builtin-hotkey.ts index 03d559a9a..75d36bc6f 100644 --- a/packages/engine/src/inner-plugins/builtin-hotkey.ts +++ b/packages/engine/src/inner-plugins/builtin-hotkey.ts @@ -1,18 +1,56 @@ /* eslint-disable max-len */ -import { isFormEvent, isNodeSchema } from '@alilc/lowcode-utils'; -import { - insertChildren, -} from '@alilc/lowcode-designer'; +import { isFormEvent, isNodeSchema, isNode } from '@alilc/lowcode-utils'; import { IPublicModelPluginContext, IPublicEnumTransformStage, IPublicModelNode, IPublicTypeNodeSchema, + IPublicTypeNodeData, } from '@alilc/lowcode-types'; import symbols from '../modules/symbols'; const { nodeSymbol, documentSymbol } = symbols; +function insertChild( + container: IPublicModelNode, + originalChild: IPublicModelNode | IPublicTypeNodeData, + at?: number | null, +): IPublicModelNode | null { + let child = originalChild; + if (isNode(child) && (child as IPublicModelNode).isSlotNode) { + child = (child as IPublicModelNode).exportSchema(IPublicEnumTransformStage.Clone); + } + let node = null; + if (isNode(child)) { + node = (child as IPublicModelNode); + container.children?.insert(node, at); + } else { + node = container.document?.createNode(child) || null; + if (node) { + container.children?.insert(node, at); + } + } + + return (node as IPublicModelNode) || null; +} + +function insertChildren( + container: IPublicModelNode, + nodes: IPublicModelNode[] | IPublicTypeNodeData[], + at?: number | null, +): IPublicModelNode[] { + let index = at; + let node: any; + const results: IPublicModelNode[] = []; + // eslint-disable-next-line no-cond-assign + while ((node = nodes.pop())) { + node = insertChild(container, node, index); + results.push(node); + index = node.index; + } + return results; +} + /** * 获得合适的插入位置 */ From 5c6572e3026ce7dafde6648b04f6ea0bc1be4b5e Mon Sep 17 00:00:00 2001 From: haoziqaq <357229046@qq.com> Date: Tue, 17 Jan 2023 18:58:34 +0800 Subject: [PATCH 05/11] fix(react-simulator-renderer): fix missing i18n of customCreateElement --- .../src/locale/en-US.json | 4 ++++ .../src/locale/index.ts | 21 +++++++++++++++++++ .../src/locale/zh-CN.json | 4 ++++ .../src/renderer-view.tsx | 10 +++++---- 4 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 packages/react-simulator-renderer/src/locale/en-US.json create mode 100644 packages/react-simulator-renderer/src/locale/index.ts create mode 100644 packages/react-simulator-renderer/src/locale/zh-CN.json diff --git a/packages/react-simulator-renderer/src/locale/en-US.json b/packages/react-simulator-renderer/src/locale/en-US.json new file mode 100644 index 000000000..ac864c0a2 --- /dev/null +++ b/packages/react-simulator-renderer/src/locale/en-US.json @@ -0,0 +1,4 @@ +{ + "Drag and drop components or templates here": "Drag and drop components or templates here", + "Locked elements and child elements cannot be edited": "Locked elements and child elements cannot be edited" +} \ No newline at end of file diff --git a/packages/react-simulator-renderer/src/locale/index.ts b/packages/react-simulator-renderer/src/locale/index.ts new file mode 100644 index 000000000..e4b39a347 --- /dev/null +++ b/packages/react-simulator-renderer/src/locale/index.ts @@ -0,0 +1,21 @@ +import { createElement } from 'react'; +import enUS from './en-US.json'; +import zhCN from './zh-CN.json'; + +const instance: Record> = { + 'zh-CN': zhCN as Record, + 'en-US': enUS as Record, +}; + +export function createIntl(locale: string = 'zh-CN') { + const intl = (id: string) => { + return instance[locale][id]; + }; + + const intlNode = (id: string) => createElement('span', instance[locale][id]); + + return { + intl, + intlNode, + }; +} diff --git a/packages/react-simulator-renderer/src/locale/zh-CN.json b/packages/react-simulator-renderer/src/locale/zh-CN.json new file mode 100644 index 000000000..74bb821dd --- /dev/null +++ b/packages/react-simulator-renderer/src/locale/zh-CN.json @@ -0,0 +1,4 @@ +{ + "Drag and drop components or templates here": "拖拽组件或模板到这里", + "Locked elements and child elements cannot be edited": "锁定元素及子元素无法编辑" +} \ No newline at end of file diff --git a/packages/react-simulator-renderer/src/renderer-view.tsx b/packages/react-simulator-renderer/src/renderer-view.tsx index d1c7abe30..68e66fc02 100644 --- a/packages/react-simulator-renderer/src/renderer-view.tsx +++ b/packages/react-simulator-renderer/src/renderer-view.tsx @@ -10,6 +10,7 @@ import { SimulatorRendererContainer, DocumentInstance } from './renderer'; import { host } from './host'; import { isRendererDetached } from './utils/misc'; import './renderer.less'; +import { createIntl } from './locale'; // patch cloneElement avoid lost keyProps const originCloneElement = window.React.cloneElement; @@ -130,6 +131,7 @@ class Renderer extends Component<{ documentInstance: DocumentInstance; }> { startTime: number | null = null; + schemaChangedSymbol = false; componentDidUpdate() { this.recordTime(); @@ -152,8 +154,6 @@ class Renderer extends Component<{ this.recordTime(); } - schemaChangedSymbol = false; - getSchemaChangedSymbol = () => { return this.schemaChangedSymbol; }; @@ -172,6 +172,8 @@ class Renderer extends Component<{ if (!container.autoRender || isRendererDetached()) return null; + const { intl } = createIntl(locale); + return ( { return node?.getExtraProp('isLocked')?.getValue() === true; }); if (lockedNode) { - defaultPlaceholder = '锁定元素及子元素无法编辑'; + defaultPlaceholder = intl('Locked elements and child elements cannot be edited'); } children = (
From be309cba0178010a14ef8dca5169f3ad900832e7 Mon Sep 17 00:00:00 2001 From: haoziqaq <357229046@qq.com> Date: Thu, 19 Jan 2023 10:41:15 +0800 Subject: [PATCH 06/11] fix(editor-skeleton): fix missing i18n --- .../src/transducers/addon-combine.ts | 108 ++++++++++-------- 1 file changed, 63 insertions(+), 45 deletions(-) diff --git a/packages/editor-skeleton/src/transducers/addon-combine.ts b/packages/editor-skeleton/src/transducers/addon-combine.ts index 1b5c27015..855dbe569 100644 --- a/packages/editor-skeleton/src/transducers/addon-combine.ts +++ b/packages/editor-skeleton/src/transducers/addon-combine.ts @@ -1,8 +1,14 @@ -import { IPublicTypeTransformedComponentMetadata, IPublicTypeFieldConfig, IPublicModelSettingTarget } from '@alilc/lowcode-types'; +import { + IPublicTypeTransformedComponentMetadata, + IPublicTypeFieldConfig, + IPublicModelSettingTarget, +} from '@alilc/lowcode-types'; import { IconSlot } from '../icons/slot'; import { getConvertedExtraKey } from '@alilc/lowcode-designer'; -export default function (metadata: IPublicTypeTransformedComponentMetadata): IPublicTypeTransformedComponentMetadata { +export default function ( + metadata: IPublicTypeTransformedComponentMetadata, +): IPublicTypeTransformedComponentMetadata { const { componentName, configure = {} } = metadata; // 如果已经处理过,不再重新执行一遍 @@ -111,35 +117,33 @@ export default function (metadata: IPublicTypeTransformedComponentMetadata): IPu }, ]; } - /* - propsGroup.push({ - name: '#generals', - title: { type: 'i18n', 'zh-CN': '通用', 'en-US': 'General' }, - items: [ - { - name: 'id', - title: 'ID', - setter: 'StringSetter', - }, - { - name: 'key', - title: 'Key', - // todo: use Mixin - setter: 'StringSetter', - }, - { - name: 'ref', - title: 'Ref', - setter: 'StringSetter', - }, - { - name: '!more', - title: '更多', - setter: 'PropertiesSetter', - }, - ], - }); - */ + // propsGroup.push({ + // name: '#generals', + // title: { type: 'i18n', 'zh-CN': '通用', 'en-US': 'General' }, + // items: [ + // { + // name: 'id', + // title: 'ID', + // setter: 'StringSetter', + // }, + // { + // name: 'key', + // title: 'Key', + // // todo: use Mixin + // setter: 'StringSetter', + // }, + // { + // name: 'ref', + // title: 'Ref', + // setter: 'StringSetter', + // }, + // { + // name: '!more', + // title: '更多', + // setter: 'PropertiesSetter', + // }, + // ], + // }); const stylesGroup: IPublicTypeFieldConfig[] = []; const advancedGroup: IPublicTypeFieldConfig[] = []; if (propsGroup) { @@ -216,18 +220,24 @@ export default function (metadata: IPublicTypeTransformedComponentMetadata): IPu setValue(field: IPublicModelSettingTarget, eventData) { const { eventDataList, eventList } = eventData; - Array.isArray(eventList) && eventList.map((item) => { - field.parent.clearPropValue(item.name); - return item; - }); - Array.isArray(eventDataList) && eventDataList.map((item) => { - field.parent.setPropValue(item.name, { - type: 'JSFunction', - // 需要传下入参 - value: `function(){return this.${item.relatedEventName}.apply(this,Array.prototype.slice.call(arguments).concat([${item.paramStr ? item.paramStr : ''}])) }`, + Array.isArray(eventList) && + eventList.map((item) => { + field.parent.clearPropValue(item.name); + return item; + }); + Array.isArray(eventDataList) && + eventDataList.map((item) => { + field.parent.setPropValue(item.name, { + type: 'JSFunction', + // 需要传下入参 + value: `function(){return this.${ + item.relatedEventName + }.apply(this,Array.prototype.slice.call(arguments).concat([${ + item.paramStr ? item.paramStr : '' + }])) }`, + }); + return item; }); - return item; - }); }, }, ], @@ -296,7 +306,7 @@ export default function (metadata: IPublicTypeTransformedComponentMetadata): IPu }, { name: 'key', - title: '循环 Key', + title: { type: 'i18n', 'zh-CN': '循环 Key', 'en-US': 'Loop Key' }, setter: [ { componentName: 'StringSetter', @@ -317,8 +327,16 @@ export default function (metadata: IPublicTypeTransformedComponentMetadata): IPu advancedGroup.push({ name: 'key', title: { - label: '渲染唯一标识(key)', - tip: '搭配「条件渲染」或「循环渲染」时使用,和 react 组件中的 key 原理相同,点击查看帮助', + label: { + type: 'i18n', + 'zh-CN': '渲染唯一标识 (key)', + 'en-US': 'Render unique identifier (key)', + }, + tip: { + type: 'i18n', + 'zh-CN': '搭配「条件渲染」或「循环渲染」时使用,和 react 组件中的 key 原理相同,点击查看帮助', + 'en-US': 'Used with 「Conditional Rendering」or「Cycle Rendering」, the same principle as the key in the react component, click to view the help', + }, docUrl: 'https://www.yuque.com/lce/doc/qm75w3', }, setter: [ From 20f289fd28e7aed6aabbaa4a22c2d9157f2128d8 Mon Sep 17 00:00:00 2001 From: zhutengfei1990 <1041885117@qq.com> Date: Tue, 24 Jan 2023 16:47:55 +0800 Subject: [PATCH 07/11] fix: fix typo in specs --- docs/docs/guide/design/specs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/guide/design/specs.md b/docs/docs/guide/design/specs.md index 3e2b1342c..0d97f5cc0 100644 --- a/docs/docs/guide/design/specs.md +++ b/docs/docs/guide/design/specs.md @@ -23,7 +23,7 @@ sidebar_position: 1 对于低代码物料来说,A 平台创建的物料无法使用到 B 平台上,如果想在 B 平台实现同样的物料,需要按照 B 平台的标准搭建一份物料。 -对于 ProCode 物料来说,需要在低代码平台进行消费,是需要进行转换的,包括搭建配置项的生成、物料搭建试图等,可能还需要特殊的描述文件进行描述。由于这一层没有统一,同一份 ProCode 物料每接入一个低代码,可能需要的描述文件格式不同,转换的代码不同,使用的工具也不同。 +对于 ProCode 物料来说,需要在低代码平台进行消费,是需要进行转换的,包括搭建配置项的生成、物料搭建视图等,可能还需要特殊的描述文件进行描述。由于这一层没有统一,同一份 ProCode 物料每接入一个低代码,可能需要的描述文件格式不同,转换的代码不同,使用的工具也不同。 ### 生态隔离 From 093eeb9b700af38e07aff6097f5a95e2ec876877 Mon Sep 17 00:00:00 2001 From: JackLian Date: Sat, 28 Jan 2023 16:50:04 +0800 Subject: [PATCH 08/11] fix(docs): fix toc display issue for specs --- docs/docs/specs/material-spec.md | 62 ++++++++++++++++---------------- docs/docusaurus.config.js | 4 +-- 2 files changed, 32 insertions(+), 34 deletions(-) diff --git a/docs/docs/specs/material-spec.md b/docs/docs/specs/material-spec.md index 234ec62f6..3bee847c0 100644 --- a/docs/docs/specs/material-spec.md +++ b/docs/docs/specs/material-spec.md @@ -84,7 +84,7 @@ component // 组件名称, 比如 biz-button ``` -#### README.md +##### README.md - README.md 应该包含业务组件的源信息、使用说明以及 API,示例如下: @@ -126,7 +126,7 @@ npm install @alifd/ice-layout -S | type | type | String | `primray`、`normal` | normal | ``` -#### package.json +##### package.json `package.json` 中包含了一些依赖信息和配置信息,示例如下: ```json @@ -159,7 +159,7 @@ npm install @alifd/ice-layout -S } ``` -#### src/index.js +##### src/index.js 包含组件的出口文件,示例如下: @@ -178,7 +178,7 @@ export default Button; import Button, { Group } form '@scope/button'; ``` -#### src/index.scss +##### src/index.scss ```css /* 不引入依赖组件的样式,比如组件 import { Button } from '@alifd/next'; */ @@ -193,7 +193,7 @@ import Button, { Group } form '@scope/button'; } ``` -#### demo +##### demo demo 目录存放的是组件的文档,无文档的业务组件无法带来任何价值,因此 demo 是必选项。demo 目录下的文件采取 markdown 的写法,可以是多个文件,示例(demo/basic.md)如下: demo/basic.md @@ -236,12 +236,12 @@ ReactDOM.render(
API 是组件的属性解释,给开发者作为组件属性配置的参考。为了保持 API 的一致性,我们制定这个 API 命名规范。对于业界通用的,约定俗成的命名,我们遵循社区的约定。对于业界有多种规则难以确定的,我们确定其中一种,大家共同遵守。 -#### 通用规则 +##### 通用规则 - 所有的 API 采用小驼峰的书写规则,如 `onChange`、`direction`、`defaultVisible`。 - 标签名采用大驼峰书写规则,如 `Menu`、`Slider`、`DatePicker`。 -#### 通用命名 +##### 通用命名 | API 名称 | 类型 | 描述 | 常见变量 | | :------------- | :------------- | :----------------------------------------------------------- | :---------------------------------------------------- | @@ -261,7 +261,7 @@ API 是组件的属性解释,给开发者作为组件属性配置的参考。 | has+'属性' | boolean | 拥有某个属性 | 例如 `hasArrow`, `hasHeader`, `hasClose` 等等 | -#### 多选枚举 +##### 多选枚举 当某个 API 的接口,允许用户指定多个枚举值的时候,我们把这个接口定义为多选枚举。一个很典型的例子是某个弹层组件的 `closable` 属性,我们会允许:键盘 esc 按键、点击 mask、点击 close 按钮、点击组件以外的任何区域进行关闭。 @@ -280,11 +280,11 @@ true 表示触发规则都会关闭,false 表示触发规则不会关闭。 - ``,任何情况下都不关闭,只能通过受控设置 visible - ``,用户按 esc 或者点击关闭按钮会关闭 -#### 事件 +##### 事件 - 标准事件或者自定义的符合 w3c 标准的事件,命名必须 on 开头, 即 `on` + 事件名,如 onExpand。 -#### 表单规范 +##### 表单规范 - 支持[受控模式](https://reactjs.org/docs/forms.html#controlled-components)(value + onChange) (A) - value 控制组件数据展现 @@ -292,7 +292,7 @@ true 表示触发规则都会关闭,false 表示触发规则不会关闭。 - `value={undefined}`的时候清空数据,field 的 reset 函数会给所有组件下发 undefined 数据 (AA)) - 一次完整操作抛一次 onChange 事件 `建议` 比如有 Process 表示进展中的状态,建议增加 API `onProcess`;如果有 Start 表示启动状态,建议增加 API `onStart`  (AA) -#### 属性的传递 +##### 属性的传递 **1. 原子组件(Atomic Component)** > 最小粒子,不能再拆分的组件 @@ -354,7 +354,7 @@ $ iceworks sync 文件命名采取 [bcp47](https://tools.ietf.org/html/bcp47) 规范 -#### 目录规范 +##### 目录规范 在 `src` 目录新增 `locale` 目录用于管理不同语言的文案。 @@ -367,7 +367,7 @@ $ iceworks sync |------ ja-JP.js ``` -#### 定义不同的语言 +##### 定义不同的语言 ```javascript // zh-CN.js @@ -390,7 +390,7 @@ export default { }; ``` -#### 组件支持多语言建议方案 +##### 组件支持多语言建议方案 ```jsx // index.jsx @@ -417,7 +417,7 @@ export default class BizHello extends Component { } ``` -#### 组件支持全局替换国际化文案 +##### 组件支持全局替换国际化文案 配合 ConfigProvider 支持全局替换国际化文案。 @@ -451,7 +451,7 @@ export default ConfigProvider.config(BizHello, { 业务组件中如果有自定义的需要跟随主题色的 UI,一定要引入变量的形式,增加组件的流通性。 -#### src/index.scss +##### src/index.scss ```css /* 如果需要引入主题变量引入此段 */ @@ -503,7 +503,7 @@ api 属性标准参考 [https://fusion.design/help.html#/dev-biz](https://fusio 无障碍需要符合 [WCAG 2.1 A 级标准](https://www.w3.org/TR/WCAG21/),可参考 [W3C 无障碍最佳实践](https://www.w3.org/TR/wai-aria-practices-1.1/)、[Fusion 无障碍指引 2.3.1](https://alibaba-fusion.github.io/next/part1/basics.html) 章节等。 -#### 增加 a11y.md 无障碍 demo +##### 增加 a11y.md 无障碍 demo 必须借助 API 才能完成无障碍工作的组件必须为开发者提供无障碍的使用文档,请[参考](https://fusion.design/pc/component/select?themeid=2#accessibility-container)组件 API 中 `ARIA and Keyboard` ,建议在 `demo` 目录新增 `a11y.md` 文件用于演示组件的无障碍使用。 @@ -517,7 +517,7 @@ component 详细指引查看无障碍开发指南 [https://alibaba-fusion.github.io/next/part1/basics.html](https://alibaba-fusion.github.io/next/part1/basics.html)。 -#### 通过键盘快速访问 +##### 通过键盘快速访问 一般键盘事件有 Up Arrow/Down Arrow/Enter/Esc/Tab @@ -531,7 +531,7 @@ component | Esc | 关闭列表 | -#### 对读屏软件友好 +##### 对读屏软件友好 - 对于组件,我们为开发者内置 `role` 和特定 `aria-_属性`,开发者也可以对非组件 API 属性都可以透传至 DOM 元素,进行修改 `role` 和 `aria-_参数`,但是要注意对应关系,请[参考](https://alibaba-fusion.github.io/next/part1/WAI-ARIA.html)。 - 对一些特殊的组件传递参数才能支持无障碍,设置 `id`,`autoFocus` 和传参数,如下: @@ -925,18 +925,18 @@ props 数组下对象字段描述: |initialChildren | 组件拖入“设计器”时根据此配置自动生成 children 节点 schema |NodeData[]/Function NodeData[] | ((target: SettingTarget) => NodeData[]);| |getResizingHandlers| 用于配置设计器中组件 resize 操作工具的样式和内容 | Function| (currentNode: any) => Array<{ type: 'N' | 'W' | 'S' | 'E' | 'NW' | 'NE' | 'SE' | 'SW'; content?: ReactElement; propTarget?: string; appearOn?: 'mouse-enter' | 'mouse-hover' | 'selected' | 'always'; }> / ReactElement[]; |callbacks| 配置 callbacks 可捕获引擎抛出的一些事件,例如 onNodeAdd、onResize 等 | Callback| - -|callbacks.onNodeAdd| 在容器中拖入组件时触发的事件回调| Function| (e: MouseEvent, currentNode: any) => any -|callbacks.onNodeRemove| 在容器中删除组件时触发的事件回调| Function| (e: MouseEvent, currentNode: any) => any +|callbacks.onNodeAdd| 在容器中拖入组件时触发的事件回调 | Function| (e: MouseEvent, currentNode: any) => any +|callbacks.onNodeRemove| 在容器中删除组件时触发的事件回调 | Function| (e: MouseEvent, currentNode: any) => any |callbacks.onResize| 调整容器尺寸时触发的事件回调,常常与 getResizingHandlers 搭配使用 | Function| 详见 Types 定义 |callbacks.onResizeStart| 调整容器尺寸开始时触发的事件回调,常常与 getResizingHandlers 搭配使用 | Function| 详见 Types 定义 |callbacks.onResizeEnd| 调整容器尺寸结束时触发的事件回调,常常与 getResizingHandlers 搭配使用 | Function| 详见 Types 定义 -|callbacks.onSubtreeModified| 容器节点结构树发生变化时触发的回调| Function| (currentNode: any, options: any) => void; -|callbacks.onMouseDownHook| 鼠标按下操作回调| Function| (e: MouseEvent, currentNode: any) => any; -|callbacks.onClickHook| 鼠标单击操作回调| Function| (e: MouseEvent, currentNode: any) => any; -|callbacks.onDblClickHook| 鼠标双击操作回调| Function| (e: MouseEvent, currentNode: any) => any; +|callbacks.onSubtreeModified| 容器节点结构树发生变化时触发的回调 | Function| (currentNode: any, options: any) => void; +|callbacks.onMouseDownHook| 鼠标按下操作回调 | Function| (e: MouseEvent, currentNode: any) => any; +|callbacks.onClickHook| 鼠标单击操作回调 | Function| (e: MouseEvent, currentNode: any) => any; +|callbacks.onDblClickHook| 鼠标双击操作回调 | Function| (e: MouseEvent, currentNode: any) => any; |callbacks.onMoveHook| 节点被拖动回调 | Function| (currentNode: any) => boolean; |callbacks.onHoverHook| 节点被 hover 回调 | Function| (currentNode: any) => boolean; -|callbacks.onChildMoveHook| 容器节点的子节点被拖动回调| Function| (childNode: any, currentNode: any) => boolean; +|callbacks.onChildMoveHook| 容器节点的子节点被拖动回调 | Function| (childNode: any, currentNode: any) => boolean; 描述举例: @@ -1543,7 +1543,7 @@ block/ ``` -#### 入口文件 +##### 入口文件 (/src/index.jsx) @@ -1559,7 +1559,7 @@ const App = hot(router); ReactDOM.render(, document.getElementById(pkg.config && pkg.config.targetRootID || 'root')); ``` -#### 应用参数配置文件 +##### 应用参数配置文件 (/src/config/app.js) @@ -1596,7 +1596,7 @@ export default { } ``` -#### 应用扩展配置规范: +##### 应用扩展配置规范: (/src/utils/index.js) @@ -1618,7 +1618,7 @@ export default { } ``` -#### 应用常量配置 +##### 应用常量配置 (/src/config/constants.js) @@ -1628,7 +1628,7 @@ export default { } ``` -#### 应用样式配置 +##### 应用样式配置 (/src/global.scss) diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index 97a0237b4..0aaa4c50f 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -39,7 +39,6 @@ const config = { presets: [ [ 'classic', - /** @type {import('@docusaurus/preset-classic').Options} */ ({ docs: { sidebarPath: require.resolve('./config/sidebars.js'), @@ -55,7 +54,6 @@ const config = { ], themeConfig: - /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ ({ docs: { sidebar: { @@ -76,7 +74,7 @@ const config = { metadata: [{ name: 'referrer', content: 'no-referrer' }], tableOfContents: { minHeadingLevel: 2, - maxHeadingLevel: 5, + maxHeadingLevel: 6, }, }), From 1b74e71353a4fde3b9030752cde93e27745b1ab6 Mon Sep 17 00:00:00 2001 From: JackLian Date: Sun, 29 Jan 2023 10:14:26 +0800 Subject: [PATCH 09/11] refactor: remove dependency of documentSymbol --- packages/designer/src/component-meta.ts | 10 +++--- .../designer/src/document/document-model.ts | 16 ++++++--- packages/designer/src/document/node/node.ts | 33 ++++++++----------- .../designer/tests/document/node/node.test.ts | 2 +- .../src/inner-plugins/builtin-hotkey.ts | 16 ++++++--- packages/shell/src/model/document-model.ts | 7 ++-- 6 files changed, 48 insertions(+), 36 deletions(-) diff --git a/packages/designer/src/component-meta.ts b/packages/designer/src/component-meta.ts index 70d8630b5..9a74d0ddb 100644 --- a/packages/designer/src/component-meta.ts +++ b/packages/designer/src/component-meta.ts @@ -13,9 +13,9 @@ import { IPublicTypeMetadataTransducer, IPublicModelComponentMeta, } from '@alilc/lowcode-types'; -import { deprecate, isRegExp, isTitleConfig } from '@alilc/lowcode-utils'; +import { deprecate, isRegExp, isTitleConfig, isNode } from '@alilc/lowcode-utils'; import { computed, createModuleEventBus, IEventBus } from '@alilc/lowcode-editor-core'; -import { isNode, Node, INode } from './document'; +import { Node, INode } from './document'; import { Designer } from './designer'; import { IconContainer, @@ -161,6 +161,9 @@ export class ComponentMeta implements IComponentMeta { return this._acceptable!; } + // compatiable vision + prototype?: any; + constructor(readonly designer: Designer, metadata: IPublicTypeComponentMetadata) { this.parseMetadata(metadata); } @@ -347,8 +350,6 @@ export class ComponentMeta implements IComponentMeta { }; } - // compatiable vision - prototype?: any; } export function isComponentMeta(obj: any): obj is ComponentMeta { @@ -373,4 +374,3 @@ function preprocessMetadata(metadata: IPublicTypeComponentMetadata): IPublicType configure: {}, }; } - diff --git a/packages/designer/src/document/document-model.ts b/packages/designer/src/document/document-model.ts index 26648403b..5eb60c396 100644 --- a/packages/designer/src/document/document-model.ts +++ b/packages/designer/src/document/document-model.ts @@ -17,11 +17,11 @@ import { IProject, Project } from '../project'; import { ISimulatorHost } from '../simulator'; import { ComponentMeta } from '../component-meta'; import { IDropLocation, Designer, IHistory } from '../designer'; -import { Node, insertChildren, insertChild, isNode, RootNode, INode } from './node/node'; +import { Node, insertChildren, insertChild, RootNode, INode } from './node/node'; import { Selection, ISelection } from './selection'; import { History } from './history'; import { IModalNodesManager, ModalNodesManager } from './node'; -import { uniqueId, isPlainObject, compatStage, isJSExpression, isDOMText, isNodeSchema, isDragNodeObject, isDragNodeDataObject } from '@alilc/lowcode-utils'; +import { uniqueId, isPlainObject, compatStage, isJSExpression, isDOMText, isNodeSchema, isDragNodeObject, isDragNodeDataObject, isNode } from '@alilc/lowcode-utils'; import { EDITOR_EVENT } from '../types'; export type GetDataType = T extends undefined @@ -32,7 +32,7 @@ export type GetDataType = T extends undefined : any : T; -export interface IDocumentModel extends Omit< IPublicModelDocumentModel, 'selection' > { +export interface IDocumentModel extends Omit< IPublicModelDocumentModel, 'selection' | 'checkNesting' > { readonly designer: Designer; @@ -59,6 +59,11 @@ export interface IDocumentModel extends Omit< IPublicModelDocumentModel, 'select get rootNode(): INode | null; + checkNesting( + dropTarget: INode, + dragObject: IPublicTypeDragNodeObject | IPublicTypeNodeSchema | INode | IPublicTypeDragNodeDataObject, + ): boolean; + } export class DocumentModel implements IDocumentModel { @@ -569,7 +574,10 @@ export class DocumentModel implements IDocumentModel { this.rootNode = null; } - checkNesting(dropTarget: INode, dragObject: IPublicTypeDragNodeObject | IPublicTypeNodeSchema | Node | IPublicTypeDragNodeDataObject): boolean { + checkNesting( + dropTarget: INode, + dragObject: IPublicTypeDragNodeObject | IPublicTypeNodeSchema | INode | IPublicTypeDragNodeDataObject, + ): boolean { let items: Array; if (isDragNodeDataObject(dragObject)) { items = Array.isArray(dragObject.data) ? dragObject.data : [dragObject.data]; diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts index 2b5433b00..f52d7e7bf 100644 --- a/packages/designer/src/document/node/node.ts +++ b/packages/designer/src/document/node/node.ts @@ -16,7 +16,7 @@ import { IPublicModelExclusiveGroup, IPublicEnumTransformStage, } from '@alilc/lowcode-types'; -import { compatStage, isDOMText, isJSExpression } from '@alilc/lowcode-utils'; +import { compatStage, isDOMText, isJSExpression, isNode } from '@alilc/lowcode-utils'; import { SettingTopEntry } from '@alilc/lowcode-designer'; import { Props, getConvertedExtraKey, IProps } from './props/props'; import { DocumentModel, IDocumentModel } from '../document-model'; @@ -109,6 +109,8 @@ export interface INode extends IPublicModelNode { getExtraProp(key: string, createIfNone?: boolean): IProp | null; replaceChild(node: INode, data: any): INode; + + getSuitablePlace(node: INode, ref: any): any; } /** @@ -913,7 +915,7 @@ export class Node /** * 判断是否包含特定节点 */ - contains(node: Node): boolean { + contains(node: INode): boolean { return contains(this, node); } @@ -1149,14 +1151,14 @@ export class Node /** * TODO: replace non standard metas with standard ones. */ - getSuitablePlace(node: Node, ref: any): any { + getSuitablePlace(node: INode, ref: any): any { const focusNode = this.document?.focusNode; // 如果节点是模态框,插入到根节点下 if (node?.componentMeta?.isModal) { return { container: focusNode, ref }; } - if (!ref && this.contains(focusNode)) { + if (!ref && focusNode && this.contains(focusNode)) { const rootCanDropIn = focusNode.componentMeta?.prototype?.options?.canDropIn; if ( rootCanDropIn === undefined || @@ -1171,7 +1173,7 @@ export class Node if (this.isRoot() && this.children) { const dropElement = this.children.filter((c) => { - if (!c.isContainer()) { + if (!c.isContainerNode) { return false; } const canDropIn = c.componentMeta?.prototype?.options?.canDropIn; @@ -1304,22 +1306,15 @@ export type PageNode = Node; export type ComponentNode = Node; export type RootNode = PageNode | ComponentNode; -/** - * @deprecated use same function from '@alilc/lowcode-utils' instead - */ -export function isNode(node: any): node is Node { - return node && node.isNode; +export function isRootNode(node: INode): node is INode { + return node && node.isRootNode; } -export function isRootNode(node: Node): node is RootNode { - return node && node.isRoot(); -} - -export function isLowCodeComponent(node: Node): boolean { +export function isLowCodeComponent(node: INode): node is INode { return node.componentMeta?.getMetadata().devMode === 'lowCode'; } -export function getZLevelTop(child: Node, zLevel: number): Node | null { +export function getZLevelTop(child: INode, zLevel: number): INode | null { let l = child.zLevel; if (l < zLevel || zLevel < 0) { return null; @@ -1340,12 +1335,12 @@ export function getZLevelTop(child: Node, zLevel: number): Node | null { * @param node2 测试的被包含节点 * @returns 是否包含 */ -export function contains(node1: Node, node2: Node): boolean { +export function contains(node1: INode, node2: INode): boolean { if (node1 === node2) { return true; } - if (!node1.isParental() || !node2.parent) { + if (!node1.isParentalNode || !node2.parent) { return false; } @@ -1367,7 +1362,7 @@ export enum PositionNO { BeforeOrAfter = 2, TheSame = 0, } -export function comparePosition(node1: Node, node2: Node): PositionNO { +export function comparePosition(node1: INode, node2: INode): PositionNO { if (node1 === node2) { return PositionNO.TheSame; } diff --git a/packages/designer/tests/document/node/node.test.ts b/packages/designer/tests/document/node/node.test.ts index d8915c991..f7d35f6d6 100644 --- a/packages/designer/tests/document/node/node.test.ts +++ b/packages/designer/tests/document/node/node.test.ts @@ -7,7 +7,6 @@ import { DocumentModel } from '../../../src/document/document-model'; import { isRootNode, Node, - isNode, comparePosition, contains, PositionNO, @@ -23,6 +22,7 @@ import rootHeaderMetadata from '../../fixtures/component-metadata/root-header'; import rootContentMetadata from '../../fixtures/component-metadata/root-content'; import rootFooterMetadata from '../../fixtures/component-metadata/root-footer'; import { shellModelFactory } from '../../../../engine/src/modules/shell-model-factory'; +import { isNode } from '@alilc/lowcode-utils'; describe('Node 方法测试', () => { let editor: Editor; diff --git a/packages/engine/src/inner-plugins/builtin-hotkey.ts b/packages/engine/src/inner-plugins/builtin-hotkey.ts index 75d36bc6f..b6d3a0950 100644 --- a/packages/engine/src/inner-plugins/builtin-hotkey.ts +++ b/packages/engine/src/inner-plugins/builtin-hotkey.ts @@ -6,10 +6,12 @@ import { IPublicModelNode, IPublicTypeNodeSchema, IPublicTypeNodeData, + IPublicEnumDragObjectType, + IPublicTypeDragNodeObject, } from '@alilc/lowcode-types'; import symbols from '../modules/symbols'; -const { nodeSymbol, documentSymbol } = symbols; +const { nodeSymbol } = symbols; function insertChild( container: IPublicModelNode, @@ -265,10 +267,16 @@ export const builtinHotkey = (ctx: IPublicModelPluginContext) => { if (!target) { return; } - let canAddComponentsTree = componentsTree.filter((i) => { - return (doc as any)[documentSymbol].checkNestingUp(target, i); + let canAddComponentsTree = componentsTree.filter((node: IPublicModelNode) => { + const dragNodeObject: IPublicTypeDragNodeObject = { + type: IPublicEnumDragObjectType.Node, + nodes: [node], + }; + return doc.checkNesting(target, dragNodeObject); }); - if (canAddComponentsTree.length === 0) return; + if (canAddComponentsTree.length === 0) { + return; + } const nodes = insertChildren(target, canAddComponentsTree, index); if (nodes) { doc.selection.selectAll(nodes.map((o) => o.id)); diff --git a/packages/shell/src/model/document-model.ts b/packages/shell/src/model/document-model.ts index 13fc49bae..ba371543a 100644 --- a/packages/shell/src/model/document-model.ts +++ b/packages/shell/src/model/document-model.ts @@ -8,7 +8,6 @@ import { GlobalEvent, IPublicModelDocumentModel, IPublicTypeOnChangeOptions, - IPublicModelDragObject, IPublicTypeDragNodeObject, IPublicTypeDragNodeDataObject, IPublicModelNode, @@ -227,9 +226,11 @@ export class DocumentModel implements IPublicModelDocumentModel { dropTarget: IPublicModelNode, dragObject: IPublicTypeDragNodeObject | IPublicTypeDragNodeDataObject, ): boolean { - let innerDragObject: IPublicModelDragObject = dragObject; + let innerDragObject = dragObject; if (isDragNodeObject(dragObject)) { - innerDragObject.nodes = innerDragObject.nodes.map((node: Node) => (node[nodeSymbol] || node)); + innerDragObject.nodes = innerDragObject.nodes?.map( + (node: IPublicModelNode) => ((node as any)[nodeSymbol] || node), + ); } return this[documentSymbol].checkNesting( ((dropTarget as any)[nodeSymbol] || dropTarget) as any, From 67a5e724fd2934f6773456542cf9dbc40081d12a Mon Sep 17 00:00:00 2001 From: JackLian Date: Sun, 29 Jan 2023 17:35:24 +0800 Subject: [PATCH 10/11] refactor: remove dependency of nodeSymbol --- docs/docs/api/model/node.md | 4 +- packages/designer/src/document/node/node.ts | 2 +- .../src/inner-plugins/builtin-hotkey.ts | 70 +++++++++++++++++-- 3 files changed, 67 insertions(+), 9 deletions(-) diff --git a/docs/docs/api/model/node.md b/docs/docs/api/model/node.md index fbc88034b..333e973f0 100644 --- a/docs/docs/api/model/node.md +++ b/docs/docs/api/model/node.md @@ -160,7 +160,7 @@ sidebar_position: 1 `@type {IPublicModelComponentMeta | null}` -相关类型:[IPublicTypeIconType](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/component-meta.ts) +相关类型:[IPublicModelComponentMeta](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/component-meta.ts) ### document @@ -644,4 +644,4 @@ isConditionalVisible(): boolean | undefined; setConditionalVisible(): void; ``` -**@since v1.1.0** \ No newline at end of file +**@since v1.1.0** diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts index f52d7e7bf..1d294663b 100644 --- a/packages/designer/src/document/node/node.ts +++ b/packages/designer/src/document/node/node.ts @@ -1149,7 +1149,7 @@ export class Node } /** - * TODO: replace non standard metas with standard ones. + * @deprecated no one is using this, will be removed in a future release */ getSuitablePlace(node: INode, ref: any): any { const focusNode = this.document?.focusNode; diff --git a/packages/engine/src/inner-plugins/builtin-hotkey.ts b/packages/engine/src/inner-plugins/builtin-hotkey.ts index b6d3a0950..73aac64aa 100644 --- a/packages/engine/src/inner-plugins/builtin-hotkey.ts +++ b/packages/engine/src/inner-plugins/builtin-hotkey.ts @@ -9,9 +9,6 @@ import { IPublicEnumDragObjectType, IPublicTypeDragNodeObject, } from '@alilc/lowcode-types'; -import symbols from '../modules/symbols'; - -const { nodeSymbol } = symbols; function insertChild( container: IPublicModelNode, @@ -163,6 +160,67 @@ function getPrevForSelect(prev: IPublicModelNode | null, head?: any, parent?: IP return null; } +function getSuitablePlaceForNode(targetNode: IPublicModelNode, node: IPublicModelNode, ref: any): any { + const { document } = targetNode; + if (!document) { + return null; + } + + const dragNodeObject: IPublicTypeDragNodeObject = { + type: IPublicEnumDragObjectType.Node, + nodes: [node], + }; + + const focusNode = document?.focusNode; + // 如果节点是模态框,插入到根节点下 + if (node?.componentMeta?.isModal) { + return { container: focusNode, ref }; + } + const canDropInFn = document.checkNesting; + + if (!ref && focusNode && targetNode.contains(focusNode)) { + if (canDropInFn(focusNode, dragNodeObject)) { + return { container: focusNode }; + } + + return null; + } + + if (targetNode.isRootNode && targetNode.children) { + const dropElement = targetNode.children.filter((c) => { + if (!c.isContainerNode) { + return false; + } + if (canDropInFn(c, dragNodeObject)) { + return true; + } + return false; + })[0]; + + if (dropElement) { + return { container: dropElement, ref }; + } + + if (canDropInFn(targetNode, dragNodeObject)) { + return { container: targetNode, ref }; + } + + return null; + } + + if (targetNode.isContainerNode) { + if (canDropInFn(targetNode, dragNodeObject)) { + return { container: targetNode, ref }; + } + } + + if (targetNode.parent) { + return getSuitablePlaceForNode(targetNode.parent, node, { index: targetNode.index }); + } + + return null; +} + // 注册默认的 setters export const builtinHotkey = (ctx: IPublicModelPluginContext) => { return { @@ -426,14 +484,14 @@ export const builtinHotkey = (ctx: IPublicModelPluginContext) => { const silbing = firstNode.prevSibling; if (silbing) { if (silbing.isContainerNode) { - const place = (silbing as any)[nodeSymbol].getSuitablePlace(firstNode, null); + const place = getSuitablePlaceForNode(silbing, firstNode, null); silbing.insertAfter(firstNode, place.ref, true); } else { parent.insertBefore(firstNode, silbing, true); } firstNode?.select(); } else { - const place = (parent as any)[nodeSymbol].getSuitablePlace(firstNode, null); // upwards + const place = getSuitablePlaceForNode(parent, firstNode, null); // upwards if (place) { const container = place.container.internalToShellNode(); container.insertBefore(firstNode, place.ref); @@ -474,7 +532,7 @@ export const builtinHotkey = (ctx: IPublicModelPluginContext) => { } firstNode?.select(); } else { - const place = (parent as any)[nodeSymbol].getSuitablePlace(firstNode, null); // upwards + const place = getSuitablePlaceForNode(parent, firstNode, null); // upwards if (place) { const container = place.container.internalToShellNode(); container.insertAfter(firstNode, place.ref, true); From 6482609ac140b62ddd2b0469f187e0b9b775583b Mon Sep 17 00:00:00 2001 From: liujuping Date: Sun, 29 Jan 2023 19:00:02 +0800 Subject: [PATCH 11/11] feat: add resource layer layout in workspace mode --- .../types/src/shell/type/resource-list.ts | 2 +- .../src/{ => context}/base-context.ts | 6 +-- .../context.ts => context/view-context.ts} | 12 ++--- packages/workspace/src/index.ts | 2 +- packages/workspace/src/layouts/workbench.tsx | 6 +-- packages/workspace/src/resource.ts | 35 ++++++++------ .../view.tsx => view/editor-view.tsx} | 16 +++---- .../workspace/src/view/resource-view.less | 14 ++++++ packages/workspace/src/view/resource-view.tsx | 36 +++++++++++++++ .../view.tsx => view/window-view.tsx} | 25 ++++------ .../{editor-window/context.ts => window.ts} | 6 +-- packages/workspace/src/workspace.ts | 46 ++++++++++--------- 12 files changed, 127 insertions(+), 79 deletions(-) rename packages/workspace/src/{ => context}/base-context.ts (95%) rename packages/workspace/src/{editor-view/context.ts => context/view-context.ts} (93%) rename packages/workspace/src/{editor-view/view.tsx => view/editor-view.tsx} (69%) create mode 100644 packages/workspace/src/view/resource-view.less create mode 100644 packages/workspace/src/view/resource-view.tsx rename packages/workspace/src/{editor-window/view.tsx => view/window-view.tsx} (52%) rename packages/workspace/src/{editor-window/context.ts => window.ts} (95%) diff --git a/packages/types/src/shell/type/resource-list.ts b/packages/types/src/shell/type/resource-list.ts index e5fbcba7e..9b8cc3272 100644 --- a/packages/types/src/shell/type/resource-list.ts +++ b/packages/types/src/shell/type/resource-list.ts @@ -1,7 +1,7 @@ export interface IPublicResourceData { resourceName: string; title: string; - category: string; + category?: string; options: { [key: string]: any; }; diff --git a/packages/workspace/src/base-context.ts b/packages/workspace/src/context/base-context.ts similarity index 95% rename from packages/workspace/src/base-context.ts rename to packages/workspace/src/context/base-context.ts index 0ff63ee02..b90a131a3 100644 --- a/packages/workspace/src/base-context.ts +++ b/packages/workspace/src/context/base-context.ts @@ -1,5 +1,3 @@ -/* eslint-disable no-param-reassign */ -/* eslint-disable max-len */ import { Editor, engineConfig, Setters as InnerSetters, @@ -33,8 +31,8 @@ import { IPublicTypePluginMeta, } from '@alilc/lowcode-types'; import { getLogger } from '@alilc/lowcode-utils'; -import { Workspace as InnerWorkspace } from './workspace'; -import { EditorWindow } from './editor-window/context'; +import { Workspace as InnerWorkspace } from '../workspace'; +import { EditorWindow } from '../window'; export class BasicContext { skeleton: Skeleton; diff --git a/packages/workspace/src/editor-view/context.ts b/packages/workspace/src/context/view-context.ts similarity index 93% rename from packages/workspace/src/editor-view/context.ts rename to packages/workspace/src/context/view-context.ts index b991532fb..55bbf2d57 100644 --- a/packages/workspace/src/editor-view/context.ts +++ b/packages/workspace/src/context/view-context.ts @@ -2,8 +2,8 @@ import { makeObservable, obx } from '@alilc/lowcode-editor-core'; import { IPublicEditorViewConfig, IPublicTypeEditorView } from '@alilc/lowcode-types'; import { flow } from 'mobx'; import { Workspace as InnerWorkspace } from '../workspace'; -import { BasicContext } from '../base-context'; -import { EditorWindow } from '../editor-window/context'; +import { BasicContext } from './base-context'; +import { EditorWindow } from '../window'; import { getWebviewPlugin } from '../inner-plugins/webview'; export class Context extends BasicContext { @@ -17,6 +17,10 @@ export class Context extends BasicContext { @obx isInit: boolean = false; + get active() { + return this._activate; + } + init = flow(function* (this: any) { if (this.viewType === 'webview') { const url = yield this.instance?.url?.(); @@ -44,10 +48,6 @@ export class Context extends BasicContext { this.innerHotkey.activate(this._activate); }; - get active() { - return this._activate; - } - async save() { return await this.instance?.save?.(); } diff --git a/packages/workspace/src/index.ts b/packages/workspace/src/index.ts index 2f6da97a8..9442266bb 100644 --- a/packages/workspace/src/index.ts +++ b/packages/workspace/src/index.ts @@ -1,4 +1,4 @@ export { Workspace } from './workspace'; -export * from './editor-window/context'; +export * from './window'; export * from './layouts/workbench'; export { Resource } from './resource'; diff --git a/packages/workspace/src/layouts/workbench.tsx b/packages/workspace/src/layouts/workbench.tsx index 7ffb0e531..fe5ef846f 100644 --- a/packages/workspace/src/layouts/workbench.tsx +++ b/packages/workspace/src/layouts/workbench.tsx @@ -1,6 +1,6 @@ import { Component } from 'react'; import { TipContainer, observer } from '@alilc/lowcode-editor-core'; -import { EditorWindowView } from '../editor-window/view'; +import { WindowView } from '../view/window-view'; import classNames from 'classnames'; import TopArea from './top-area'; import LeftArea from './left-area'; @@ -46,9 +46,9 @@ export class Workbench extends Component<{
{ workspace.windows.map(d => ( - )) diff --git a/packages/workspace/src/resource.ts b/packages/workspace/src/resource.ts index 2495909b4..effa6abee 100644 --- a/packages/workspace/src/resource.ts +++ b/packages/workspace/src/resource.ts @@ -1,6 +1,6 @@ import { IPublicTypeEditorView, IPublicModelResource, IPublicResourceData, IPublicResourceTypeConfig } from '@alilc/lowcode-types'; import { Logger } from '@alilc/lowcode-utils'; -import { BasicContext } from './base-context'; +import { BasicContext } from './context/base-context'; import { ResourceType } from './resource-type'; import { Workspace as InnerWorkSpace } from './workspace'; @@ -13,20 +13,6 @@ export class Resource implements IPublicModelResource { editorViewMap: Map = new Map(); - constructor(readonly resourceData: IPublicResourceData, readonly resourceType: ResourceType, workspace: InnerWorkSpace) { - this.context = new BasicContext(workspace, ''); - this.resourceTypeInstance = resourceType.resourceTypeModel(this.context, {}); - this.init(); - if (this.resourceTypeInstance.editorViews) { - this.resourceTypeInstance.editorViews.forEach((d: any) => { - this.editorViewMap.set(d.viewName, d); - }); - } - if (!resourceType) { - logger.error(`resourceType[${resourceType}] is unValid.`); - } - } - get name() { return this.resourceType.name; } @@ -55,6 +41,24 @@ export class Resource implements IPublicModelResource { return this.resourceData?.category; } + get skeleton() { + return this.context.innerSkeleton; + } + + constructor(readonly resourceData: IPublicResourceData, readonly resourceType: ResourceType, workspace: InnerWorkSpace) { + this.context = new BasicContext(workspace, `resource-${resourceData.resourceName || resourceType.name}`); + this.resourceTypeInstance = resourceType.resourceTypeModel(this.context, {}); + this.init(); + if (this.resourceTypeInstance.editorViews) { + this.resourceTypeInstance.editorViews.forEach((d: any) => { + this.editorViewMap.set(d.viewName, d); + }); + } + if (!resourceType) { + logger.error(`resourceType[${resourceType}] is unValid.`); + } + } + async init() { await this.resourceTypeInstance.init?.(); await this.context.innerPlugins.init(); @@ -63,6 +67,7 @@ export class Resource implements IPublicModelResource { async import(schema: any) { return await this.resourceTypeInstance.import?.(schema); } + async save(value: any) { return await this.resourceTypeInstance.save?.(value); } diff --git a/packages/workspace/src/editor-view/view.tsx b/packages/workspace/src/view/editor-view.tsx similarity index 69% rename from packages/workspace/src/editor-view/view.tsx rename to packages/workspace/src/view/editor-view.tsx index 77f0dffeb..7ada5c911 100644 --- a/packages/workspace/src/editor-view/view.tsx +++ b/packages/workspace/src/view/editor-view.tsx @@ -4,9 +4,9 @@ import { Workbench, } from '@alilc/lowcode-editor-skeleton'; import { PureComponent } from 'react'; -import { Context } from './context'; +import { Context } from '../context/view-context'; -export * from '../base-context'; +export * from '../context/base-context'; @observer export class EditorView extends PureComponent<{ @@ -23,13 +23,11 @@ export class EditorView extends PureComponent<{ } return ( - <> - - + ); } } diff --git a/packages/workspace/src/view/resource-view.less b/packages/workspace/src/view/resource-view.less new file mode 100644 index 000000000..4c281f8d8 --- /dev/null +++ b/packages/workspace/src/view/resource-view.less @@ -0,0 +1,14 @@ +.workspace-resource-view { + display: flex; + position: absolute; + flex-direction: column; + top: 0; + bottom: 0; + left: 0; + right: 0; +} + +.workspace-editor-body { + position: relative; + height: 100%; +} \ No newline at end of file diff --git a/packages/workspace/src/view/resource-view.tsx b/packages/workspace/src/view/resource-view.tsx new file mode 100644 index 000000000..37e960b99 --- /dev/null +++ b/packages/workspace/src/view/resource-view.tsx @@ -0,0 +1,36 @@ +import { PureComponent } from 'react'; +import { EditorView } from './editor-view'; +import { observer } from '@alilc/lowcode-editor-core'; +import TopArea from '../layouts/top-area'; +import { Resource } from '../resource'; +import { EditorWindow } from '../window'; +import './resource-view.less'; + +@observer +export class ResourceView extends PureComponent<{ + window: EditorWindow; + resource: Resource; +}, any> { + render() { + const { skeleton } = this.props.resource; + const { editorViews } = this.props.window; + return ( +
+ +
+ { + Array.from(editorViews.values()).map((editorView: any) => { + return ( + + ); + }) + } +
+
+ ); + } +} \ No newline at end of file diff --git a/packages/workspace/src/editor-window/view.tsx b/packages/workspace/src/view/window-view.tsx similarity index 52% rename from packages/workspace/src/editor-window/view.tsx rename to packages/workspace/src/view/window-view.tsx index eb049aeed..396582a02 100644 --- a/packages/workspace/src/editor-window/view.tsx +++ b/packages/workspace/src/view/window-view.tsx @@ -1,17 +1,17 @@ import { PureComponent } from 'react'; -import { EditorView } from '../editor-view/view'; +import { ResourceView } from './resource-view'; import { engineConfig, observer } from '@alilc/lowcode-editor-core'; -import { EditorWindow } from './context'; +import { EditorWindow } from '../window'; import { BuiltinLoading } from '@alilc/lowcode-designer'; @observer -export class EditorWindowView extends PureComponent<{ - editorWindow: EditorWindow; +export class WindowView extends PureComponent<{ + window: EditorWindow; active: boolean; }, any> { render() { const { active } = this.props; - const { editorView, editorViews } = this.props.editorWindow; + const { editorView, resource } = this.props.window; if (!editorView) { const Loading = engineConfig.get('loadingComponent', BuiltinLoading); return ( @@ -23,17 +23,10 @@ export class EditorWindowView extends PureComponent<{ return (
- { - Array.from(editorViews.values()).map((editorView: any) => { - return ( - - ); - }) - } +
); } diff --git a/packages/workspace/src/editor-window/context.ts b/packages/workspace/src/window.ts similarity index 95% rename from packages/workspace/src/editor-window/context.ts rename to packages/workspace/src/window.ts index 680647587..73064c6b4 100644 --- a/packages/workspace/src/editor-window/context.ts +++ b/packages/workspace/src/window.ts @@ -1,8 +1,8 @@ import { uniqueId } from '@alilc/lowcode-utils'; import { makeObservable, obx } from '@alilc/lowcode-editor-core'; -import { Context } from '../editor-view/context'; -import { Workspace } from '../workspace'; -import { Resource } from '../resource'; +import { Context } from './context/view-context'; +import { Workspace } from './workspace'; +import { Resource } from './resource'; export class EditorWindow { id: string = uniqueId('window'); diff --git a/packages/workspace/src/workspace.ts b/packages/workspace/src/workspace.ts index c4462a71a..509ca9d9d 100644 --- a/packages/workspace/src/workspace.ts +++ b/packages/workspace/src/workspace.ts @@ -2,8 +2,8 @@ import { Designer } from '@alilc/lowcode-designer'; import { createModuleEventBus, Editor, IEventBus, makeObservable, obx } from '@alilc/lowcode-editor-core'; import { Plugins } from '@alilc/lowcode-shell'; import { IPublicApiWorkspace, IPublicResourceList, IPublicTypeResourceType } from '@alilc/lowcode-types'; -import { BasicContext } from './base-context'; -import { EditorWindow } from './editor-window/context'; +import { BasicContext } from './context/base-context'; +import { EditorWindow } from './window'; import { Resource } from './resource'; import { ResourceType } from './resource-type'; @@ -20,6 +20,12 @@ export class Workspace implements IPublicApiWorkspace { private emitter: IEventBus = createModuleEventBus('workspace'); + private _isActive = false; + + private resourceTypeMap: Map = new Map(); + + private resourceList: Resource[] = []; + get skeleton() { return this.context.innerSkeleton; } @@ -28,7 +34,17 @@ export class Workspace implements IPublicApiWorkspace { return this.context.innerPlugins; } - private _isActive = false; + get isActive() { + return this._isActive; + } + + get defaultResourceType(): ResourceType | null { + if (this.resourceTypeMap.size >= 1) { + return Array.from(this.resourceTypeMap.values())[0]; + } + + return null; + } windows: EditorWindow[] = []; @@ -36,10 +52,6 @@ export class Workspace implements IPublicApiWorkspace { @obx.ref window: EditorWindow; - private resourceTypeMap: Map = new Map(); - - private resourceList: Resource[] = []; - constructor( readonly registryInnerPlugin: (designer: Designer, editor: Editor, plugins: Plugins) => Promise, readonly shellModelFactory: any, @@ -66,10 +78,6 @@ export class Workspace implements IPublicApiWorkspace { this.emitChangeActiveWindow(); } - get isActive() { - return this._isActive; - } - setActive(value: boolean) { this._isActive = value; } @@ -105,14 +113,6 @@ export class Workspace implements IPublicApiWorkspace { return this.resourceTypeMap.get(resourceName)!; } - get defaultResourceType(): ResourceType | null { - if (this.resourceTypeMap.size >= 1) { - return Array.from(this.resourceTypeMap.values())[0]; - } - - return null; - } - removeResourceType(resourceName: string) { if (this.resourceTypeMap.has(resourceName)) { this.resourceTypeMap.delete(resourceName); @@ -153,13 +153,17 @@ export class Workspace implements IPublicApiWorkspace { console.error(`${name} is not available`); return; } - const filterWindows = this.windows.filter(d => (d.resource.name === name && d.title == title)); + const filterWindows = this.windows.filter(d => (d.resource.name === name && d.resource.title == title)); if (filterWindows && filterWindows.length) { this.window = filterWindows[0]; this.emitChangeActiveWindow(); return; } - const resource = new Resource({}, resourceType, this); + const resource = new Resource({ + resourceName: name, + title, + options, + }, resourceType, this); this.window = new EditorWindow(resource, this, title, options); this.windows.push(this.window); this.editorWindowMap.set(this.window.id, this.window);