From e3842b05310010ac0d4899e524b7932b4948d337 Mon Sep 17 00:00:00 2001 From: liujuping Date: Fri, 25 Aug 2023 16:43:16 +0800 Subject: [PATCH 001/219] feat: add editorCabinSymbol and skeletonCabinSymbol --- packages/engine/src/modules/symbols.ts | 4 +++ packages/shell/src/api/common.tsx | 49 +++++++++++++++++++++++++- packages/shell/src/symbols.ts | 2 ++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/packages/engine/src/modules/symbols.ts b/packages/engine/src/modules/symbols.ts index a0371abf98..435e8cbc2c 100644 --- a/packages/engine/src/modules/symbols.ts +++ b/packages/engine/src/modules/symbols.ts @@ -12,6 +12,8 @@ import { propSymbol, simulatorHostSymbol, skeletonItemSymbol, + editorCabinSymbol, + skeletonCabinSymbol, } from '@alilc/lowcode-shell'; export default { @@ -25,6 +27,8 @@ export default { settingPropEntrySymbol: settingFieldSymbol, settingTopEntrySymbol, designerCabinSymbol, + editorCabinSymbol, + skeletonCabinSymbol, propSymbol, simulatorHostSymbol, skeletonItemSymbol, diff --git a/packages/shell/src/api/common.tsx b/packages/shell/src/api/common.tsx index 9f38cf1091..3c2d2e5cce 100644 --- a/packages/shell/src/api/common.tsx +++ b/packages/shell/src/api/common.tsx @@ -1,4 +1,4 @@ -import { editorSymbol, skeletonSymbol, designerCabinSymbol, designerSymbol, settingFieldSymbol } from '../symbols'; +import { editorSymbol, skeletonSymbol, designerCabinSymbol, designerSymbol, settingFieldSymbol, editorCabinSymbol, skeletonCabinSymbol } from '../symbols'; import { isFormEvent as innerIsFormEvent, compatibleLegaoSchema as innerCompatibleLegaoSchema, @@ -36,6 +36,10 @@ import { getConvertedExtraKey as innerGetConvertedExtraKey, getOriginalExtraKey as innerGetOriginalExtraKey, IDesigner, + DropLocation as InnerDropLocation, + Designer as InnerDesigner, + Node as InnerNode, + LowCodePluginManager as InnerLowCodePluginManager, } from '@alilc/lowcode-designer'; import { Skeleton as InnerSkeleton, @@ -43,6 +47,8 @@ import { PopupContext as InnerPopupContext, PopupPipe as InnerPopupPipe, Workbench as InnerWorkbench, + SettingsPrimaryPane as InnerSettingsPrimaryPane, + registerDefaults as InnerRegisterDefaults, } from '@alilc/lowcode-editor-skeleton'; import { Editor, @@ -61,6 +67,7 @@ import { action as innerAction, runInAction as innerRunInAction, engineConfig as innerEngineConfig, + globalContext, } from '@alilc/lowcode-editor-core'; import { Dragon as ShellDragon } from '../model'; import { ReactNode } from 'react'; @@ -94,6 +101,10 @@ class DesignerCabin implements IPublicApiCommonDesignerCabin { DragObjectType: InnerDragObjectType, isDragNodeDataObject: innerIsDragNodeDataObject, isNode: innerIsNode, + DropLocation: InnerDropLocation, + Designer: InnerDesigner, + Node: InnerNode, + LowCodePluginManager: InnerLowCodePluginManager, }; } @@ -160,8 +171,19 @@ class DesignerCabin implements IPublicApiCommonDesignerCabin { class SkeletonCabin implements IPublicApiCommonSkeletonCabin { private readonly [skeletonSymbol]: InnerSkeleton; + readonly [skeletonCabinSymbol]: any; + constructor(skeleton: InnerSkeleton) { this[skeletonSymbol] = skeleton; + this[skeletonCabinSymbol] = { + Workbench: this.Workbench, + createSettingFieldView: this.createSettingFieldView, + PopupContext: InnerPopupContext, + PopupPipe: InnerPopupPipe, + SettingsPrimaryPane: InnerSettingsPrimaryPane, + registerDefaults: InnerRegisterDefaults, + Skeleton: InnerSkeleton, + }; } get Workbench(): any { @@ -242,8 +264,33 @@ class Utils implements IPublicApiCommonUtils { class EditorCabin implements IPublicApiCommonEditorCabin { private readonly [editorSymbol]: Editor; + /** + * @deprecated + */ + readonly [editorCabinSymbol]: any; + constructor(editor: Editor) { this[editorSymbol] = editor; + this[editorCabinSymbol] = { + Editor, + globalContext, + runInAction: innerRunInAction, + Title: InnerTitle, + Tip: InnerTip, + shallowIntl: innerShallowIntl, + createIntl: innerCreateIntl, + intl: innerIntl, + createSetterContent: this.createSetterContent.bind(this), + globalLocale: innerGlobalLocale, + obx: innerObx, + action: innerAction, + engineConfig: innerEngineConfig, + observable: innerObservable, + makeObservable: innerMakeObservable, + untracked: innerUntracked, + computed: innerComputed, + observer: innerObserver, + }; } /** diff --git a/packages/shell/src/symbols.ts b/packages/shell/src/symbols.ts index b4ec01c7ec..cc1be48560 100644 --- a/packages/shell/src/symbols.ts +++ b/packages/shell/src/symbols.ts @@ -24,6 +24,8 @@ export const simulatorHostSymbol = Symbol('simulatorHost'); export const dragObjectSymbol = Symbol('dragObject'); export const locateEventSymbol = Symbol('locateEvent'); export const designerCabinSymbol = Symbol('designerCabin'); +export const editorCabinSymbol = Symbol('editorCabin'); +export const skeletonCabinSymbol = Symbol('skeletonCabin'); export const hotkeySymbol = Symbol('hotkey'); export const pluginsSymbol = Symbol('plugins'); export const workspaceSymbol = Symbol('workspace'); From 857685a3b412c0155a22f1da4c0a95138544df0b Mon Sep 17 00:00:00 2001 From: liujuping Date: Mon, 28 Aug 2023 16:54:11 +0800 Subject: [PATCH 002/219] feat(node): add getRGL api --- docs/docs/api/model/node.md | 18 ++++++++ packages/designer/src/component-actions.ts | 47 ++++++++++----------- packages/designer/src/document/node/node.ts | 2 +- packages/shell/src/model/node.ts | 20 +++++++++ packages/types/src/shell/model/node.ts | 12 ++++++ 5 files changed, 74 insertions(+), 25 deletions(-) diff --git a/docs/docs/api/model/node.md b/docs/docs/api/model/node.md index c10af34660..697eefd088 100644 --- a/docs/docs/api/model/node.md +++ b/docs/docs/api/model/node.md @@ -657,4 +657,22 @@ setConditionalVisible(): void; */ getDOMNode(): HTMLElement; +``` + +### getRGL + +获取磁贴相关信息 + +```typescript +/** + * 获取磁贴相关信息 + */ +getRGL(): { + isContainerNode: boolean; + isEmptyNode: boolean; + isRGLContainerNode: boolean; + isRGLNode: boolean; + isRGL: boolean; + rglNode: Node | null; +} ``` \ No newline at end of file diff --git a/packages/designer/src/component-actions.ts b/packages/designer/src/component-actions.ts index a7a690a44d..76ead7d9a6 100644 --- a/packages/designer/src/component-actions.ts +++ b/packages/designer/src/component-actions.ts @@ -1,4 +1,4 @@ -import { IPublicTypeComponentAction, IPublicTypeMetadataTransducer } from '@alilc/lowcode-types'; +import { IPublicModelNode, IPublicTypeComponentAction, IPublicTypeMetadataTransducer } from '@alilc/lowcode-types'; import { engineConfig } from '@alilc/lowcode-editor-core'; import { intlNode } from './locale'; import { @@ -8,10 +8,11 @@ import { IconClone, IconHidden, } from './icons'; -import { Node } from './document'; import { componentDefaults, legacyIssues } from './transducers'; export class ComponentActions { + private metadataTransducers: IPublicTypeMetadataTransducer[] = []; + actions: IPublicTypeComponentAction[] = [ { name: 'remove', @@ -19,7 +20,7 @@ export class ComponentActions { icon: IconRemove, title: intlNode('remove'), /* istanbul ignore next */ - action(node: Node) { + action(node: IPublicModelNode) { node.remove(); }, }, @@ -31,13 +32,13 @@ export class ComponentActions { icon: IconHidden, title: intlNode('hide'), /* istanbul ignore next */ - action(node: Node) { - node.setVisible(false); + action(node: IPublicModelNode) { + node.visible = false; }, }, /* istanbul ignore next */ - condition: (node: Node) => { - return node.componentMeta.isModal; + condition: (node: IPublicModelNode) => { + return node.componentMeta?.isModal; }, important: true, }, @@ -47,25 +48,25 @@ export class ComponentActions { icon: IconClone, title: intlNode('copy'), /* istanbul ignore next */ - action(node: Node) { + action(node: IPublicModelNode) { // node.remove(); const { document: doc, parent, index } = node; if (parent) { - const newNode = doc.insertNode(parent, node, index + 1, true); - newNode.select(); - const { isRGL, rglNode } = node.getRGL(); + const newNode = doc?.insertNode(parent, node, (index ?? 0) + 1, true); + newNode?.select(); + const { isRGL, rglNode } = node?.getRGL(); if (isRGL) { // 复制 layout 信息 - const layout = rglNode.getPropValue('layout') || []; - const curLayout = layout.filter((item) => item.i === node.getPropValue('fieldId')); + const layout: any = rglNode?.getPropValue('layout') || []; + const curLayout = layout.filter((item: any) => item.i === node.getPropValue('fieldId')); if (curLayout && curLayout[0]) { layout.push({ ...curLayout[0], - i: newNode.getPropValue('fieldId'), + i: newNode?.getPropValue('fieldId'), }); - rglNode.setPropValue('layout', layout); + rglNode?.setPropValue('layout', layout); // 如果是磁贴块复制,则需要滚动到影响位置 - setTimeout(() => newNode.document.simulator?.scrollToNode(newNode), 10); + setTimeout(() => newNode?.document?.project?.simulatorHost?.scrollToNode(newNode), 10); } } } @@ -79,13 +80,13 @@ export class ComponentActions { icon: IconLock, // 锁定 icon title: intlNode('lock'), /* istanbul ignore next */ - action(node: Node) { + action(node: IPublicModelNode) { node.lock(); }, }, /* istanbul ignore next */ - condition: (node: Node) => { - return engineConfig.get('enableCanvasLock', false) && node.isContainer() && !node.isLocked; + condition: (node: IPublicModelNode) => { + return engineConfig.get('enableCanvasLock', false) && node.isContainerNode && !node.isLocked; }, important: true, }, @@ -95,13 +96,13 @@ export class ComponentActions { icon: IconUnlock, // 解锁 icon title: intlNode('unlock'), /* istanbul ignore next */ - action(node: Node) { + action(node: IPublicModelNode) { node.lock(false); }, }, /* istanbul ignore next */ - condition: (node: Node) => { - return engineConfig.get('enableCanvasLock', false) && node.isContainer() && node.isLocked; + condition: (node: IPublicModelNode) => { + return engineConfig.get('enableCanvasLock', false) && node.isContainerNode && node.isLocked; }, important: true, }, @@ -132,8 +133,6 @@ export class ComponentActions { } } - private metadataTransducers: IPublicTypeMetadataTransducer[] = []; - registerMetadataTransducer( transducer: IPublicTypeMetadataTransducer, level = 100, diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts index b0e509bce8..9effc341dd 100644 --- a/packages/designer/src/document/node/node.ts +++ b/packages/designer/src/document/node/node.ts @@ -1225,7 +1225,7 @@ export class Node const isRGLContainerNode = this.isRGLContainer; const isRGLNode = this.getParent()?.isRGLContainer; const isRGL = isRGLContainerNode || (isRGLNode && (!isContainerNode || !isEmptyNode)); - let rglNode = isRGLContainerNode ? this : isRGL ? this?.getParent() : {}; + let rglNode = isRGLContainerNode ? this : isRGL ? this?.getParent() : null; return { isContainerNode, isEmptyNode, isRGLContainerNode, isRGLNode, isRGL, rglNode }; } diff --git a/packages/shell/src/model/node.ts b/packages/shell/src/model/node.ts index f2cddd1ab8..29d24232eb 100644 --- a/packages/shell/src/model/node.ts +++ b/packages/shell/src/model/node.ts @@ -655,4 +655,24 @@ export class Node implements IPublicModelNode { setConditionalVisible(): void { this[nodeSymbol].setConditionalVisible(); } + + getRGL() { + const { + isContainerNode, + isEmptyNode, + isRGLContainerNode, + isRGLNode, + isRGL, + rglNode, + } = this[nodeSymbol].getRGL(); + + return { + isContainerNode, + isEmptyNode, + isRGLContainerNode, + isRGLNode, + isRGL, + rglNode: Node.create(rglNode), + }; + } } diff --git a/packages/types/src/shell/model/node.ts b/packages/types/src/shell/model/node.ts index 0255376aec..9d8cec3647 100644 --- a/packages/types/src/shell/model/node.ts +++ b/packages/types/src/shell/model/node.ts @@ -490,6 +490,18 @@ export interface IBaseModelNode< * 获取节点实例对应的 dom 节点 */ getDOMNode(): HTMLElement; + + /** + * 获取磁贴相关信息 + */ + getRGL(): { + isContainerNode: boolean; + isEmptyNode: boolean; + isRGLContainerNode: boolean; + isRGLNode: boolean; + isRGL: boolean; + rglNode: Node | null; + }; } export interface IPublicModelNode extends IBaseModelNode {} \ No newline at end of file From dc0cf5f62c7671d6743d225fac63691f58027009 Mon Sep 17 00:00:00 2001 From: liujuping Date: Mon, 28 Aug 2023 15:51:50 +0800 Subject: [PATCH 003/219] fix: fix utils under appHelper will not be updated when props.appHelper is updated --- packages/renderer-core/src/renderer/base.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index 99a9a40cfa..89dc143d5f 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -131,7 +131,6 @@ export default function baseRendererFactory(): IBaseRenderComponent { static contextType = AppContext; - appHelper?: IRendererAppHelper; i18n: any; getLocale: any; setLocale: any; @@ -174,7 +173,6 @@ export default function baseRendererFactory(): IBaseRenderComponent { __beforeInit(_props: IBaseRendererProps) { } __init(props: IBaseRendererProps) { - this.appHelper = props.__appHelper; this.__compScopes = {}; this.__instanceMap = {}; this.__bindCustomMethods(props); @@ -1019,6 +1017,10 @@ export default function baseRendererFactory(): IBaseRenderComponent { return !isSchema(schema) || !componentNames.includes(schema?.componentName ?? ''); }; + get appHelper(): IRendererAppHelper { + return this.props.__appHelper; + } + get requestHandlersMap() { return this.appHelper?.requestHandlersMap; } From a3b9d6ff48995e5580fe42b2507388a2e3ae03e2 Mon Sep 17 00:00:00 2001 From: liujuping Date: Tue, 29 Aug 2023 14:17:42 +0800 Subject: [PATCH 004/219] fix(outline-pane): when dialog is dragged, the outline pane is not displayed visible state --- packages/plugin-outline-pane/src/views/tree-title.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/plugin-outline-pane/src/views/tree-title.tsx b/packages/plugin-outline-pane/src/views/tree-title.tsx index 02ac94ae69..c8c0e75b09 100644 --- a/packages/plugin-outline-pane/src/views/tree-title.tsx +++ b/packages/plugin-outline-pane/src/views/tree-title.tsx @@ -83,6 +83,7 @@ export default class TreeTitle extends PureComponent<{ editing: false, title: treeNode.titleLabel, condition: treeNode.condition, + visible: !treeNode.hidden, }); treeNode.onTitleLabelChanged(() => { this.setState({ From 1d572ccc0b42bd7771b7503058fdfe729f814cf6 Mon Sep 17 00:00:00 2001 From: liujuping Date: Thu, 31 Aug 2023 17:15:40 +0800 Subject: [PATCH 005/219] style: udpate some style for multi theme --- packages/designer/src/project/project.less | 2 +- .../editor-core/src/widgets/tip/style.less | 2 +- .../src/components/settings/style.less | 1 - packages/editor-skeleton/src/index.ts | 1 + packages/editor-skeleton/src/layouts/index.ts | 7 + .../editor-skeleton/src/layouts/left-area.tsx | 7 +- .../src/layouts/sub-top-area.tsx | 0 .../editor-skeleton/src/layouts/theme.less | 2 + .../src/layouts/workbench.less | 136 ++++-- .../plugin-outline-pane/src/views/style.less | 6 +- .../workspace/src/layouts/bottom-area.tsx | 34 -- packages/workspace/src/layouts/left-area.tsx | 50 --- .../workspace/src/layouts/left-fixed-pane.tsx | 42 -- .../workspace/src/layouts/left-float-pane.tsx | 136 ------ packages/workspace/src/layouts/main-area.tsx | 16 - packages/workspace/src/layouts/theme.less | 62 --- packages/workspace/src/layouts/top-area.tsx | 60 --- packages/workspace/src/layouts/workbench.less | 421 ------------------ packages/workspace/src/layouts/workbench.tsx | 22 +- packages/workspace/src/view/resource-view.tsx | 2 +- 20 files changed, 138 insertions(+), 871 deletions(-) create mode 100644 packages/editor-skeleton/src/layouts/index.ts rename packages/{workspace => editor-skeleton}/src/layouts/sub-top-area.tsx (100%) delete mode 100644 packages/workspace/src/layouts/bottom-area.tsx delete mode 100644 packages/workspace/src/layouts/left-area.tsx delete mode 100644 packages/workspace/src/layouts/left-fixed-pane.tsx delete mode 100644 packages/workspace/src/layouts/left-float-pane.tsx delete mode 100644 packages/workspace/src/layouts/main-area.tsx delete mode 100644 packages/workspace/src/layouts/theme.less delete mode 100644 packages/workspace/src/layouts/top-area.tsx delete mode 100644 packages/workspace/src/layouts/workbench.less diff --git a/packages/designer/src/project/project.less b/packages/designer/src/project/project.less index 9d37c73fb4..38f1f74428 100644 --- a/packages/designer/src/project/project.less +++ b/packages/designer/src/project/project.less @@ -14,7 +14,7 @@ } .lc-simulator { - background: rgb(237, 239, 243); + background-color: var(--color-background, rgb(237, 239, 243)); } .lc-simulator-shell { diff --git a/packages/editor-core/src/widgets/tip/style.less b/packages/editor-core/src/widgets/tip/style.less index 3c02e5313e..21b60b9b5d 100644 --- a/packages/editor-core/src/widgets/tip/style.less +++ b/packages/editor-core/src/widgets/tip/style.less @@ -147,7 +147,7 @@ z-index: 2; position: fixed; box-sizing: border-box; - background: rgba(0, 0, 0, 0.7); + background: var(--color-layer-tooltip-background); max-height: 400px; color: var(--color-text-reverse, rgba(255, 255, 255, 0.8)); left: 0; diff --git a/packages/editor-skeleton/src/components/settings/style.less b/packages/editor-skeleton/src/components/settings/style.less index 23b707afd8..57a7c9357f 100644 --- a/packages/editor-skeleton/src/components/settings/style.less +++ b/packages/editor-skeleton/src/components/settings/style.less @@ -143,7 +143,6 @@ .lc-outline-pane { position: absolute; z-index: 100; - background-color: white; top: 0; bottom: 0; display: none; diff --git a/packages/editor-skeleton/src/index.ts b/packages/editor-skeleton/src/index.ts index d4851ff5b0..a39b445d1f 100644 --- a/packages/editor-skeleton/src/index.ts +++ b/packages/editor-skeleton/src/index.ts @@ -8,3 +8,4 @@ export * from './components/popup'; export * from './context'; export * from './register-defaults'; export * from './widget'; +export * from './layouts'; diff --git a/packages/editor-skeleton/src/layouts/index.ts b/packages/editor-skeleton/src/layouts/index.ts new file mode 100644 index 0000000000..b3c7a10580 --- /dev/null +++ b/packages/editor-skeleton/src/layouts/index.ts @@ -0,0 +1,7 @@ +export { default as LeftArea } from './left-area'; +export { default as LeftFloatPane } from './left-float-pane'; +export { default as LeftFixedPane } from './left-fixed-pane'; +export { default as MainArea } from './main-area'; +export { default as BottomArea } from './bottom-area'; +export { default as TopArea } from './top-area'; +export { default as SubTopArea } from './sub-top-area'; \ No newline at end of file diff --git a/packages/editor-skeleton/src/layouts/left-area.tsx b/packages/editor-skeleton/src/layouts/left-area.tsx index cbeba5a5c8..d30dcfa863 100644 --- a/packages/editor-skeleton/src/layouts/left-area.tsx +++ b/packages/editor-skeleton/src/layouts/left-area.tsx @@ -4,14 +4,14 @@ import { observer } from '@alilc/lowcode-editor-core'; import { Area } from '../area'; @observer -export default class LeftArea extends Component<{ area: Area }> { +export default class LeftArea extends Component<{ area: Area; className?: string }> { render() { - const { area } = this.props; + const { area, className = 'lc-left-area' } = this.props; if (area.isEmpty()) { return null; } return ( -
@@ -21,7 +21,6 @@ export default class LeftArea extends Component<{ area: Area }> { } } - @observer class Contents extends Component<{ area: Area }> { render() { diff --git a/packages/workspace/src/layouts/sub-top-area.tsx b/packages/editor-skeleton/src/layouts/sub-top-area.tsx similarity index 100% rename from packages/workspace/src/layouts/sub-top-area.tsx rename to packages/editor-skeleton/src/layouts/sub-top-area.tsx diff --git a/packages/editor-skeleton/src/layouts/theme.less b/packages/editor-skeleton/src/layouts/theme.less index b0da053db1..53afb69328 100644 --- a/packages/editor-skeleton/src/layouts/theme.less +++ b/packages/editor-skeleton/src/layouts/theme.less @@ -16,6 +16,7 @@ --color-icon-hover: @normal-alpha-3; --color-icon-active: @brand-color-1; --color-icon-reverse: @white-alpha-1; + --color-icon-pane: @dark-alpha-3; --color-line-normal: @normal-alpha-7; --color-line-darken: darken(@normal-alpha-7, 10%); @@ -57,6 +58,7 @@ --color-block-background-deep-dark: @normal-5; --color-layer-mask-background: @dark-alpha-7; --color-layer-tooltip-background: rgba(44,47,51,0.8); + --color-background: #edeff3; --pane-title-bg-color: rgba(31,56,88,.04); } diff --git a/packages/editor-skeleton/src/layouts/workbench.less b/packages/editor-skeleton/src/layouts/workbench.less index fccdad4c2d..0a034822f4 100644 --- a/packages/editor-skeleton/src/layouts/workbench.less +++ b/packages/editor-skeleton/src/layouts/workbench.less @@ -38,7 +38,7 @@ body { font-family: var(--font-family); font-size: var(--font-size-text); color: var(--color-text); - background-color: #edeff3; + background-color: var(--color-background); } * { @@ -49,13 +49,10 @@ body { width: 100%; height: 100%; position: relative; - background-color: #fff; - background-color: var(--color-pane-background); &.hidden { display: none; } .lc-panel-title { - // background-color: var(--pane-title-bg-color,rgba(31,56,88,.04)); display: flex; align-items: center; justify-content: flex-start; @@ -71,7 +68,6 @@ body { height: 48px; font-size: 16px; padding: 0 15px; - // border-bottom: 1px solid var(--color-line-normal,rgba(31,56,88,.1)); color: #0f1726; font-weight: bold; } @@ -125,9 +121,6 @@ body { height: 100%; width: 100%; position: relative; - background-color: #fff; - background-color: var(--color-pane-background); - // overflow: auto; &.hidden { display: none; } @@ -137,7 +130,7 @@ body { height: 100%; display: flex; flex-direction: column; - background-color: #edeff3; + background-color: var(--color-background); position: absolute; left: 0; top: 0; @@ -164,47 +157,58 @@ body { &.active { z-index: 999; - background: #edeff3; + background: var(--color-background); } } } -.lc-workbench { +.lc-workbench, .lc-workspace-workbench { height: 100%; display: flex; flex-direction: column; - background-color: #edeff3; + background-color: var(--color-background); &.engine-main { height: 100%; display: flex; flex-direction: column; - background-color: #edeff3; + background-color: var(--color-background); } - .lc-top-area { - height: var(--top-area-height); - background-color: var(--color-pane-background); + .lc-top-area, .lc-sub-top-area { width: 100%; display: none; margin-bottom: 2px; padding: 8px 12px 8px 16px; + &.lc-top-area { + background-color: var(--color-top-area-background, var(--color-pane-background)); + height: var(--top-area-height); + } + + &.lc-sub-top-area { + background-color: var(--color-sub-top-area-background, var(--color-pane-background)); + height: var(--sub-top-area-height, var(--top-area-height)); + margin: var(--sub-top-area-margin, 0px 0px 2px 0px); + padding: var(--sub-top-area-padding, 8px 12px 8px 16px); + } + &.lc-area-visible { display: flex; } - .lc-top-area-left { + .lc-top-area-left, .lc-sub-top-area-left { display: flex; align-items: center; + max-width: 100%; } - .lc-top-area-center { + .lc-top-area-center, .lc-sub-top-area-center { flex: 1; display: flex; justify-content: center; margin: 0 8px; } - .lc-top-area-right { + .lc-top-area-right, .lc-sub-top-area-right { display: flex; align-items: center; > * { @@ -216,7 +220,7 @@ body { } } } - .lc-workbench-body { + .lc-workbench-body, .lc-workspace-workbench-body { flex: 1; display: flex; min-height: 0; @@ -264,7 +268,7 @@ body { z-index: 2; .next-icon { line-height: 1; - color: rgba(0, 0, 0, 0.6); + color: var(--color-icon-pane); } } @@ -277,7 +281,7 @@ body { z-index: 2; svg { vertical-align: middle; - color: rgba(0, 0, 0, 0.6); + color: var(--color-icon-pane); } } @@ -288,7 +292,7 @@ body { width: var(--dock-pane-width); // min-width: var(--dock-fixed-pane-width); left: calc(var(--left-area-width) + 1px); - background-color: var(--color-pane-background); + background-color: var(--color-left-float-pane-background, var(--color-pane-background)); box-shadow: 4px 6px 6px 0 rgba(31, 50, 88, 0.08); z-index: 820; display: none; @@ -297,15 +301,20 @@ body { display: block; } } - .lc-left-area { + .lc-left-area, .lc-workspace-left-area { height: 100%; width: var(--left-area-width); - background-color: var(--color-pane-background); display: none; flex-shrink: 0; flex-direction: column; justify-content: space-between; overflow: hidden; + &.lc-left-area { + background-color: var(--color-left-area-background, var(--color-pane-background)); + } + &.lc-workspace-left-area { + background-color: var(--color-workspace-left-area-background, var(--color-pane-background)); + } &.lc-area-visible { display: flex; } @@ -316,6 +325,8 @@ body { flex-direction: column; justify-content: flex-start; align-items: center; + color: var(--color-text); + .lc-title { flex-direction: column; width: calc(var(--left-area-width) - 2px); @@ -325,6 +336,9 @@ body { justify-content: center; cursor: pointer; + &.has-tip { + cursor: pointer; + } &.actived { color: #0079f2; } @@ -366,6 +380,9 @@ body { .lc-left-area.lc-area-visible ~ .lc-workbench-center { margin-left: 2px; } + .lc-workspace-left-area.lc-area-visible ~ .lc-workspace-workbench-center { + margin-left: 2px; + } .lc-outline-pane { .lc-outline-tree .tree-node .tree-node-title { border-bottom: none; @@ -390,7 +407,7 @@ body { } .lc-main-area { flex: 1; - background-color: #edeff3; + background-color: var(--color-background); } .lc-bottom-area { height: var(--bottom-area-height); @@ -404,13 +421,14 @@ body { .lc-right-area { height: 100%; width: var(--right-area-width); - background-color: var(--color-pane-background); + background-color: var(--color-right-area-background, var(--color-pane-background)); display: none; flex-shrink: 0; margin-left: 2px; position: relative; > .lc-panel { position: absolute; + background-color: var(--color-right-area-background, var(--color-pane-background, #fff)); left: 0; top: 0; } @@ -437,4 +455,68 @@ body { } } } + .engine-actionitem { + max-width: 100%; + color: var(--color-text); + } +} + +.lc-workspace-workbench { + height: 100%; + display: flex; + flex-direction: column; + background-color: var(--color-background); + .lc-workspace-workbench-body { + flex: 1; + display: flex; + min-height: 0; + position: relative; + + .lc-workspace-workbench-center { + flex: 1; + display: flex; + flex-direction: column; + z-index: 10; + position: relative; + .lc-toolbar { + display: flex; + height: var(--toolbar-height); + background-color: var(--color-pane-background); + padding: 8px 16px; + .lc-toolbar-center { + display: flex; + justify-content: center; + align-items: center; + flex: 1; + } + } + .lc-main-area { + flex: 1; + } + .lc-bottom-area { + height: var(--bottom-area-height); + background-color: var(--color-pane-background); + display: none; + &.lc-area-visible { + display: block; + } + } + } + + .lc-workspace-workbench-center-content { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + flex-direction: column; + display: flex; + align-content: stretch; + } + + .lc-workspace-workbench-window { + position: relative; + height: 100%; + } + } } diff --git a/packages/plugin-outline-pane/src/views/style.less b/packages/plugin-outline-pane/src/views/style.less index 254b639d62..406a5b5da4 100644 --- a/packages/plugin-outline-pane/src/views/style.less +++ b/packages/plugin-outline-pane/src/views/style.less @@ -3,7 +3,6 @@ width: 100%; position: relative; z-index: 200; - background-color: white; > .lc-outline-tree-container { top: 52px; @@ -29,8 +28,8 @@ } .lc-outline-filter-icon { - background: #ebecf0; - border: 1px solid #c4c6cf; + background: var(--color-block-background-shallow, #ebecf0); + border: 1px solid var(--color-field-border, #c4c6cf); display: flex; align-items: center; border-radius: 0 2px 2px 0; @@ -245,7 +244,6 @@ .tree-node-title { font-size: var(--font-size-text); cursor: pointer; - background: var(--color-pane-background); border-bottom: 1px solid var(--color-line-normal, rgba(31, 56, 88, 0.1)); display: flex; align-items: center; diff --git a/packages/workspace/src/layouts/bottom-area.tsx b/packages/workspace/src/layouts/bottom-area.tsx deleted file mode 100644 index 5fc4d815bc..0000000000 --- a/packages/workspace/src/layouts/bottom-area.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { Component, Fragment } from 'react'; -import classNames from 'classnames'; -import { observer } from '@alilc/lowcode-editor-core'; -import { Area, Panel } from '@alilc/lowcode-editor-skeleton'; - -@observer -export default class BottomArea extends Component<{ area: Area }> { - render() { - const { area } = this.props; - if (area.isEmpty()) { - return null; - } - return ( -
- -
- ); - } -} - -@observer -class Contents extends Component<{ area: Area }> { - render() { - const { area } = this.props; - return ( - - {area.container.items.map((item) => item.content)} - - ); - } -} diff --git a/packages/workspace/src/layouts/left-area.tsx b/packages/workspace/src/layouts/left-area.tsx deleted file mode 100644 index 3057386eda..0000000000 --- a/packages/workspace/src/layouts/left-area.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { Component, Fragment } from 'react'; -import classNames from 'classnames'; -import { observer } from '@alilc/lowcode-editor-core'; -import { Area } from '@alilc/lowcode-editor-skeleton'; - -@observer -export default class LeftArea extends Component<{ area: Area }> { - render() { - const { area } = this.props; - if (area.isEmpty()) { - return null; - } - return ( -
- -
- ); - } -} - - -@observer -class Contents extends Component<{ area: Area }> { - render() { - const { area } = this.props; - const top: any[] = []; - const bottom: any[] = []; - area.container.items.slice().sort((a, b) => { - const index1 = a.config?.index || 0; - const index2 = b.config?.index || 0; - return index1 === index2 ? 0 : (index1 > index2 ? 1 : -1); - }).forEach((item) => { - const content =
{item.content}
; - if (item.align === 'bottom') { - bottom.push(content); - } else { - top.push(content); - } - }); - return ( - -
{top}
-
{bottom}
-
- ); - } -} diff --git a/packages/workspace/src/layouts/left-fixed-pane.tsx b/packages/workspace/src/layouts/left-fixed-pane.tsx deleted file mode 100644 index e0c01c5109..0000000000 --- a/packages/workspace/src/layouts/left-fixed-pane.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { Component, Fragment } from 'react'; -import classNames from 'classnames'; -import { observer } from '@alilc/lowcode-editor-core'; -import { Area, Panel, PanelConfig } from '@alilc/lowcode-editor-skeleton'; - -@observer -export default class LeftFixedPane extends Component<{ area: Area }> { - componentDidUpdate() { - // FIXME: dirty fix, need deep think - this.props.area.skeleton.editor.get('designer')?.touchOffsetObserver(); - } - - - render() { - const { area } = this.props; - const width = area.current?.config.props?.width; - const style = width - ? { - width, - } - : undefined; - - return ( -
- -
- ); - } -} - -@observer -class Contents extends Component<{ area: Area }> { - render() { - const { area } = this.props; - return {area.container.items.map((panel) => panel.content)}; - } -} diff --git a/packages/workspace/src/layouts/left-float-pane.tsx b/packages/workspace/src/layouts/left-float-pane.tsx deleted file mode 100644 index 3df3e197c2..0000000000 --- a/packages/workspace/src/layouts/left-float-pane.tsx +++ /dev/null @@ -1,136 +0,0 @@ -import { Component, Fragment } from 'react'; -import classNames from 'classnames'; -import { observer, Focusable } from '@alilc/lowcode-editor-core'; -import { Area, Panel } from '@alilc/lowcode-editor-skeleton'; -import { IPublicApiProject } from '@alilc/lowcode-types'; - -@observer -export default class LeftFloatPane extends Component<{ area: Area }> { - private dispose?: () => void; - - private focusing?: Focusable; - - private shell: HTMLElement | null = null; - - componentDidMount() { - const { area } = this.props; - const triggerClose = (e: any) => { - if (!area.visible) return; - // 当 MouseEvent 的 target 为「插入占位符」时,不关闭当前 panel - if (e.originalEvent?.target?.classList.contains('insertion')) return; - // 假如当前操作 target 祖先节点中有属性 data-keep-visible-while-dragging="true" 代表该 target 所属 panel - // 不希望 target 在 panel 范围内拖拽时关闭 panel - const panelElem = e.originalEvent?.target.closest('div[data-keep-visible-while-dragging="true"]'); - if (panelElem) return; - area.setVisible(false); - }; - area.skeleton.editor.eventBus.on('designer.drag', triggerClose); - - this.dispose = () => { - area.skeleton.editor.removeListener('designer.drag', triggerClose); - }; - - const project: IPublicApiProject | undefined = area.skeleton.editor.get('project'); - - this.focusing = area.skeleton.focusTracker.create({ - range: (e) => { - const target = e.target as HTMLElement; - if (!target) { - return false; - } - if (this.shell?.contains(target)) { - return true; - } - // 点击了 iframe 内容,算失焦 - if ((document.querySelector('.lc-simulator-content-frame') as HTMLIFrameElement)?.contentWindow?.document.documentElement.contains(target)) { - return false; - } - if (project?.simulatorHost?.contentWindow?.document.documentElement.contains(target)) { - return false; - } - // 点击设置区 - if (document.querySelector('.lc-right-area')?.contains(target)) { - return false; - } - // 点击非编辑区域的popup/dialog,插件栏左侧等不触发失焦 - if (!document.querySelector('.lc-workbench')?.contains(target)) { - return true; - } - // 排除设置区,iframe 之后,都不算失焦 - if (document.querySelector('.lc-workbench-body')?.contains(target)) { - return true; - } - const docks = area.current?.getAssocDocks(); - if (docks && docks?.length) { - return docks.some(dock => dock.getDOMNode()?.contains(target)); - } - return false; - }, - onEsc: () => { - this.props.area.setVisible(false); - }, - onBlur: () => { - this.props.area.setVisible(false); - }, - }); - - this.onEffect(); - } - - onEffect() { - const { area } = this.props; - if (area.visible) { - this.focusing?.active(); - // 关闭当前fixed区域的面板 - // TODO: 看看有没有更合适的地方 - const fixedContainer = area?.skeleton?.leftFixedArea?.container; - const currentFixed = fixedContainer?.current; - if (currentFixed) { - fixedContainer.unactive(currentFixed); - } - } else { - this.focusing?.suspense(); - } - } - - componentDidUpdate() { - this.onEffect(); - } - - componentWillUnmount() { - this.focusing?.purge(); - this.dispose?.(); - } - - render() { - const { area } = this.props; - const width = area.current?.config.props?.width; - - const style = width ? { - width, - } : undefined; - return ( -
{ this.shell = ref; }} - className={classNames('lc-left-float-pane', { - 'lc-area-visible': area.visible, - })} - style={style} - > - -
- ); - } -} - -@observer -class Contents extends Component<{ area: Area }> { - render() { - const { area } = this.props; - return ( - - {area.container.items.map((panel) => panel.content)} - - ); - } -} diff --git a/packages/workspace/src/layouts/main-area.tsx b/packages/workspace/src/layouts/main-area.tsx deleted file mode 100644 index 5313d7007e..0000000000 --- a/packages/workspace/src/layouts/main-area.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { Component } from 'react'; -import classNames from 'classnames'; -import { observer } from '@alilc/lowcode-editor-core'; -import { Area, Panel, Widget } from '@alilc/lowcode-editor-skeleton'; - -@observer -export default class MainArea extends Component<{ area: Area }> { - render() { - const { area } = this.props; - return ( -
- {area.container.items.map((item) => item.content)} -
- ); - } -} diff --git a/packages/workspace/src/layouts/theme.less b/packages/workspace/src/layouts/theme.less deleted file mode 100644 index b0da053db1..0000000000 --- a/packages/workspace/src/layouts/theme.less +++ /dev/null @@ -1,62 +0,0 @@ -@import '../less-variables.less'; - -/* - * Theme Colors - * - * 乐高设计器的主要主题色变量 - */ -:root { - --color-brand: @brand-color-1; - --color-brand-light: @brand-color-2; - --color-brand-dark: @brand-color-3; - - --color-canvas-background: @normal-alpha-8; - - --color-icon-normal: @normal-alpha-4; - --color-icon-hover: @normal-alpha-3; - --color-icon-active: @brand-color-1; - --color-icon-reverse: @white-alpha-1; - - --color-line-normal: @normal-alpha-7; - --color-line-darken: darken(@normal-alpha-7, 10%); - - --color-title: @dark-alpha-2; - --color-text: @dark-alpha-3; - --color-text-dark: darken(@dark-alpha-3, 10%); - --color-text-light: lighten(@dark-alpha-3, 10%); - --color-text-reverse: @white-alpha-2; - --color-text-regular: @normal-alpha-2; - - --color-field-label: @dark-alpha-4; - --color-field-text: @dark-alpha-3; - --color-field-placeholder: @normal-alpha-5; - --color-field-border: @normal-alpha-5; - --color-field-border-hover: @normal-alpha-4; - --color-field-border-active: @normal-alpha-3; - --color-field-background: @white-alpha-1; - - --color-function-success: @brand-success; - --color-function-success-dark: darken(@brand-success, 10%); - --color-function-success-light: lighten(@brand-success, 10%); - --color-function-warning: @brand-warning; - --color-function-warning-dark: darken(@brand-warning, 10%); - --color-function-warning-light: lighten(@brand-warning, 10%); - --color-function-information: @brand-link-hover; - --color-function-information-dark: darken(@brand-link-hover, 10%); - --color-function-information-light: lighten(@brand-link-hover, 10%); - --color-function-error: @brand-danger; - --color-function-error-dark: darken(@brand-danger, 10%); - --color-function-error-light: lighten(@brand-danger, 10%); - - --color-pane-background: @white-alpha-1; - --color-block-background-normal: @white-alpha-1; - --color-block-background-light: @normal-alpha-9; - --color-block-background-shallow: @normal-alpha-8; - --color-block-background-dark: @normal-alpha-7; - --color-block-background-disabled: @normal-alpha-6; - --color-block-background-deep-dark: @normal-5; - --color-layer-mask-background: @dark-alpha-7; - --color-layer-tooltip-background: rgba(44,47,51,0.8); - - --pane-title-bg-color: rgba(31,56,88,.04); -} diff --git a/packages/workspace/src/layouts/top-area.tsx b/packages/workspace/src/layouts/top-area.tsx deleted file mode 100644 index cecaee2a71..0000000000 --- a/packages/workspace/src/layouts/top-area.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import { Component, Fragment } from 'react'; -import classNames from 'classnames'; -import { observer } from '@alilc/lowcode-editor-core'; -import { Area } from '@alilc/lowcode-editor-skeleton'; - -@observer -export default class TopArea extends Component<{ area: Area; itemClassName?: string }> { - render() { - const { area, itemClassName } = this.props; - - if (area.isEmpty()) { - return null; - } - - return ( -
- -
- ); - } -} - -@observer -class Contents extends Component<{ area: Area; itemClassName?: string }> { - render() { - const { area, itemClassName } = this.props; - const left: any[] = []; - const center: any[] = []; - const right: any[] = []; - area.container.items.slice().sort((a, b) => { - const index1 = a.config?.index || 0; - const index2 = b.config?.index || 0; - return index1 === index2 ? 0 : (index1 > index2 ? 1 : -1); - }).forEach(item => { - const content = ( -
- {item.content} -
- ); - if (item.align === 'center') { - center.push(content); - } else if (item.align === 'left') { - left.push(content); - } else { - right.push(content); - } - }); - - return ( - -
{left}
-
{center}
-
{right}
-
- ); - } -} diff --git a/packages/workspace/src/layouts/workbench.less b/packages/workspace/src/layouts/workbench.less deleted file mode 100644 index 05eb5f513b..0000000000 --- a/packages/workspace/src/layouts/workbench.less +++ /dev/null @@ -1,421 +0,0 @@ -@import './theme.less'; - -:root { - --font-family: @font-family; - --font-size-label: @fontSize-4; - --font-size-text: @fontSize-5; - --font-size-btn-large: @fontSize-3; - --font-size-btn-medium: @fontSize-4; - --font-size-btn-small: @fontSize-5; - - --global-border-radius: @global-border-radius; - --input-border-radius: @input-border-radius; - --popup-border-radius: @popup-border-radius; - - --left-area-width: 48px; - --right-area-width: 300px; - --top-area-height: 48px; - --toolbar-height: 36px; - --dock-pane-width: 300px; - --dock-fixed-pane-width: 300px; -} - -@media (min-width: 1860px) { - :root { - --right-area-width: 400px; - --dock-pane-width: 452px; - --dock-fixed-pane-width: 350px; - } -} - -html, -body { - height: 100%; - overflow: hidden; - padding: 0; - margin: 0; - position: relative; - font-family: var(--font-family); - font-size: var(--font-size-text); - color: var(--color-text); - background-color: #edeff3; -} - -* { - box-sizing: border-box; -} - -.lc-titled-panel { - width: 100%; - height: 100%; - position: relative; - background-color: #fff; - background-color: var(--color-pane-background); - &.hidden { - display: none; - } - .lc-panel-title { - // background-color: var(--pane-title-bg-color,rgba(31,56,88,.04)); - display: flex; - align-items: center; - justify-content: flex-start; - padding: 0 15px; - - .lc-help-tip { - margin-left: 4px; - color: rgba(0, 0, 0, 0.4); - cursor: pointer; - } - } - > .lc-panel-title { - height: 48px; - font-size: 16px; - padding: 0 15px; - // border-bottom: 1px solid var(--color-line-normal,rgba(31,56,88,.1)); - color: #0f1726; - font-weight: bold; - } - - .lc-panel-body { - position: absolute; - top: 48px; - bottom: 0; - left: 0; - right: 0; - overflow: visible; - /* - .my-tabs { - width: 100%; - height: 100%; - position: relative; - .tabs-title { - display: flex; - height: var(--pane-title-height); - > .tab-title { - cursor: pointer; - padding: 0; - flex: 1; - min-width: 0; - justify-content: center; - border-bottom: 2px solid transparent; - &.actived { - cursor: default; - color: var(--color-text-avtived); - border-bottom-color: #3896ee; - } - } - } - .tabs-content { - position: absolute; - top: var(--pane-title-height); - bottom: 0; - left: 0; - right: 0; - height: calc(100% - var(--pane-title-height)); - overflow: hidden; - } - } - */ - } - .lc-outline-tree-container { - border-top: 1px solid var(--color-line-normal, rgba(31, 56, 88, 0.1)); - } -} -.lc-panel { - height: 100%; - width: 100%; - position: relative; - background-color: #fff; - background-color: var(--color-pane-background); - // overflow: auto; - &.hidden { - display: none; - } -} - -.lc-workspace-workbench { - height: 100%; - display: flex; - flex-direction: column; - background-color: #edeff3; - .lc-top-area, .lc-sub-top-area { - height: var(--top-area-height); - background-color: var(--color-pane-background); - width: 100%; - display: none; - margin-bottom: 2px; - padding: 8px 12px 8px 16px; - - &.lc-area-visible { - display: flex; - } - - .lc-top-area-left, .lc-sub-top-area-left { - display: flex; - align-items: center; - max-width: 100%; - } - - .lc-top-area-center, .lc-sub-top-area-center { - flex: 1; - display: flex; - justify-content: center; - margin: 0 8px; - } - .lc-top-area-right, .lc-sub-top-area-right { - display: flex; - align-items: center; - > * { - margin-left: 4px; - margin-right: 4px; - } - .ve-quick-search-trigger { - display: flex; - } - } - } - .lc-workspace-workbench-body { - flex: 1; - display: flex; - min-height: 0; - position: relative; - - .lc-tabs-title { - width: 100%; - height: 32px; - position: relative; - display: center; - display: flex; - justify-content: center; - align-items: center; - // background: rgba(31,56,88,0.04); - border-bottom: 1px solid #edeff3; - .lc-tab-title { - flex: 1; - height: 32px; - display: flex; - align-items: center; - justify-content: center; - border-bottom: 2px solid transparent; - cursor: pointer; - font-size: 12px; - &.actived { - color: #0079f2; - border-bottom-color: #0079f2; - } - } - } - - .lc-tabs-content { - position: absolute; - top: 32px; - bottom: 0; - left: 0; - right: 0; - } - - .lc-pane-icon-close { - position: absolute; - right: 16px; - top: 14px; - height: auto; - z-index: 2; - .next-icon { - line-height: 1; - color: rgba(0, 0, 0, 0.6); - } - } - - .lc-pane-icon-fix, - .lc-pane-icon-float { - position: absolute; - right: 38px; - top: 14px; - height: auto; - z-index: 2; - svg { - vertical-align: middle; - color: rgba(0, 0, 0, 0.6); - } - } - - .lc-left-float-pane { - position: absolute; - top: 0; - bottom: 0; - width: var(--dock-pane-width); - // min-width: var(--dock-fixed-pane-width); - left: calc(var(--left-area-width) + 1px); - background-color: var(--color-pane-background); - box-shadow: 4px 6px 6px 0 rgba(31, 50, 88, 0.08); - z-index: 820; - display: none; - // padding-top: 36px; - &.lc-area-visible { - display: block; - } - } - .lc-left-area { - height: 100%; - width: var(--left-area-width); - background-color: var(--color-pane-background); - display: none; - flex-shrink: 0; - flex-direction: column; - justify-content: space-between; - overflow: hidden; - &.lc-area-visible { - display: flex; - } - .lc-left-area-top, - .lc-left-area-bottom { - width: 100%; - display: flex; - flex-direction: column; - justify-content: flex-start; - align-items: center; - .lc-title { - flex-direction: column; - width: calc(var(--left-area-width) - 2px); - height: 46px; - display: flex; - align-items: center; - justify-content: center; - - &.has-tip { - cursor: pointer; - } - &.actived { - color: #0079f2; - } - &.disabled { - opacity: 0.4; - } - .lc-title-icon { - height: 20px; - width: 20px; - margin: 0; - .next-icon:before { - line-height: 1 !important; - } - } - } - } - .lc-left-area-top { - padding-top: 12px; - } - .lc-left-area-bottom { - padding-bottom: 12px; - } - } - .lc-left-fixed-pane { - width: var(--dock-fixed-pane-width); - background-color: var(--color-pane-background); - height: 100%; - display: none; - flex-shrink: 0; - position: relative; - z-index: 820; - &.lc-area-visible { - display: block; - } - } - .lc-left-area.lc-area-visible ~ .lc-left-fixed-pane { - margin-left: 1px; - } - .lc-left-area.lc-area-visible ~ .lc-workspace-workbench-center { - margin-left: 2px; - } - .lc-outline-pane { - .lc-outline-tree .tree-node .tree-node-title { - border-bottom: none; - } - } - .lc-workspace-workbench-center { - flex: 1; - display: flex; - flex-direction: column; - z-index: 10; - position: relative; - .lc-toolbar { - display: flex; - height: var(--toolbar-height); - background-color: var(--color-pane-background); - padding: 8px 16px; - .lc-toolbar-center { - display: flex; - justify-content: center; - align-items: center; - flex: 1; - } - } - .lc-main-area { - flex: 1; - } - .lc-bottom-area { - height: var(--bottom-area-height); - background-color: var(--color-pane-background); - display: none; - &.lc-area-visible { - display: block; - } - } - } - - .lc-workspace-workbench-center-content { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - flex-direction: column; - display: flex; - align-content: stretch; - } - - .engine-actionitem { - max-width: 100%; - } - - .lc-workspace-workbench-window { - position: relative; - height: 100%; - } - - .lc-right-area { - height: 100%; - width: var(--right-area-width); - background-color: var(--color-pane-background); - display: none; - flex-shrink: 0; - margin-left: 2px; - position: relative; - > .lc-panel { - position: absolute; - left: 0; - top: 0; - } - &.lc-area-visible { - display: block; - } - .lc-settings-tabs { - > .next-tabs-nav-extra { - top: 36px !important; - } - .lc-settings-tab-item { - .next-tabs-tab-inner { - font-size: 12px; - line-height: 12px; - } - } - .lc-title { - color: inherit; - line-height: inherit !important; - } - } - .lc-settings-tabs-content { - top: 66px; - } - } - } -} diff --git a/packages/workspace/src/layouts/workbench.tsx b/packages/workspace/src/layouts/workbench.tsx index 08d6dc1a93..7d2d96df12 100644 --- a/packages/workspace/src/layouts/workbench.tsx +++ b/packages/workspace/src/layouts/workbench.tsx @@ -2,17 +2,10 @@ import { Component } from 'react'; import { TipContainer, engineConfig, observer } from '@alilc/lowcode-editor-core'; import { WindowView } from '../view/window-view'; import classNames from 'classnames'; -import TopArea from './top-area'; -import LeftArea from './left-area'; -import LeftFixedPane from './left-fixed-pane'; -import LeftFloatPane from './left-float-pane'; -import MainArea from './main-area'; -import BottomArea from './bottom-area'; -import './workbench.less'; import { SkeletonContext } from '../skeleton-context'; import { EditorConfig, PluginClassSet } from '@alilc/lowcode-types'; import { Workspace } from '../workspace'; -import SubTopArea from './sub-top-area'; +import { BottomArea, LeftArea, LeftFixedPane, LeftFloatPane, MainArea, SubTopArea, TopArea } from '@alilc/lowcode-editor-skeleton'; @observer export class Workbench extends Component<{ @@ -23,12 +16,18 @@ export class Workbench extends Component<{ topAreaItemClassName?: string; }, { workspaceEmptyComponent: any; + theme?: string; }> { constructor(props: any) { super(props); const { config, components, workspace } = this.props; const { skeleton } = workspace; skeleton.buildFromConfig(config, components); + engineConfig.onGot('theme', (theme) => { + this.setState({ + theme, + }); + }); engineConfig.onGot('workspaceEmptyComponent', (workspaceEmptyComponent) => { this.setState({ workspaceEmptyComponent, @@ -36,20 +35,21 @@ export class Workbench extends Component<{ }); this.state = { workspaceEmptyComponent: engineConfig.get('workspaceEmptyComponent'), + theme: engineConfig.get('theme'), }; } render() { const { workspace, className, topAreaItemClassName } = this.props; const { skeleton } = workspace; - const WorkspaceEmptyComponent = this.state.workspaceEmptyComponent; + const { workspaceEmptyComponent: WorkspaceEmptyComponent, theme } = this.state; return ( -
+
- +
diff --git a/packages/workspace/src/view/resource-view.tsx b/packages/workspace/src/view/resource-view.tsx index 9ef30af092..e2204dd505 100644 --- a/packages/workspace/src/view/resource-view.tsx +++ b/packages/workspace/src/view/resource-view.tsx @@ -1,10 +1,10 @@ import { PureComponent } from 'react'; import { EditorView } from './editor-view'; import { observer } from '@alilc/lowcode-editor-core'; -import TopArea from '../layouts/top-area'; import { IResource } from '../resource'; import { IEditorWindow } from '../window'; import './resource-view.less'; +import { TopArea } from '@alilc/lowcode-editor-skeleton'; @observer export class ResourceView extends PureComponent<{ From f48c49c21f72c34cb3b0791baa39ba7e8629c74b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=BE=E5=B8=85?= <21106848+sdshaoda@users.noreply.github.com> Date: Thu, 31 Aug 2023 16:26:30 +0800 Subject: [PATCH 006/219] docs: Update summary.md add material spec link --- docs/docs/guide/design/summary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/guide/design/summary.md b/docs/docs/guide/design/summary.md index cd5edfd886..38d523cac9 100644 --- a/docs/docs/guide/design/summary.md +++ b/docs/docs/guide/design/summary.md @@ -20,7 +20,7 @@ sidebar_position: 0 低代码引擎分为 4 大模块,入料 - 编排 - 渲染 - 出码: -- 入料模块就是将外部的物料,比如海量的 npm 组件,按照《物料描述协议》进行描述。将描述后的数据通过引擎 API 注册后,在编辑器中使用。 +- 入料模块就是将外部的物料,比如海量的 npm 组件,按照[《低代码引擎物料协议规范》](/site/docs/specs/material-spec)进行描述。将描述后的数据通过引擎 API 注册后,在编辑器中使用。 > **注意,这里仅是增加描述,而非重写一套,这样我们能最大程度复用 ProCode 体系已沉淀的组件。** - 编排,本质上来讲,就是**不断在生成符合[《低代码引擎搭建协议规范》](/site/docs/specs/lowcode-spec)的页面描述,将编辑器中的所有物料,进行布局设置、组件 CRUD 操作、以及 JS / CSS 编写/ 逻辑编排 **等,最终转换成页面描述,技术细节后文会展开。 - 渲染,顾名思义,就是**将编排生成的页面描述结构渲染成视图的过程**,视图是面向用户的,所以必须处理好内部数据流、生命周期、事件绑定、国际化等。 From 2c2241ef73d5582084202e562dd82f551c8367f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= Date: Mon, 4 Sep 2023 11:44:36 +0800 Subject: [PATCH 007/219] Revert "fix(material): fix rendering is blocked, when the url in the asset fails to load" This reverts commit 8b5e2b47c6668817e365b31277f2b2d6c9313cca. --- packages/editor-core/src/editor.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/editor-core/src/editor.ts b/packages/editor-core/src/editor.ts index 10aa0bea1c..f31a2a2dda 100644 --- a/packages/editor-core/src/editor.ts +++ b/packages/editor-core/src/editor.ts @@ -153,11 +153,7 @@ export class Editor extends EventEmitter implements IEditor { return; } if (!AssetsCache[exportName] || !npm?.version || AssetsCache[exportName].npm?.version !== npm?.version) { - try { - await (new AssetLoader()).load(url); - } catch (error) { - console.error(`${url} load error: `, error); - } + await (new AssetLoader()).load(url); } AssetsCache[exportName] = component; function setAssetsComponent(component: any, extraNpmInfo: any = {}) { From bfdc7a277ba4713dbfdd1c9efe01bbd9126a4219 Mon Sep 17 00:00:00 2001 From: liujuping Date: Mon, 4 Sep 2023 11:51:18 +0800 Subject: [PATCH 008/219] feat(workspace): fix onWindowRendererReady api --- packages/workspace/src/layouts/workbench.tsx | 2 +- packages/workspace/src/window.ts | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/workspace/src/layouts/workbench.tsx b/packages/workspace/src/layouts/workbench.tsx index 7d2d96df12..9bdbe3f932 100644 --- a/packages/workspace/src/layouts/workbench.tsx +++ b/packages/workspace/src/layouts/workbench.tsx @@ -49,7 +49,7 @@ export class Workbench extends Component<{
- +
diff --git a/packages/workspace/src/window.ts b/packages/workspace/src/window.ts index 2c670346fb..ce5aab4142 100644 --- a/packages/workspace/src/window.ts +++ b/packages/workspace/src/window.ts @@ -126,9 +126,10 @@ export class EditorWindow implements IEditorWindow { async init() { await this.initViewTypes(); await this.execViewTypesInit(); - Promise.all(Array.from(this.editorViews.values()).map((d) => d.onSimulatorRendererReady)).then(() => { - this.workspace.emitWindowRendererReady(); - }); + Promise.all(Array.from(this.editorViews.values()).map((d) => d.onSimulatorRendererReady())) + .then(() => { + this.workspace.emitWindowRendererReady(); + }); this.url = await this.resource.url(); this.setDefaultViewName(); this.initReady = true; From 4677d99127f25f202805b23f661c7f1cc1fc5a3a Mon Sep 17 00:00:00 2001 From: "chenkeyao.chenkeya" Date: Tue, 5 Sep 2023 14:53:30 +0800 Subject: [PATCH 009/219] feat: Modify the content of the article menu and add a video menu --- docs/config/navbar.js | 6 ++++++ docs/docs/article/index.md | 32 ++------------------------------ docs/docs/video/index.md | 13 +++++++++++++ 3 files changed, 21 insertions(+), 30 deletions(-) create mode 100644 docs/docs/video/index.md diff --git a/docs/config/navbar.js b/docs/config/navbar.js index 20d5e5f90c..24f8a39376 100644 --- a/docs/config/navbar.js +++ b/docs/config/navbar.js @@ -39,6 +39,12 @@ module.exports = { position: 'left', label: '文章', }, + { + type: 'doc', + docId: 'video/index', + position: 'left', + label: '视频', + }, { type: 'doc', docId: 'demoUsage/intro', diff --git a/docs/docs/article/index.md b/docs/docs/article/index.md index 8ff76ff476..2f6f2cee3f 100644 --- a/docs/docs/article/index.md +++ b/docs/docs/article/index.md @@ -1,8 +1,4 @@ ---- -title: 低代码引擎相关文章资料 ---- - -## 官方文章 +# 官方文章 - [2023/04/04 什么?低代码引擎可以开发应用了](https://mp.weixin.qq.com/s/dwi40gJjGBHW9MVpag5Oxg) - [2023/03/23 低代码引擎 LowCodeEngine 茁壮成长的一年](https://mp.weixin.qq.com/s/DDt4LQLFUBQ2-F5ehZGBKg) - [2023/02/21 基于 LowCodeEngine 的低代码组件体系的建设和实践](https://mp.weixin.qq.com/s/rnvbGHImGt6oJuX2wCtaqw) @@ -14,28 +10,4 @@ title: 低代码引擎相关文章资料 - [2022/04/07 磁贴布局在钉钉宜搭报表设计引擎中的实现](https://mp.weixin.qq.com/s/PSTut5ahAB8nlJ9kBpBaxw) - [2022/03/23 阿里低代码引擎 LowCodeEngine 正式开源!](https://mp.weixin.qq.com/s/T66LghtWLz2Oh048XqaniA) - [2022/01/10 阿里低代码引擎和生态建设实战及思考](https://mp.weixin.qq.com/s/MI6MrUKKydtnSdO4xq6jwA) -- [2021/04/14 2B 领域下的低代码探索之路](https://mp.weixin.qq.com/s/HAxrMHLT43dPH488RiEIdw) - -## Portal 设计项目实战 -#### 直播回放 -[https://www.bilibili.com/video/BV1AS4y1K7DP/](https://www.bilibili.com/video/BV1AS4y1K7DP/) - -#### 示例项目 -- 前端: [https://github.com/mark-ck/lowcode-portal](https://github.com/mark-ck/lowcode-portal) -- 后端: [https://github.com/mark-ck/document-solution-site](https://github.com/mark-ck/document-solution-site) -- 组件库:[https://github.com/mark-ck/portal-components](https://github.com/mark-ck/portal-components) - -**注意** -1. 前端项目要把代码里请求接口的域名改成本地或者自己的域名; -2. 后端项目要把 config.default.js 里的 yuque 和 oss 配置补全; - -#### 视频链接 -- [阿里低代码引擎项目实战 (1)-引擎 demo 部署到 faas 服务](https://www.bilibili.com/video/BV1B44y1P7GM/) -- [【有翻车】阿里低代码引擎项目实战 (2)-保存页面到远端存储](https://www.bilibili.com/video/BV1AS4y1K7DP/) -- [阿里巴巴低代码引擎项目实战 (3)-自定义组件接入](https://www.bilibili.com/video/BV1dZ4y1m76S/) -- [阿里低代码引擎项目实战 (4)-自定义插件 - 页面管理](https://www.bilibili.com/video/BV17a411i73f/) -- [阿里低代码引擎项目实战 (4)-用户登录](https://www.bilibili.com/video/BV1Wu411e7EQ/) -- [【有翻车】阿里低代码引擎项目实战 (5)-表单回显](https://www.bilibili.com/video/BV1UY4y1v7D7/) -- [阿里低代码引擎项目实战 (6)-自定义插件 - 页面管理 - 后端](https://www.bilibili.com/video/BV1uZ4y1U7Ly/) -- [阿里低代码引擎项目实战 (6)-自定义插件 - 页面管理 - 前端](https://www.bilibili.com/video/BV1Yq4y1a74P/) -- [阿里低代码引擎项目实战 (7)-自定义插件 - 页面管理 (完结)](https://www.bilibili.com/video/BV13Y4y1e7EV/) +- [2021/04/14 2B 领域下的低代码探索之路](https://mp.weixin.qq.com/s/HAxrMHLT43dPH488RiEIdw) \ No newline at end of file diff --git a/docs/docs/video/index.md b/docs/docs/video/index.md new file mode 100644 index 0000000000..9f348e4e65 --- /dev/null +++ b/docs/docs/video/index.md @@ -0,0 +1,13 @@ +# 官方视频 +- [2023/08/03 初识低代码引擎](https://www.bilibili.com/video/BV1gu411p7TC) + +# 社区视频 +- [阿里低代码引擎项目实战 (1)-引擎 demo 部署到 faas 服务](https://www.bilibili.com/video/BV1B44y1P7GM/) +- [【有翻车】阿里低代码引擎项目实战 (2)-保存页面到远端存储](https://www.bilibili.com/video/BV1AS4y1K7DP/) +- [阿里巴巴低代码引擎项目实战 (3)-自定义组件接入](https://www.bilibili.com/video/BV1dZ4y1m76S/) +- [阿里低代码引擎项目实战 (4)-自定义插件 - 页面管理](https://www.bilibili.com/video/BV17a411i73f/) +- [阿里低代码引擎项目实战 (4)-用户登录](https://www.bilibili.com/video/BV1Wu411e7EQ/) +- [【有翻车】阿里低代码引擎项目实战 (5)-表单回显](https://www.bilibili.com/video/BV1UY4y1v7D7/) +- [阿里低代码引擎项目实战 (6)-自定义插件 - 页面管理 - 后端](https://www.bilibili.com/video/BV1uZ4y1U7Ly/) +- [阿里低代码引擎项目实战 (6)-自定义插件 - 页面管理 - 前端](https://www.bilibili.com/video/BV1Yq4y1a74P/) +- [阿里低代码引擎项目实战 (7)-自定义插件 - 页面管理 (完结)](https://www.bilibili.com/video/BV13Y4y1e7EV/) From 70df59a2ce82f1d9fe59c8177ae1b9782465d83e Mon Sep 17 00:00:00 2001 From: liujuping Date: Tue, 5 Sep 2023 15:41:14 +0800 Subject: [PATCH 010/219] style(outline-pane): fix outline-pane styles --- packages/editor-skeleton/src/layouts/right-area.tsx | 13 +++++++++++-- packages/editor-skeleton/src/layouts/workbench.less | 1 + packages/plugin-outline-pane/src/index.tsx | 1 + 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/editor-skeleton/src/layouts/right-area.tsx b/packages/editor-skeleton/src/layouts/right-area.tsx index 4393eef55f..f00ae1461a 100644 --- a/packages/editor-skeleton/src/layouts/right-area.tsx +++ b/packages/editor-skeleton/src/layouts/right-area.tsx @@ -22,14 +22,23 @@ export default class RightArea extends Component<{ area: Area }> { } } - @observer class Contents extends Component<{ area: Area }> { render() { const { area } = this.props; + return ( - {area.container.items.map((item) => item.content)} + { + area.container.items + .slice() + .sort((a, b) => { + const index1 = a.config?.index || 0; + const index2 = b.config?.index || 0; + return index1 === index2 ? 0 : (index1 > index2 ? 1 : -1); + }) + .map((item) => item.content) + } ); } diff --git a/packages/editor-skeleton/src/layouts/workbench.less b/packages/editor-skeleton/src/layouts/workbench.less index 0a034822f4..38cbcfae09 100644 --- a/packages/editor-skeleton/src/layouts/workbench.less +++ b/packages/editor-skeleton/src/layouts/workbench.less @@ -431,6 +431,7 @@ body { background-color: var(--color-right-area-background, var(--color-pane-background, #fff)); left: 0; top: 0; + z-index: 1; } &.lc-area-visible { display: block; diff --git a/packages/plugin-outline-pane/src/index.tsx b/packages/plugin-outline-pane/src/index.tsx index addebbb402..822c503f27 100644 --- a/packages/plugin-outline-pane/src/index.tsx +++ b/packages/plugin-outline-pane/src/index.tsx @@ -92,6 +92,7 @@ export const OutlinePlugin = (ctx: IPublicModelPluginContext, options: any) => { paneName: BackupPaneName, treeMaster, }, + index: 1, }); // 处理 master pane 和 backup pane 切换 From 34acd70659880409416add185926e874d179876d Mon Sep 17 00:00:00 2001 From: JackLian Date: Tue, 5 Sep 2023 15:50:33 +0800 Subject: [PATCH 011/219] chore(docs): publish docs 1.1.8 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 012ef49d04..45c645bc09 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.1.7", + "version": "1.1.8", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 7ef62308d7a53c62feef8da92c1c0374f89b9412 Mon Sep 17 00:00:00 2001 From: liujuping Date: Wed, 6 Sep 2023 17:17:35 +0800 Subject: [PATCH 012/219] feat(common): update skeletonCabinSymbol exports --- packages/shell/src/api/common.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/shell/src/api/common.tsx b/packages/shell/src/api/common.tsx index 3c2d2e5cce..605d2fb077 100644 --- a/packages/shell/src/api/common.tsx +++ b/packages/shell/src/api/common.tsx @@ -176,7 +176,7 @@ class SkeletonCabin implements IPublicApiCommonSkeletonCabin { constructor(skeleton: InnerSkeleton) { this[skeletonSymbol] = skeleton; this[skeletonCabinSymbol] = { - Workbench: this.Workbench, + Workbench: InnerWorkbench, createSettingFieldView: this.createSettingFieldView, PopupContext: InnerPopupContext, PopupPipe: InnerPopupPipe, From 4507e83d7da87a9a4e759caa237e4b59e9fdef6d Mon Sep 17 00:00:00 2001 From: liujuping Date: Thu, 7 Sep 2023 10:06:50 +0800 Subject: [PATCH 013/219] feat(common): update designerCabinSymbol exports --- packages/shell/src/api/common.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/shell/src/api/common.tsx b/packages/shell/src/api/common.tsx index 605d2fb077..a2e4d8c4fa 100644 --- a/packages/shell/src/api/common.tsx +++ b/packages/shell/src/api/common.tsx @@ -40,6 +40,7 @@ import { Designer as InnerDesigner, Node as InnerNode, LowCodePluginManager as InnerLowCodePluginManager, + DesignerView as InnerDesignerView, } from '@alilc/lowcode-designer'; import { Skeleton as InnerSkeleton, @@ -105,6 +106,7 @@ class DesignerCabin implements IPublicApiCommonDesignerCabin { Designer: InnerDesigner, Node: InnerNode, LowCodePluginManager: InnerLowCodePluginManager, + DesignerView: InnerDesignerView, }; } From 4e0b2fae5d2a59f068b1d5315f3fab6134e4d203 Mon Sep 17 00:00:00 2001 From: liujuping Date: Thu, 7 Sep 2023 10:09:40 +0800 Subject: [PATCH 014/219] feat(hotkey): when text is selected, allow the default copy and paste behavior --- packages/engine/src/inner-plugins/builtin-hotkey.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/engine/src/inner-plugins/builtin-hotkey.ts b/packages/engine/src/inner-plugins/builtin-hotkey.ts index 692773a756..1a1f3a9c44 100644 --- a/packages/engine/src/inner-plugins/builtin-hotkey.ts +++ b/packages/engine/src/inner-plugins/builtin-hotkey.ts @@ -277,6 +277,10 @@ export const builtinHotkey = (ctx: IPublicModelPluginContext) => { if (isFormEvent(e) || !doc) { return; } + const anchorValue = document.getSelection()?.anchorNode?.nodeValue; + if (anchorValue && typeof anchorValue === 'string') { + return; + } e.preventDefault(); let selected = doc.selection.getTopNodes(true); From 24cac48a3252c3cfe7e0c382e3a859c6b6f4194f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= Date: Fri, 8 Sep 2023 10:56:44 +0800 Subject: [PATCH 015/219] docs: update loop.md --- docs/docs/demoUsage/appendix/loop.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/docs/demoUsage/appendix/loop.md b/docs/docs/demoUsage/appendix/loop.md index 8b364ecf4f..46f39398af 100644 --- a/docs/docs/demoUsage/appendix/loop.md +++ b/docs/docs/demoUsage/appendix/loop.md @@ -15,3 +15,14 @@ sidebar_position: 0 ![image.png](https://img.alicdn.com/imgextra/i4/O1CN01XQfnYL1P4wxn01oXv_!!6000000001788-2-tps-3840-1896.png) this.index 是当前循环的索引值。 + +3.在事件绑定函数中使用 + +在事件绑定函数中使用扩展参数设置 +![image](https://github.com/alibaba/lowcode-engine/assets/11935995/7274506e-decd-497a-b07f-c95941a706b4) + +绑定之后在函数中使用 +![image](https://github.com/alibaba/lowcode-engine/assets/11935995/9d52ee5c-9959-4991-91be-9391e639bb7e) + +按钮点击效果 +![image](https://github.com/alibaba/lowcode-engine/assets/11935995/6ca590c9-1f5f-4d48-94a5-439130a22e92) From a560830db652713e29e209fb03a0ea6a6d7e9d40 Mon Sep 17 00:00:00 2001 From: JackLian Date: Fri, 8 Sep 2023 14:16:07 +0800 Subject: [PATCH 016/219] chore(docs): publish docs 1.1.9 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 45c645bc09..773f549cba 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.1.8", + "version": "1.1.9", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 6b14986e8f6cab6af5bc580c9f1a2a4fa925ef5f Mon Sep 17 00:00:00 2001 From: liujuping Date: Mon, 11 Sep 2023 11:23:36 +0800 Subject: [PATCH 017/219] feat(config): add defaultSettingPanelProps config --- docs/docs/api/configOptions.md | 11 ++++++++++- .../src/inner-plugins/default-panel-registry.tsx | 4 +++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/docs/docs/api/configOptions.md b/docs/docs/api/configOptions.md index 4127576569..467655f68c 100644 --- a/docs/docs/api/configOptions.md +++ b/docs/docs/api/configOptions.md @@ -254,6 +254,16 @@ JSExpression 是否只支持使用 this 来访问上下文变量,假如需要 自定义 loading 组件 +### 插件 + +#### defaultSettingPanelProps + +内置设置面板插件的 panelProps + +#### defaultOutlinePaneProps + +内置大纲树面板插件的 panelProps + ### 其他 #### enableStrictPluginMode @@ -282,4 +292,3 @@ customPluginTransducer: async (originPlugin: IPublicTypePlugin, ctx: IPublicMode 大纲树插件面板默认 props - diff --git a/packages/engine/src/inner-plugins/default-panel-registry.tsx b/packages/engine/src/inner-plugins/default-panel-registry.tsx index d7549d764b..b5f538d44c 100644 --- a/packages/engine/src/inner-plugins/default-panel-registry.tsx +++ b/packages/engine/src/inner-plugins/default-panel-registry.tsx @@ -28,6 +28,9 @@ export const defaultPanelRegistry = (editor: any) => { props: { ignoreRoot: true, }, + panelProps: { + ...(config.get('defaultSettingPanelProps') || {}), + }, }); } }, @@ -39,5 +42,4 @@ export const defaultPanelRegistry = (editor: any) => { return fun; }; - export default defaultPanelRegistry; From 1072ff36fb6be0743ae199e9a48eeaa38bd8e0d1 Mon Sep 17 00:00:00 2001 From: liujuping Date: Wed, 13 Sep 2023 11:02:15 +0800 Subject: [PATCH 018/219] feat(workspace): add workspace.skeleton api --- docs/docs/api/workspace.md | 10 ++++++++++ packages/editor-skeleton/src/skeleton.ts | 2 +- packages/shell/src/api/workspace.ts | 5 +++++ packages/workspace/src/workspace.ts | 3 +++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/docs/docs/api/workspace.md b/docs/docs/api/workspace.md index 3c13b00aa0..9911dc93ad 100644 --- a/docs/docs/api/workspace.md +++ b/docs/docs/api/workspace.md @@ -37,6 +37,16 @@ get plugins(): IPublicApiPlugins 关联模型 [IPublicApiPlugins](./plugins) +### skeleton + +应用级别的面板管理 + +```typescript +get skeleton(): IPublicApiSkeleton +``` + +关联模型 [IPublicApiSkeleton](./skeleton) + ### windows 当前设计器的编辑窗口 diff --git a/packages/editor-skeleton/src/skeleton.ts b/packages/editor-skeleton/src/skeleton.ts index 8836434049..89bffc4cfe 100644 --- a/packages/editor-skeleton/src/skeleton.ts +++ b/packages/editor-skeleton/src/skeleton.ts @@ -108,7 +108,7 @@ export interface ISkeleton extends Omit): IWidget | Widget | Panel | Stage | Dock | PanelDock | undefined; } -export class Skeleton { +export class Skeleton implements ISkeleton { private panels = new Map(); private containers = new Map>(); diff --git a/packages/shell/src/api/workspace.ts b/packages/shell/src/api/workspace.ts index 8737e37bd7..fd3e82fa90 100644 --- a/packages/shell/src/api/workspace.ts +++ b/packages/shell/src/api/workspace.ts @@ -3,6 +3,7 @@ import { IWorkspace } from '@alilc/lowcode-workspace'; import { resourceSymbol, workspaceSymbol } from '../symbols'; import { Resource as ShellResource, Window as ShellWindow } from '../model'; import { Plugins } from './plugins'; +import { Skeleton } from './skeleton'; export class Workspace implements IPublicApiWorkspace { readonly [workspaceSymbol]: IWorkspace; @@ -92,6 +93,10 @@ export class Workspace implements IPublicApiWorkspace { return new Plugins(this[workspaceSymbol].plugins, true); } + get skeleton() { + return new Skeleton(this[workspaceSymbol].skeleton, 'workspace', true); + } + get windows() { return this[workspaceSymbol].windows.map((d) => new ShellWindow(d)); } diff --git a/packages/workspace/src/workspace.ts b/packages/workspace/src/workspace.ts index 22eb9ede2b..59b9e866b2 100644 --- a/packages/workspace/src/workspace.ts +++ b/packages/workspace/src/workspace.ts @@ -6,6 +6,7 @@ import { EditorWindow, WINDOW_STATE } from './window'; import type { IEditorWindow } from './window'; import { IResource, Resource } from './resource'; import { IResourceType, ResourceType } from './resource-type'; +import { ISkeleton } from '@alilc/lowcode-editor-skeleton'; enum EVENT { CHANGE_WINDOW = 'change_window', @@ -33,6 +34,8 @@ export interface IWorkspace extends Omit; getResourceList(): IResource[]; From cf2f5c29bce5917e56e774843266f1b5801fd1c3 Mon Sep 17 00:00:00 2001 From: Rainke Date: Wed, 13 Sep 2023 21:32:38 -0500 Subject: [PATCH 019/219] fix: do not parse props when condition is false or loop data is empty (#2477) * fix: do not parse children props when condition is falsy * fix: skip parsing children when loop data is empty --- packages/renderer-core/src/renderer/base.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index 89dc143d5f..216735edcf 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -545,6 +545,7 @@ export default function baseRendererFactory(): IBaseRenderComponent { if (schema.loop != null) { const loop = this.__parseData(schema.loop, scope); + if (Array.isArray(loop) && loop.length === 0) return null; const useLoop = isUseLoop(loop, this.__designModeIsDesign); if (useLoop) { return this.__createLoopVirtualDom( @@ -649,7 +650,7 @@ export default function baseRendererFactory(): IBaseRenderComponent { props.key = props.__id; } - let child = this.__getSchemaChildrenVirtualDom(schema, scope, Comp); + let child = this.__getSchemaChildrenVirtualDom(schema, scope, Comp, condition); const renderComp = (innerProps: any) => engine.createElement(Comp, innerProps, child); // 设计模式下的特殊处理 if (engine && [DESIGN_MODE.EXTEND, DESIGN_MODE.BORDER].includes(engine.props.designMode)) { @@ -709,8 +710,8 @@ export default function baseRendererFactory(): IBaseRenderComponent { return []; } - __getSchemaChildrenVirtualDom = (schema: IPublicTypeNodeSchema | undefined, scope: any, Comp: any) => { - let children = getSchemaChildren(schema); + __getSchemaChildrenVirtualDom = (schema: IPublicTypeNodeSchema | undefined, scope: any, Comp: any, condition = true) => { + let children = condition ? getSchemaChildren(schema) : null; // @todo 补完这里的 Element 定义 @承虎 let result: any = []; From cfc22f7ecc666ae8258013634c3aa17958299b90 Mon Sep 17 00:00:00 2001 From: liujuping Date: Mon, 18 Sep 2023 15:48:32 +0800 Subject: [PATCH 020/219] feat: add simulatorRender shell --- docs/docs/api/model/simulatorRender.md | 38 +++++++++++++++++++ docs/docs/api/simulatorHost.md | 4 +- packages/engine/src/modules/symbols.ts | 2 + packages/shell/src/api/simulator-host.ts | 13 +++++-- packages/shell/src/model/simulator-render.ts | 23 +++++++++++ packages/shell/src/symbols.ts | 1 + .../types/src/shell/api/simulator-host.ts | 6 +-- packages/types/src/shell/model/index.ts | 1 + .../types/src/shell/model/simulator-render.ts | 14 +++++++ 9 files changed, 93 insertions(+), 9 deletions(-) create mode 100644 docs/docs/api/model/simulatorRender.md create mode 100644 packages/shell/src/model/simulator-render.ts create mode 100644 packages/types/src/shell/model/simulator-render.ts diff --git a/docs/docs/api/model/simulatorRender.md b/docs/docs/api/model/simulatorRender.md new file mode 100644 index 0000000000..f5bacec493 --- /dev/null +++ b/docs/docs/api/model/simulatorRender.md @@ -0,0 +1,38 @@ +--- +title: SimulatorRender +sidebar_position: 6 +--- +> **@types** [IPublicModelSimulatorRender](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/simulator-render.ts)
+> **@since** v1.0.0 + +## 基本介绍 + +画布节点选中模型 + +## 属性 +### components + +画布组件列表 + +```typescript +/** + * 画布组件列表 + */ +components: { + [key: string]: any; +} +``` + +## 方法 + +### rerender + +触发画布重新渲染 + +```typescript +/** + * 触发画布重新渲染 + */ +rerender: () => void; +``` + diff --git a/docs/docs/api/simulatorHost.md b/docs/docs/api/simulatorHost.md index b30a614992..ee8f038fc3 100644 --- a/docs/docs/api/simulatorHost.md +++ b/docs/docs/api/simulatorHost.md @@ -50,11 +50,11 @@ get(key: string): any; ``` ### rerender -刷新渲染画布 +触发组件构建,并刷新渲染画布 ```typescript /** - * 刷新渲染画布 + * 触发组件构建,并刷新渲染画布 * make simulator render again */ rerender(): void; diff --git a/packages/engine/src/modules/symbols.ts b/packages/engine/src/modules/symbols.ts index 435e8cbc2c..55c70e5dcb 100644 --- a/packages/engine/src/modules/symbols.ts +++ b/packages/engine/src/modules/symbols.ts @@ -14,6 +14,7 @@ import { skeletonItemSymbol, editorCabinSymbol, skeletonCabinSymbol, + simulatorRenderSymbol, } from '@alilc/lowcode-shell'; export default { @@ -32,4 +33,5 @@ export default { propSymbol, simulatorHostSymbol, skeletonItemSymbol, + simulatorRenderSymbol, }; diff --git a/packages/shell/src/api/simulator-host.ts b/packages/shell/src/api/simulator-host.ts index 3ed7448905..663ba0c668 100644 --- a/packages/shell/src/api/simulator-host.ts +++ b/packages/shell/src/api/simulator-host.ts @@ -2,7 +2,8 @@ import { BuiltinSimulatorHost, } from '@alilc/lowcode-designer'; import { simulatorHostSymbol, nodeSymbol } from '../symbols'; -import { IPublicApiSimulatorHost, IPublicModelNode } from '@alilc/lowcode-types'; +import { IPublicApiSimulatorHost, IPublicModelNode, IPublicModelSimulatorRender } from '@alilc/lowcode-types'; +import { SimulatorRender } from '../model/simulator-render'; export class SimulatorHost implements IPublicApiSimulatorHost { private readonly [simulatorHostSymbol]: BuiltinSimulatorHost; @@ -30,8 +31,12 @@ export class SimulatorHost implements IPublicApiSimulatorHost { return this[simulatorHostSymbol].contentDocument; } - get renderer(): any { - return this[simulatorHostSymbol].renderer; + get renderer(): IPublicModelSimulatorRender | undefined { + if (this[simulatorHostSymbol].renderer) { + return SimulatorRender.create(this[simulatorHostSymbol].renderer); + } + + return undefined; } /** @@ -61,7 +66,7 @@ export class SimulatorHost implements IPublicApiSimulatorHost { } /** - * 刷新渲染画布 + * 触发组件构建,并刷新渲染画布 */ rerender(): void { this[simulatorHostSymbol].rerender(); diff --git a/packages/shell/src/model/simulator-render.ts b/packages/shell/src/model/simulator-render.ts new file mode 100644 index 0000000000..f6ae47996c --- /dev/null +++ b/packages/shell/src/model/simulator-render.ts @@ -0,0 +1,23 @@ +import { IPublicModelSimulatorRender } from '@alilc/lowcode-types'; +import { simulatorRenderSymbol } from '../symbols'; +import { BuiltinSimulatorRenderer } from '@alilc/lowcode-designer'; + +export class SimulatorRender implements IPublicModelSimulatorRender { + private readonly [simulatorRenderSymbol]: BuiltinSimulatorRenderer; + + constructor(simulatorRender: BuiltinSimulatorRenderer) { + this[simulatorRenderSymbol] = simulatorRender; + } + + static create(simulatorRender: BuiltinSimulatorRenderer): IPublicModelSimulatorRender { + return new SimulatorRender(simulatorRender); + } + + get components() { + return this[simulatorRenderSymbol].components; + } + + rerender() { + return this[simulatorRenderSymbol].rerender(); + } +} \ No newline at end of file diff --git a/packages/shell/src/symbols.ts b/packages/shell/src/symbols.ts index cc1be48560..8e2962a24f 100644 --- a/packages/shell/src/symbols.ts +++ b/packages/shell/src/symbols.ts @@ -21,6 +21,7 @@ export const dragonSymbol = Symbol('dragon'); export const componentMetaSymbol = Symbol('componentMeta'); export const dropLocationSymbol = Symbol('dropLocation'); export const simulatorHostSymbol = Symbol('simulatorHost'); +export const simulatorRenderSymbol = Symbol('simulatorRender'); export const dragObjectSymbol = Symbol('dragObject'); export const locateEventSymbol = Symbol('locateEvent'); export const designerCabinSymbol = Symbol('designerCabin'); diff --git a/packages/types/src/shell/api/simulator-host.ts b/packages/types/src/shell/api/simulator-host.ts index 1c0f5dec35..9137067951 100644 --- a/packages/types/src/shell/api/simulator-host.ts +++ b/packages/types/src/shell/api/simulator-host.ts @@ -1,7 +1,7 @@ -import { IPublicModelNode } from '../model'; - +import { IPublicModelNode, IPublicModelSimulatorRender } from '../model'; export interface IPublicApiSimulatorHost { + /** * 获取 contentWindow * @experimental unstable api, pay extra caution when trying to use it @@ -17,7 +17,7 @@ export interface IPublicApiSimulatorHost { /** * @experimental unstable api, pay extra caution when trying to use it */ - get renderer(): any; + get renderer(): IPublicModelSimulatorRender | undefined; /** * 设置若干用于画布渲染的变量,比如画布大小、locale 等。 diff --git a/packages/types/src/shell/model/index.ts b/packages/types/src/shell/model/index.ts index 1924f11215..ffe6347ac2 100644 --- a/packages/types/src/shell/model/index.ts +++ b/packages/types/src/shell/model/index.ts @@ -32,3 +32,4 @@ export * from './clipboard'; export * from './setting-field'; export * from './editor-view'; export * from './skeleton-item'; +export * from './simulator-render'; diff --git a/packages/types/src/shell/model/simulator-render.ts b/packages/types/src/shell/model/simulator-render.ts new file mode 100644 index 0000000000..8cf3a03c55 --- /dev/null +++ b/packages/types/src/shell/model/simulator-render.ts @@ -0,0 +1,14 @@ +export interface IPublicModelSimulatorRender { + + /** + * 画布组件列表 + */ + components: { + [key: string]: any; + }; + + /** + * 触发画布重新渲染 + */ + rerender: () => void; +} From 3e75af171d75b44c213242f6f9d0bda85c4e4cd0 Mon Sep 17 00:00:00 2001 From: JackLian Date: Tue, 19 Sep 2023 09:33:40 +0800 Subject: [PATCH 021/219] chore(docs): publish docs 1.1.10 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 773f549cba..3950b35c9c 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.1.9", + "version": "1.1.10", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 3658bac27feb8b9f7b0c71a579ad9c4b6fb52214 Mon Sep 17 00:00:00 2001 From: zsynuting Date: Mon, 18 Sep 2023 16:27:21 +0800 Subject: [PATCH 022/219] remove unnecessary dep --- packages/designer/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/designer/package.json b/packages/designer/package.json index 274d266fc0..1081aef8ff 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -15,7 +15,6 @@ }, "license": "MIT", "dependencies": { - "@alilc/build-plugin-lce": "^0.0.4-beta.2", "@alilc/lowcode-editor-core": "1.1.10", "@alilc/lowcode-types": "1.1.10", "@alilc/lowcode-utils": "1.1.10", From 7a40aff277bba2969242a2d5780dd6e032714cd7 Mon Sep 17 00:00:00 2001 From: iChengbo Date: Mon, 25 Sep 2023 15:02:37 +0800 Subject: [PATCH 023/219] fix: make the color of the logger more highlighted --- packages/utils/src/logger.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/utils/src/logger.ts b/packages/utils/src/logger.ts index 032b54bdc4..58c7d23b19 100644 --- a/packages/utils/src/logger.ts +++ b/packages/utils/src/logger.ts @@ -52,11 +52,11 @@ const bizNameColors = [ '#2e8b57', ]; const bodyColors: Record = { - debug: '#666666', - log: '#bbbbbb', - info: '#ffffff', - warn: '#bbbbbb', - error: '#bbbbbb', + debug: '#fadb14', + log: '#8c8c8c', + info: '#52c41a', + warn: '#fa8c16', + error: '#ff4d4f', }; const levelMarks: Record = { debug: 'debug', From 4728484e7e449b8af4d66b414bdb474608bc95e0 Mon Sep 17 00:00:00 2001 From: liujuping Date: Mon, 25 Sep 2023 18:09:57 +0800 Subject: [PATCH 024/219] feat: suport more locale config --- packages/react-simulator-renderer/src/locale/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react-simulator-renderer/src/locale/index.ts b/packages/react-simulator-renderer/src/locale/index.ts index e4b39a347c..5f4ef01505 100644 --- a/packages/react-simulator-renderer/src/locale/index.ts +++ b/packages/react-simulator-renderer/src/locale/index.ts @@ -9,10 +9,10 @@ const instance: Record> = { export function createIntl(locale: string = 'zh-CN') { const intl = (id: string) => { - return instance[locale][id]; + return instance[locale]?.[id] || id; }; - const intlNode = (id: string) => createElement('span', instance[locale][id]); + const intlNode = (id: string) => createElement('span', instance[locale]?.[id] || id); return { intl, From 5c139181b6b0e1a542e0babc9cb63e7938306079 Mon Sep 17 00:00:00 2001 From: liujuping Date: Tue, 26 Sep 2023 17:21:01 +0800 Subject: [PATCH 025/219] fix: fix workspace openEditorWindow API bugs --- packages/workspace/src/workspace.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/workspace/src/workspace.ts b/packages/workspace/src/workspace.ts index 59b9e866b2..9f1abaa0fb 100644 --- a/packages/workspace/src/workspace.ts +++ b/packages/workspace/src/workspace.ts @@ -130,7 +130,9 @@ export class Workspace implements IWorkspace { } const windowInfo = this.windowQueue.shift(); - if (windowInfo) { + if (windowInfo instanceof Resource) { + this.openEditorWindowByResource(windowInfo); + } else if (windowInfo) { this.openEditorWindow(windowInfo.name, windowInfo.title, windowInfo.options, windowInfo.viewName); } } @@ -251,7 +253,7 @@ export class Workspace implements IWorkspace { } async openEditorWindowByResource(resource: IResource, sleep: boolean = false): Promise { - if (this.window && !this.window?.initReady && !sleep) { + if (this.window && !this.window.sleep && !this.window?.initReady && !sleep) { this.windowQueue.push(resource); return; } @@ -292,7 +294,7 @@ export class Workspace implements IWorkspace { } async openEditorWindow(name: string, title: string, options: Object, viewName?: string, sleep?: boolean) { - if (this.window && !this.window?.initReady && !sleep) { + if (this.window && !this.window.sleep && !this.window?.initReady && !sleep) { this.windowQueue.push({ name, title, options, viewName, }); @@ -304,7 +306,7 @@ export class Workspace implements IWorkspace { return; } this.window?.updateState(WINDOW_STATE.inactive); - const filterWindows = this.windows.filter(d => (d.resource?.name === name && d.resource.title == title)); + const filterWindows = this.windows.filter(d => (d.resource?.name === name && d.resource.title == title) || (d.resource.id == title)); if (filterWindows && filterWindows.length) { this.window = filterWindows[0]; if (!sleep && this.window.sleep) { @@ -320,6 +322,7 @@ export class Workspace implements IWorkspace { resourceName: name, title, options, + id: title?.toString(), }, resourceType, this); const window = new EditorWindow(resource, this, { title, From e3e5123b3173cd0999ace99278e904391baa3aa4 Mon Sep 17 00:00:00 2001 From: Rainke Date: Mon, 25 Sep 2023 21:27:23 -0500 Subject: [PATCH 026/219] fix: remove `class` prop --- .../src/components/settings/settings-primary-pane.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx b/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx index 800719588f..a68647ed0d 100644 --- a/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx +++ b/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx @@ -64,7 +64,6 @@ export class SettingsPrimaryPane extends Component {createIcon(settings.componentMeta?.icon, { className: 'lc-settings-navigator-icon', - class: 'lc-settings-navigator-icon', })} <span> x {settings.nodes.length}</span> From f50410ae7a51b6c4d7ad18f4146c462beb2cfb51 Mon Sep 17 00:00:00 2001 From: iChengbo <chengbo_x@163.com> Date: Thu, 5 Oct 2023 12:31:45 +0800 Subject: [PATCH 027/219] fix: some spell error --- .../designer/src/builtin-simulator/host.ts | 10 +++++----- packages/designer/src/designer/designer.ts | 4 ++-- packages/designer/src/designer/scroller.ts | 18 +++++++++--------- packages/utils/src/app-helper.ts | 12 ++++++------ packages/utils/src/asset.ts | 8 ++++---- packages/utils/src/logger.ts | 4 ++-- 6 files changed, 28 insertions(+), 28 deletions(-) diff --git a/packages/designer/src/builtin-simulator/host.ts b/packages/designer/src/builtin-simulator/host.ts index 5e6fc06a62..eb855e4498 100644 --- a/packages/designer/src/builtin-simulator/host.ts +++ b/packages/designer/src/builtin-simulator/host.ts @@ -1069,15 +1069,15 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp return null; } - const nodeIntance = this.getClosestNodeInstance(target); - if (!nodeIntance) { + const nodeInstance = this.getClosestNodeInstance(target); + if (!nodeInstance) { return null; } - const { docId } = nodeIntance; + const { docId } = nodeInstance; const doc = this.project.getDocument(docId)!; - const node = doc.getNode(nodeIntance.nodeId); + const node = doc.getNode(nodeInstance.nodeId); return { - ...nodeIntance, + ...nodeInstance, node, }; } diff --git a/packages/designer/src/designer/designer.ts b/packages/designer/src/designer/designer.ts index 784ebf57bc..d7e17e84ca 100644 --- a/packages/designer/src/designer/designer.ts +++ b/packages/designer/src/designer/designer.ts @@ -18,7 +18,7 @@ import { IPublicEnumTransformStage, IPublicModelLocateEvent, } from '@alilc/lowcode-types'; -import { megreAssets, IPublicTypeAssetsJson, isNodeSchema, isDragNodeObject, isDragNodeDataObject, isLocationChildrenDetail, Logger } from '@alilc/lowcode-utils'; +import { mergeAssets, IPublicTypeAssetsJson, isNodeSchema, isDragNodeObject, isDragNodeDataObject, isLocationChildrenDetail, Logger } from '@alilc/lowcode-utils'; import { IProject, Project } from '../project'; import { Node, DocumentModel, insertChildren, INode } from '../document'; import { ComponentMeta, IComponentMeta } from '../component-meta'; @@ -458,7 +458,7 @@ export class Designer implements IDesigner { if (components) { // 合并 assets let assets = this.editor.get('assets') || {}; - let newAssets = megreAssets(assets, incrementalAssets); + let newAssets = mergeAssets(assets, incrementalAssets); // 对于 assets 存在需要二次网络下载的过程,必须 await 等待结束之后,再进行事件触发 await this.editor.set('assets', newAssets); } diff --git a/packages/designer/src/designer/scroller.ts b/packages/designer/src/designer/scroller.ts index 67efe7f444..7391c39fab 100644 --- a/packages/designer/src/designer/scroller.ts +++ b/packages/designer/src/designer/scroller.ts @@ -46,7 +46,7 @@ function easing(n: number) { return Math.sin((n * Math.PI) / 2); } -const SCROLL_ACCURCY = 30; +const SCROLL_ACCURACY = 30; export interface IScroller extends IPublicModelScroller { @@ -142,15 +142,15 @@ export class Scroller implements IScroller { let sy = scrollTarget.top; let ax = 0; let ay = 0; - if (y < bounds.top + SCROLL_ACCURCY) { - ay = -Math.min(Math.max(bounds.top + SCROLL_ACCURCY - y, 10), 50) / scale; - } else if (y > bounds.bottom - SCROLL_ACCURCY) { - ay = Math.min(Math.max(y + SCROLL_ACCURCY - bounds.bottom, 10), 50) / scale; + if (y < bounds.top + SCROLL_ACCURACY) { + ay = -Math.min(Math.max(bounds.top + SCROLL_ACCURACY - y, 10), 50) / scale; + } else if (y > bounds.bottom - SCROLL_ACCURACY) { + ay = Math.min(Math.max(y + SCROLL_ACCURACY - bounds.bottom, 10), 50) / scale; } - if (x < bounds.left + SCROLL_ACCURCY) { - ax = -Math.min(Math.max(bounds.top + SCROLL_ACCURCY - y, 10), 50) / scale; - } else if (x > bounds.right - SCROLL_ACCURCY) { - ax = Math.min(Math.max(x + SCROLL_ACCURCY - bounds.right, 10), 50) / scale; + if (x < bounds.left + SCROLL_ACCURACY) { + ax = -Math.min(Math.max(bounds.top + SCROLL_ACCURACY - y, 10), 50) / scale; + } else if (x > bounds.right - SCROLL_ACCURACY) { + ax = Math.min(Math.max(x + SCROLL_ACCURACY - bounds.right, 10), 50) / scale; } if (!ax && !ay) { diff --git a/packages/utils/src/app-helper.ts b/packages/utils/src/app-helper.ts index d5eb2072b3..86b535c592 100644 --- a/packages/utils/src/app-helper.ts +++ b/packages/utils/src/app-helper.ts @@ -34,18 +34,18 @@ export class AppHelper extends EventEmitter { } } - batchOn(events: Array<string | symbol>, lisenter: (...args: any[]) => void) { + batchOn(events: Array<string | symbol>, listener: (...args: any[]) => void) { if (!Array.isArray(events)) return; - events.forEach((event) => this.on(event, lisenter)); + events.forEach((event) => this.on(event, listener)); } - batchOnce(events: Array<string | symbol>, lisenter: (...args: any[]) => void) { + batchOnce(events: Array<string | symbol>, listener: (...args: any[]) => void) { if (!Array.isArray(events)) return; - events.forEach((event) => this.once(event, lisenter)); + events.forEach((event) => this.once(event, listener)); } - batchOff(events: Array<string | symbol>, lisenter: (...args: any[]) => void) { + batchOff(events: Array<string | symbol>, listener: (...args: any[]) => void) { if (!Array.isArray(events)) return; - events.forEach((event) => this.off(event, lisenter)); + events.forEach((event) => this.off(event, listener)); } } diff --git a/packages/utils/src/asset.ts b/packages/utils/src/asset.ts index 4e5a360b86..ad05221248 100644 --- a/packages/utils/src/asset.ts +++ b/packages/utils/src/asset.ts @@ -50,7 +50,7 @@ export function assetItem(type: AssetType, content?: string | null, level?: Asse }; } -export function megreAssets(assets: IPublicTypeAssetsJson, incrementalAssets: IPublicTypeAssetsJson): IPublicTypeAssetsJson { +export function mergeAssets(assets: IPublicTypeAssetsJson, incrementalAssets: IPublicTypeAssetsJson): IPublicTypeAssetsJson { if (incrementalAssets.packages) { assets.packages = [...(assets.packages || []), ...incrementalAssets.packages]; } @@ -59,13 +59,13 @@ export function megreAssets(assets: IPublicTypeAssetsJson, incrementalAssets: IP assets.components = [...(assets.components || []), ...incrementalAssets.components]; } - megreAssetsComponentList(assets, incrementalAssets, 'componentList'); - megreAssetsComponentList(assets, incrementalAssets, 'bizComponentList'); + mergeAssetsComponentList(assets, incrementalAssets, 'componentList'); + mergeAssetsComponentList(assets, incrementalAssets, 'bizComponentList'); return assets; } -function megreAssetsComponentList(assets: IPublicTypeAssetsJson, incrementalAssets: IPublicTypeAssetsJson, listName: keyof IPublicTypeAssetsJson): void { +function mergeAssetsComponentList(assets: IPublicTypeAssetsJson, incrementalAssets: IPublicTypeAssetsJson, listName: keyof IPublicTypeAssetsJson): void { if (incrementalAssets[listName]) { if (assets[listName]) { // 根据title进行合并 diff --git a/packages/utils/src/logger.ts b/packages/utils/src/logger.ts index 58c7d23b19..4c8f375ecd 100644 --- a/packages/utils/src/logger.ts +++ b/packages/utils/src/logger.ts @@ -65,7 +65,7 @@ const levelMarks: Record<string, string> = { warn: 'warn', error: 'error', }; -const outputFuntion: Record<string, any> = { +const outputFunction: Record<string, any> = { debug: console.log, log: console.log, info: console.log, @@ -88,7 +88,7 @@ const shouldOutput = ( const output = (logLevel: string, bizName: string) => { return (...args: any[]) => { - return outputFuntion[logLevel].apply(console, getLogArgs(args, bizName, logLevel)); + return outputFunction[logLevel].apply(console, getLogArgs(args, bizName, logLevel)); }; }; From fc31145f89d6ca1b1377db044cbed0ebe436d268 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Sat, 7 Oct 2023 17:00:45 +0800 Subject: [PATCH 028/219] style: add style varibles and update some styles --- .../builtin-simulator/bem-tools/borders.less | 57 ++------- .../bem-tools/insertion.less | 2 +- .../designer/src/builtin-simulator/host.less | 6 +- .../node-selector/index.less | 2 +- .../src/designer/drag-ghost/ghost.less | 4 +- packages/designer/src/less-variables.less | 8 +- .../editor-core/src/widgets/tip/style.less | 12 +- .../editor-core/src/widgets/title/title.less | 2 +- .../src/components/field/fields.tsx | 34 ----- .../src/components/field/index.less | 117 +----------------- .../src/components/settings/style.less | 8 -- .../editor-skeleton/src/layouts/theme.less | 8 ++ .../src/layouts/workbench.less | 48 ++----- .../editor-skeleton/src/less-variables.less | 8 +- .../plugin-outline-pane/src/views/style.less | 48 +++---- packages/utils/src/create-icon.tsx | 6 +- packages/workspace/src/less-variables.less | 8 +- 17 files changed, 81 insertions(+), 297 deletions(-) diff --git a/packages/designer/src/builtin-simulator/bem-tools/borders.less b/packages/designer/src/builtin-simulator/bem-tools/borders.less index 2cdc9fb403..43fba6a2b8 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/borders.less +++ b/packages/designer/src/builtin-simulator/bem-tools/borders.less @@ -17,7 +17,7 @@ } & > &-status { margin-left: 5px; - color: #3c3c3c; + color: var(--color-text, #3c3c3c); transform: translateY(-100%); font-weight: lighter; } @@ -46,7 +46,7 @@ opacity: 1; max-height: 100%; overflow: hidden; - color: white; + color: var(--color-icon-reverse, white); &:hover { background: var(--color-brand-light, #006cff); } @@ -56,8 +56,8 @@ display: inline-block; width: 8px; height: 8px; - border: 1px solid #197aff; - background: #fff; + border: 1px solid var(--color-brand, #197aff); + background: var(--color-block-background-normal, #fff); pointer-events: auto; z-index: 2; } @@ -73,11 +73,9 @@ &:after { content: ""; display: block; - border: 1px solid #197aff; - background: #fff; - // background: #738397; + border: 1px solid var(--color-brand, #197aff); + background: var(--color-block-background-normal, #fff); border-radius: 2px; - // animation: flashing 1.5s infinite linear; } &.e, @@ -85,7 +83,6 @@ cursor: ew-resize; &:after { width: 4px; - // height: calc(100% - 20px); min-height: 50%; } } @@ -94,62 +91,24 @@ &.s { cursor: ns-resize; &:after { - // width: calc(100% - 20px); min-width: 50%; height: 4px; } } } - // &&-hovering { &&-detecting { z-index: 1; border-style: dashed; - background: rgba(0,121,242,.04); - - &.x-loop { - border-color: rgba(138, 93, 226, 0.8); - background: rgba(138, 93, 226, 0.04); - - >.@{scope}-title { - color: rgba(138, 93, 226, 1.0); - } - } - - &.x-condition { - border-color: rgba(255, 99, 8, 0.8); - background: rgba(255, 99, 8, 0.04); - >.@{scope}-title { - color: rgb(255, 99, 8); - } - } + background: var(--color-block-background-light, rgba(0,121,242,.04)); } &&-selecting { z-index: 2; border-width: 2px; - &.x-loop { - border-color: rgba(147, 112, 219, 1.0); - background: rgba(147, 112, 219, 0.04); - - >@{scope}-title { - color: rgba(147, 112, 219, 1.0); - } - &.highlight { - background: transparent; - } - } - - &.x-condition { - border-color: rgb(255, 99, 8); - >@{scope}-title { - color: rgb(255, 99, 8); - } - } - &.dragging { - background: rgba(182, 178, 178, 0.8); + background: var(--color-layer-mask-background, rgba(182, 178, 178, 0.8)); border: none; } } diff --git a/packages/designer/src/builtin-simulator/bem-tools/insertion.less b/packages/designer/src/builtin-simulator/bem-tools/insertion.less index 770d3893ca..c51e73106f 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/insertion.less +++ b/packages/designer/src/builtin-simulator/bem-tools/insertion.less @@ -23,6 +23,6 @@ } &.invalid { - background-color: red; + background-color: var(--color-function-error, red); } } diff --git a/packages/designer/src/builtin-simulator/host.less b/packages/designer/src/builtin-simulator/host.less index 5e230c4007..7130c42972 100644 --- a/packages/designer/src/builtin-simulator/host.less +++ b/packages/designer/src/builtin-simulator/host.less @@ -31,7 +31,7 @@ max-height: calc(100% - 32px); max-width: calc(100% - 32px); transform: translateX(-50%); - box-shadow: 0 2px 10px 0 rgba(31,56,88,.15); + box-shadow: 0 2px 10px 0 var(--color-block-background-shallow, rgba(31,56,88,.15)); } &-device-iphonex { // 增加默认的小程序的壳 @@ -44,7 +44,7 @@ background: url(https://img.alicdn.com/tfs/TB1b4DHilFR4u4jSZFPXXanzFXa-750-1574.png) no-repeat top; background-size: 375px 812px; border-radius: 44px; - box-shadow: rgba(0, 0, 0, 0.1) 0 36px 42px; + box-shadow: var(--color-block-background-shallow, rgba(0, 0, 0, 0.1)) 0 36px 42px; .@{scope}-canvas-viewport { width: auto; top: 50px; @@ -78,7 +78,7 @@ bottom: 16px; left: 16px; width: auto; - box-shadow: 0 1px 4px 0 rgba(31, 50, 88, 0.125); + box-shadow: 0 1px 4px 0 var(--color-block-background-shallow, rgba(31, 50, 88, 0.125)); } &-content { diff --git a/packages/designer/src/builtin-simulator/node-selector/index.less b/packages/designer/src/builtin-simulator/node-selector/index.less index c0335734e0..01552a2510 100644 --- a/packages/designer/src/builtin-simulator/node-selector/index.less +++ b/packages/designer/src/builtin-simulator/node-selector/index.less @@ -48,7 +48,7 @@ margin-top: 2px; &-content { padding-left: 6px; - background: #78869a; + background: var(--color-layer-tooltip-background, #78869a); display: inline-flex; border-radius: 3px; align-items: center; diff --git a/packages/designer/src/designer/drag-ghost/ghost.less b/packages/designer/src/designer/drag-ghost/ghost.less index 7ab61b41d6..1d9c03552f 100644 --- a/packages/designer/src/designer/drag-ghost/ghost.less +++ b/packages/designer/src/designer/drag-ghost/ghost.less @@ -7,8 +7,8 @@ flex-direction: column; align-items: center; pointer-events: none; - background-color: rgba(0, 0, 0, 0.4); - box-shadow: 0 0 6px grey; + background-color: var(--color-block-background-deep-dark, rgba(0, 0, 0, 0.4)); + box-shadow: 0 0 6px var(--color-block-background-shallow, grey); transform: translate(-10%, -50%); .lc-ghost { .lc-ghost-title { diff --git a/packages/designer/src/less-variables.less b/packages/designer/src/less-variables.less index c44fc196e2..017e432ce6 100644 --- a/packages/designer/src/less-variables.less +++ b/packages/designer/src/less-variables.less @@ -99,19 +99,19 @@ @brand-link-hover: #2e76a6; // F1-1-7 A10 -@brand-danger-alpha-7: rgba(240, 70, 49, 0.9); +@brand-danger-alpha-7: rgba(240, 70, 49, 0.1); // F1-1-8 A6 @brand-danger-alpha-8: rgba(240, 70, 49, 0.8); // F2-1-2 A80 @brand-warning-alpha-2: rgba(250, 189, 14, 0.8); // F2-1-7 A10 -@brand-warning-alpha-7: rgba(250, 189, 14, 0.9); +@brand-warning-alpha-7: rgba(250, 189, 14, 0.1); // F3-1-2 A80 @brand-success-alpha-2: rgba(102, 188, 92, 0.8); // F3-1-7 A10 -@brand-success-alpha-7: rgba(102, 188, 92, 0.9); +@brand-success-alpha-7: rgba(102, 188, 92, 0.1); // F4-1-7 A10 -@brand-link-alpha-7: rgba(102, 188, 92, 0.9); +@brand-link-alpha-7: rgba(102, 188, 92, 0.1); // 文本色 @text-primary-color: @dark-alpha-3; diff --git a/packages/editor-core/src/widgets/tip/style.less b/packages/editor-core/src/widgets/tip/style.less index 21b60b9b5d..aa5327f3d4 100644 --- a/packages/editor-core/src/widgets/tip/style.less +++ b/packages/editor-core/src/widgets/tip/style.less @@ -156,7 +156,7 @@ opacity: 0; border-radius: 3px; padding: 6px 8px; - text-shadow: 0 -1px rgba(0, 0, 0, 0.3); + text-shadow: 0 -1px var(--color-field-label, rgba(0, 0, 0, 0.3)); font-size: var(--font-size-text); line-height: 14px; max-width: 200px; @@ -178,19 +178,19 @@ height: 8px; &:after { border: 6px solid transparent; - border-top-color: rgba(0, 0, 0, 0.7); + border-top-color: var(--color-layer-tooltip-background, rgba(0, 0, 0, 0.7)); } } &.lc-theme-black { - background: rgba(0, 0, 0, 0.7); + background: var(--color-icon-pane, rgba(0, 0, 0, 0.7)); .lc-arrow:after { - border-top-color: rgba(0, 0, 0, 0.7); + border-top-color: var(--color-layer-tooltip-background, rgba(0, 0, 0, 0.7)); } } &.lc-theme-green { - background: #57a672; + background: var(--color-function-success-dark, #57a672); .lc-arrow:after { - border-top-color: #57a672; + border-top-color: var(--color-function-success-dark, #57a672); } } &.lc-visible { diff --git a/packages/editor-core/src/widgets/title/title.less b/packages/editor-core/src/widgets/title/title.less index e9d0765522..f6747ef474 100644 --- a/packages/editor-core/src/widgets/title/title.less +++ b/packages/editor-core/src/widgets/title/title.less @@ -21,7 +21,7 @@ cursor: help; text-decoration-line: underline; text-decoration-style: dashed; - text-decoration-color: rgba(31, 56, 88, .3); + text-decoration-color: var(--color-text-light, rgba(31, 56, 88, .3)); } line-height: initial !important; word-break: break-all; diff --git a/packages/editor-skeleton/src/components/field/fields.tsx b/packages/editor-skeleton/src/components/field/fields.tsx index b773995e3a..21ae93eb25 100644 --- a/packages/editor-skeleton/src/components/field/fields.tsx +++ b/packages/editor-skeleton/src/components/field/fields.tsx @@ -203,40 +203,6 @@ export class Field extends Component<FieldProps> { */ function createValueState(/* valueState?: number, onClear?: (e: React.MouseEvent) => void */) { return null; - - /* - let tip: any = null; - let className = 'lc-valuestate'; - let icon: any = null; - if (valueState) { - if (valueState < 0) { - // multiple value 橘黄色点: tip:多种值,点击清除 - tip = intlNode('Multiple Value, Click to Clear'); - className += ' valuestate-multiple'; - icon = <IconClear size={6} />; - } else if (valueState === 10) { - // isset orangered tip: 必填项 - tip = intlNode('Required'); - className += ' valuestate-required'; - onClear = undefined; - } else if (valueState > 0) { - // isset 蓝点 tip: 已设置值,点击清除 - tip = intlNode('Setted Value, Click to Clear'); - className += ' valuestate-isset'; - icon = <IconClear size={6} />; - } - } else { - onClear = undefined; - // unset 占位空间 - } - - return ( - <i className={className} onClick={onClear}> - {icon} - {tip && <Tip>{tip}</Tip>} - </i> - ); - */ } export interface PopupFieldProps extends FieldProps { diff --git a/packages/editor-skeleton/src/components/field/index.less b/packages/editor-skeleton/src/components/field/index.less index 249abef570..8c1facfbaf 100644 --- a/packages/editor-skeleton/src/components/field/index.less +++ b/packages/editor-skeleton/src/components/field/index.less @@ -14,54 +14,6 @@ .lc-field-title { display: flex; align-items: center; - .lc-valuestate { - height: 6px; - width: 6px; - min-width: 6px; - border-radius: 100%; - margin-right: 2px; - pointer-events: none; - display: inline-flex; - align-items: center; - justify-content: center; - color: white; - > svg { - display: none; - } - &.valuestate-multiple { - background-color: rgb(232, 145, 83); - pointer-events: auto; - &:hover { - background-color: rgb(223, 139, 30); - cursor: pointer; - transform: scale(2); - transform-origin: center; - > svg { - display: block; - } - } - } - &.valuestate-isset { - background-color: rgba(124, 177, 238, 0.6); - pointer-events: auto; - &:hover { - background-color: rgb(45, 126, 219); - cursor: pointer; - transform: scale(2); - transform-origin: center; - > svg { - display: block; - } - } - } - &.valuestate-required { - background-color: rgb(250, 82, 76); - pointer-events: auto; - &:hover { - background-color: rgb(224, 46, 40); - } - } - } } .lc-field-icon { transform-origin: center; @@ -92,11 +44,7 @@ &.lc-block-field, &.lc-accordion-field, &.lc-entry-field { display: block; - &:first-child { - > .lc-field-head { - // border-top: none; - } - } + > .lc-field-head { height: 32px; display: flex; @@ -110,7 +58,7 @@ user-select: none; > .lc-field-icon { - color: #8f9bb3; + color: var(--color-icon-normal, #8f9bb3); } } @@ -128,10 +76,6 @@ } } } - - // + .lc-inline-field { - // border-top: 1px solid var(--color-line-normal); - // } } &.lc-entry-field { @@ -163,15 +107,11 @@ > .lc-field-head { cursor: pointer; } - + &.lc-field-is-collapsed { margin-bottom: 6px; } - // collapsed - // &:last-child.lc-field-is-collapsed{ - // border-bottom: 1px solid var(--color-line-normal); - // } &.lc-field-is-collapsed { > .lc-field-head .lc-field-icon { transform: rotate(180deg); @@ -180,56 +120,5 @@ display: none; } } - - // 邻近的保持上下距离 - + .lc-field { - // margin-top: @y-gap; - } - } - - // 2rd level reset - .lc-field-body { - // .lc-inline-field { - // &:first-child { - // padding-top: 0; - // } - // + .lc-accordion-field, +.lc-block-field { - // margin-top: @y-gap; - // } - // } - - // .lc-field { - // border-top: none !important; - // } - - // .lc-accordion-field, .lc-block-field { - // > .lc-field-head { - // padding-left: @x-gap; - // background: var(--color-block-background-light); - // border-bottom: none; - // border-top: none; - // > .lc-field-icon { - // // margin-right: @x-gap/2; - // margin-right: 0; - // } - // } - - // > .lc-field-body { - // padding: 8px; - // } - // } - - // 3rd level field title width should short - // .lc-field-body .lc-inline-field { - // > .lc-field-head { - // width: 50px; - // .lc-title-label { - // width: 50px; - // } - // } - // } - // >.lc-block-setter { - // flex: 1; - // } } } diff --git a/packages/editor-skeleton/src/components/settings/style.less b/packages/editor-skeleton/src/components/settings/style.less index 57a7c9357f..4599ed55c2 100644 --- a/packages/editor-skeleton/src/components/settings/style.less +++ b/packages/editor-skeleton/src/components/settings/style.less @@ -33,14 +33,6 @@ position: relative; margin-bottom: 4px; position: absolute; - - .lc-setting-stage-back-icon { - position: absolute; - left: 8px; - top: 8px; - color: #8f9bb3; - cursor: pointer; - } } .lc-settings-notice { diff --git a/packages/editor-skeleton/src/layouts/theme.less b/packages/editor-skeleton/src/layouts/theme.less index 53afb69328..13fc19c847 100644 --- a/packages/editor-skeleton/src/layouts/theme.less +++ b/packages/editor-skeleton/src/layouts/theme.less @@ -16,6 +16,7 @@ --color-icon-hover: @normal-alpha-3; --color-icon-active: @brand-color-1; --color-icon-reverse: @white-alpha-1; + --color-icon-disabled: @normal-alpha-6; --color-icon-pane: @dark-alpha-3; --color-line-normal: @normal-alpha-7; @@ -27,6 +28,7 @@ --color-text-light: lighten(@dark-alpha-3, 10%); --color-text-reverse: @white-alpha-2; --color-text-regular: @normal-alpha-2; + --color-text-disabled: @gray-light; --color-field-label: @dark-alpha-4; --color-field-text: @dark-alpha-3; @@ -48,6 +50,8 @@ --color-function-error: @brand-danger; --color-function-error-dark: darken(@brand-danger, 10%); --color-function-error-light: lighten(@brand-danger, 10%); + --color-function-purple: rgb(144, 94, 190); + --color-function-brown: #7b605b; --color-pane-background: @white-alpha-1; --color-block-background-normal: @white-alpha-1; @@ -55,6 +59,10 @@ --color-block-background-shallow: @normal-alpha-8; --color-block-background-dark: @normal-alpha-7; --color-block-background-disabled: @normal-alpha-6; + --color-block-background-active: @brand-color-1-7; + --color-block-background-warning: @brand-warning-alpha-7; + --color-block-background-error: @brand-danger-alpha-7; + --color-block-background-success: @brand-success-alpha-7; --color-block-background-deep-dark: @normal-5; --color-layer-mask-background: @dark-alpha-7; --color-layer-tooltip-background: rgba(44,47,51,0.8); diff --git a/packages/editor-skeleton/src/layouts/workbench.less b/packages/editor-skeleton/src/layouts/workbench.less index 38cbcfae09..58123ea464 100644 --- a/packages/editor-skeleton/src/layouts/workbench.less +++ b/packages/editor-skeleton/src/layouts/workbench.less @@ -60,7 +60,7 @@ body { .lc-help-tip { margin-left: 4px; - color: rgba(0, 0, 0, 0.4); + color: var(--color-icon-normal, rgba(0, 0, 0, 0.4)); cursor: pointer; } } @@ -68,7 +68,7 @@ body { height: 48px; font-size: 16px; padding: 0 15px; - color: #0f1726; + color: var(--color-title, #0f1726); font-weight: bold; } @@ -79,39 +79,6 @@ body { left: 0; right: 0; overflow: visible; - /* - .my-tabs { - width: 100%; - height: 100%; - position: relative; - .tabs-title { - display: flex; - height: var(--pane-title-height); - > .tab-title { - cursor: pointer; - padding: 0; - flex: 1; - min-width: 0; - justify-content: center; - border-bottom: 2px solid transparent; - &.actived { - cursor: default; - color: var(--color-text-avtived); - border-bottom-color: #3896ee; - } - } - } - .tabs-content { - position: absolute; - top: var(--pane-title-height); - bottom: 0; - left: 0; - right: 0; - height: calc(100% - var(--pane-title-height)); - overflow: hidden; - } - } - */ } .lc-outline-tree-container { border-top: 1px solid var(--color-line-normal, rgba(31, 56, 88, 0.1)); @@ -234,8 +201,7 @@ body { display: flex; justify-content: center; align-items: center; - // background: rgba(31,56,88,0.04); - border-bottom: 1px solid #edeff3; + border-bottom: 1px solid var(--color-line-normal, #edeff3); .lc-tab-title { flex: 1; height: 32px; @@ -246,8 +212,8 @@ body { cursor: pointer; font-size: 12px; &.actived { - color: #0079f2; - border-bottom-color: #0079f2; + color: var(--color-brand, #0079f2); + border-bottom-color: var(--color-brand, #0079f2); } } } @@ -293,7 +259,7 @@ body { // min-width: var(--dock-fixed-pane-width); left: calc(var(--left-area-width) + 1px); background-color: var(--color-left-float-pane-background, var(--color-pane-background)); - box-shadow: 4px 6px 6px 0 rgba(31, 50, 88, 0.08); + box-shadow: 4px 6px 6px 0 var(--color-block-background-shallow, rgba(31, 50, 88, 0.08)); z-index: 820; display: none; // padding-top: 36px; @@ -340,7 +306,7 @@ body { cursor: pointer; } &.actived { - color: #0079f2; + color: var(--color-brand, #0079f2); } &.disabled { opacity: 0.4; diff --git a/packages/editor-skeleton/src/less-variables.less b/packages/editor-skeleton/src/less-variables.less index c44fc196e2..017e432ce6 100644 --- a/packages/editor-skeleton/src/less-variables.less +++ b/packages/editor-skeleton/src/less-variables.less @@ -99,19 +99,19 @@ @brand-link-hover: #2e76a6; // F1-1-7 A10 -@brand-danger-alpha-7: rgba(240, 70, 49, 0.9); +@brand-danger-alpha-7: rgba(240, 70, 49, 0.1); // F1-1-8 A6 @brand-danger-alpha-8: rgba(240, 70, 49, 0.8); // F2-1-2 A80 @brand-warning-alpha-2: rgba(250, 189, 14, 0.8); // F2-1-7 A10 -@brand-warning-alpha-7: rgba(250, 189, 14, 0.9); +@brand-warning-alpha-7: rgba(250, 189, 14, 0.1); // F3-1-2 A80 @brand-success-alpha-2: rgba(102, 188, 92, 0.8); // F3-1-7 A10 -@brand-success-alpha-7: rgba(102, 188, 92, 0.9); +@brand-success-alpha-7: rgba(102, 188, 92, 0.1); // F4-1-7 A10 -@brand-link-alpha-7: rgba(102, 188, 92, 0.9); +@brand-link-alpha-7: rgba(102, 188, 92, 0.1); // 文本色 @text-primary-color: @dark-alpha-3; diff --git a/packages/plugin-outline-pane/src/views/style.less b/packages/plugin-outline-pane/src/views/style.less index 406a5b5da4..37f51a170d 100644 --- a/packages/plugin-outline-pane/src/views/style.less +++ b/packages/plugin-outline-pane/src/views/style.less @@ -54,17 +54,17 @@ .tree-node-modal { margin: 5px; - border: 1px solid rgba(31, 56, 88, 0.2); + border: 1px solid var(--color-field-border, rgba(31, 56, 88, 0.2)); border-radius: 3px; - box-shadow: 0 1px 4px 0 rgba(31, 56, 88, 0.15); + box-shadow: 0 1px 4px 0 var(--color-block-background-shallow, rgba(31, 56, 88, 0.15)); .tree-node-modal-title { position: relative; - background: rgba(31, 56, 88, 0.04); + background: var(--color-block-background-light, rgba(31, 56, 88, 0.04)); padding: 0 10px; height: 32px; line-height: 32px; - border-bottom: 1px solid rgba(31, 56, 88, 0.2); + border-bottom: 1px solid var(--color-field-border, rgba(31, 56, 88, 0.2)); .tree-node-modal-title-visible-icon { position: absolute; @@ -89,7 +89,7 @@ left: 6px; } .tree-node-modal-radio-active { - color: #006cff; + color: var(--color-brand, #006cff); } } @@ -108,7 +108,7 @@ &:hover { .tree-node-branches::before { - border-left-color: #ddd; + border-left-color: var(--color-line-darken, #ddd); } } @@ -120,20 +120,20 @@ transform: translateZ(0); transition: all 0.2s ease-in-out; &.invalid { - border-color: red; - background-color: rgba(240, 154, 154, 0.719); + border-color: var(--color-function-error, red); + background-color: var(--color-block-background-error, rgba(240, 154, 154, 0.719)); } } .condition-group-container { - border-bottom: 1px solid #7b605b; + border-bottom: 1px solid var(--color-function-brown, #7b605b); position: relative; &:before { position: absolute; display: block; width: 0; - border-left: 0.5px solid #7b605b; + border-left: 0.5px solid var(--color-function-brown, #7b605b); height: 100%; top: 0; left: 0; @@ -142,26 +142,26 @@ } > .condition-group-title { text-align: center; - background-color: #7b605b; + background-color: var(--color-function-brown, #7b605b); height: 14px; > .lc-title { font-size: 12px; transform: scale(0.8); transform-origin: top; - color: white; - text-shadow: 0 0 2px black; + color: var(--color-text-reverse, white); + text-shadow: 0 0 2px var(--color-block-background-shallow, black); display: block; } } } .tree-node-slots { - border-bottom: 1px solid rgb(144, 94, 190); + border-bottom: 1px solid var(--color-function-purple, rgb(144, 94, 190)); position: relative; &::before { position: absolute; display: block; width: 0; - border-left: 0.5px solid rgb(144, 94, 190); + border-left: 0.5px solid var(--color-function-purple, rgb(144, 94, 190)); height: 100%; top: 0; left: 0; @@ -170,25 +170,25 @@ } > .tree-node-slots-title { text-align: center; - background-color: rgb(144, 94, 190); + background-color: var(--color-function-purple, rgb(144, 94, 190)); height: 14px; > .lc-title { font-size: 12px; transform: scale(0.8); transform-origin: top; - color: white; + color: var(--color-text-reverse, white); text-shadow: 0 0 2px black; display: block; } } &.insertion-at-slots { padding-bottom: @treeNodeHeight; - border-bottom-color: rgb(182, 55, 55); + border-bottom-color: var(--color-function-error-dark, rgb(182, 55, 55)); > .tree-node-slots-title { - background-color: rgb(182, 55, 55); + background-color: var(--color-function-error-dark, rgb(182, 55, 55)); } &::before { - border-left-color: rgb(182, 55, 55); + border-left-color: var(--color-function-error-dark, rgb(182, 55, 55)); } } } @@ -326,13 +326,13 @@ align-items: center; line-height: 0; &.cond { - color: rgb(179, 52, 6); + color: var(--color-function-error, rgb(179, 52, 6)); } &.loop { - color: rgb(103, 187, 187); + color: var(--color-function-success, rgb(103, 187, 187)); } &.slot { - color: rgb(211, 90, 211); + color: var(--color-function-purple, rgb(211, 90, 211)); } } } @@ -366,7 +366,7 @@ &.hidden { .tree-node-title-label { - color: #9b9b9b; + color: var(--color-text-disabled, #9b9b9b); } & > .tree-node-title > .tree-node-hide-btn { opacity: 0.8; diff --git a/packages/utils/src/create-icon.tsx b/packages/utils/src/create-icon.tsx index 0f25005298..0a5d6c1ff7 100644 --- a/packages/utils/src/create-icon.tsx +++ b/packages/utils/src/create-icon.tsx @@ -18,7 +18,11 @@ export function createIcon( } if (typeof icon === 'string') { if (URL_RE.test(icon)) { - return <img src={icon} {...props} />; + return createElement('img', { + src: icon, + class: props?.className, + ...props, + }); } return <Icon type={icon} {...props} />; } diff --git a/packages/workspace/src/less-variables.less b/packages/workspace/src/less-variables.less index c44fc196e2..017e432ce6 100644 --- a/packages/workspace/src/less-variables.less +++ b/packages/workspace/src/less-variables.less @@ -99,19 +99,19 @@ @brand-link-hover: #2e76a6; // F1-1-7 A10 -@brand-danger-alpha-7: rgba(240, 70, 49, 0.9); +@brand-danger-alpha-7: rgba(240, 70, 49, 0.1); // F1-1-8 A6 @brand-danger-alpha-8: rgba(240, 70, 49, 0.8); // F2-1-2 A80 @brand-warning-alpha-2: rgba(250, 189, 14, 0.8); // F2-1-7 A10 -@brand-warning-alpha-7: rgba(250, 189, 14, 0.9); +@brand-warning-alpha-7: rgba(250, 189, 14, 0.1); // F3-1-2 A80 @brand-success-alpha-2: rgba(102, 188, 92, 0.8); // F3-1-7 A10 -@brand-success-alpha-7: rgba(102, 188, 92, 0.9); +@brand-success-alpha-7: rgba(102, 188, 92, 0.1); // F4-1-7 A10 -@brand-link-alpha-7: rgba(102, 188, 92, 0.9); +@brand-link-alpha-7: rgba(102, 188, 92, 0.1); // 文本色 @text-primary-color: @dark-alpha-3; From 82d82b9d0596f75080d4bde1bfea5ef86a47ad19 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Sun, 8 Oct 2023 18:04:33 +0800 Subject: [PATCH 029/219] feat: update Outline Tree to Component Tree --- packages/plugin-outline-pane/src/locale/en-US.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugin-outline-pane/src/locale/en-US.json b/packages/plugin-outline-pane/src/locale/en-US.json index 9ade9e66f4..b86a7859bb 100644 --- a/packages/plugin-outline-pane/src/locale/en-US.json +++ b/packages/plugin-outline-pane/src/locale/en-US.json @@ -10,7 +10,7 @@ "Loop": "Loop", "Slots": "Slots", "Slot for {prop}": "Slot for {prop}", - "Outline Tree": "Outline Tree", + "Outline Tree": "Component Tree", "Filter Node": "Filter Node", "Check All": "Check All", "Conditional rendering": "Conditional rendering", From 4684d3171797765fe4a480a4ce23503747663da7 Mon Sep 17 00:00:00 2001 From: rainke <woshihepeng520@163.com> Date: Mon, 9 Oct 2023 09:59:39 +0800 Subject: [PATCH 030/219] chore: resolve react-error-overlay to 6.0.9 --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 6a650c49b6..aded2a3015 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,8 @@ "lockfile": "enable" }, "resolutions": { - "typescript": "4.6.2" + "typescript": "4.6.2", + "react-error-overlay": "6.0.9" }, "repository": "git@github.com:alibaba/lowcode-engine.git" } From 30f8066332b277335b67b681da9fe263d9a15e38 Mon Sep 17 00:00:00 2001 From: AndyJin <jjj706@163.com> Date: Thu, 12 Oct 2023 08:45:34 +0800 Subject: [PATCH 031/219] fix: fix rendering failure when children is number 0 --- packages/renderer-core/src/renderer/base.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index 216735edcf..72821cfd38 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -453,7 +453,7 @@ export default function baseRendererFactory(): IBaseRenderComponent { * @param idx 为循环渲染的循环Index */ __createVirtualDom = (originalSchema: IPublicTypeNodeData | IPublicTypeNodeData[] | undefined, originalScope: any, parentInfo: INodeInfo, idx: string | number = ''): any => { - if (!originalSchema) { + if (originalSchema === null || originalSchema === undefined) { return null; } let scope = originalScope; From 3129445d60935db69bf14b81bee5e302f22053db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=AD=A3?= <lizhengnacl@163.com> Date: Tue, 10 Oct 2023 17:11:07 +0800 Subject: [PATCH 032/219] Update specs.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 去掉重复内容 --- 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 0d97f5cc08..2e8e4c195c 100644 --- a/docs/docs/guide/design/specs.md +++ b/docs/docs/guide/design/specs.md @@ -58,7 +58,7 @@ sidebar_position: 1 ## 协议的作用 -基于统一的协议,我们完成业务组件、区块、模板等各类物料的标准统一,基于统一的协议,我们完成业务组件、区块、模板等各类物料的标准统一,各类中后台研发系统生产的物料可借助物料中心进行跨系统流通,通过丰富物料生态的共享提升各平台研发系统的效率。同时完成低代码引擎的标准统一以及低代码搭建中台能力的输出,帮助业务方快速孵化本业务域中后台研发系统。 +基于统一的协议,我们完成业务组件、区块、模板等各类物料的标准统一,各类中后台研发系统生产的物料可借助物料中心进行跨系统流通,通过丰富物料生态的共享提升各平台研发系统的效率。同时完成低代码引擎的标准统一以及低代码搭建中台能力的输出,帮助业务方快速孵化本业务域中后台研发系统。 ### 打破物料孤岛 From ca6fe7c335b5035eba18a8681a4bb7a5ccac83b3 Mon Sep 17 00:00:00 2001 From: rainke <woshihepeng520@163.com> Date: Wed, 11 Oct 2023 14:55:05 +0800 Subject: [PATCH 033/219] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20forwardRef?= =?UTF-8?q?=20=E7=BB=84=E4=BB=B6=E7=9A=84=E9=94=99=E8=AF=AF=E6=97=A0?= =?UTF-8?q?=E6=B3=95=E6=8D=95=E8=8E=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../renderer/__snapshots__/demo.test.tsx.snap | 1 + packages/renderer-core/src/hoc/index.tsx | 70 ++++++++++++++++--- packages/renderer-core/src/renderer/base.tsx | 8 +-- .../renderer-core/src/renderer/renderer.tsx | 48 ------------- packages/renderer-core/src/types/index.ts | 1 - packages/utils/src/is-react.ts | 13 +++- 6 files changed, 75 insertions(+), 66 deletions(-) diff --git a/packages/react-simulator-renderer/test/src/renderer/__snapshots__/demo.test.tsx.snap b/packages/react-simulator-renderer/test/src/renderer/__snapshots__/demo.test.tsx.snap index 0ebb606dac..2f2d19f269 100644 --- a/packages/react-simulator-renderer/test/src/renderer/__snapshots__/demo.test.tsx.snap +++ b/packages/react-simulator-renderer/test/src/renderer/__snapshots__/demo.test.tsx.snap @@ -31,6 +31,7 @@ exports[`Base should be render Text 1`] = ` behavior="NORMAL" componentId="node_ockvuu8u916" fieldId="text_kvuu9gl2" + forwardRef={[Function]} maxLine={0} showTitle={false} > diff --git a/packages/renderer-core/src/hoc/index.tsx b/packages/renderer-core/src/hoc/index.tsx index a9314060f3..aae03045ec 100644 --- a/packages/renderer-core/src/hoc/index.tsx +++ b/packages/renderer-core/src/hoc/index.tsx @@ -1,20 +1,72 @@ import { cloneEnumerableProperty } from '@alilc/lowcode-utils'; import adapter from '../adapter'; +import { IBaseRendererInstance, IRendererProps } from '../types'; -export function compWrapper(Comp: any) { +function patchDidCatch(Comp: any, { baseRenderer }: { baseRenderer: IBaseRendererInstance }) { + if (Comp.patchedCatch) { + return; + } + Comp.patchedCatch = true; + const { PureComponent } = adapter.getRuntime(); + // Rax 的 getDerivedStateFromError 有 BUG,这里先用 componentDidCatch 来替代 + // @see https://github.com/alibaba/rax/issues/2211 + const originalDidCatch = Comp.prototype.componentDidCatch; + Comp.prototype.componentDidCatch = function didCatch(this: any, error: Error, errorInfo: any) { + this.setState({ engineRenderError: true, error }); + if (originalDidCatch && typeof originalDidCatch === 'function') { + originalDidCatch.call(this, error, errorInfo); + } + }; + + const { engine } = baseRenderer.context; + const originRender = Comp.prototype.render; + Comp.prototype.render = function () { + if (this.state && this.state.engineRenderError) { + this.state.engineRenderError = false; + return engine.createElement(engine.getFaultComponent(), { + ...this.props, + error: this.state.error, + componentName: this.props._componentName, + }); + } + return originRender.call(this); + }; + if (!(Comp.prototype instanceof PureComponent)) { + const originShouldComponentUpdate = Comp.prototype.shouldComponentUpdate; + Comp.prototype.shouldComponentUpdate = function (nextProps: IRendererProps, nextState: any) { + if (nextState && nextState.engineRenderError) { + return true; + } + return originShouldComponentUpdate + ? originShouldComponentUpdate.call(this, nextProps, nextState) + : true; + }; + } +} + +export function compWrapper(Comp: any, options: { baseRenderer: IBaseRendererInstance }) { const { createElement, Component, forwardRef } = adapter.getRuntime(); + if ( + Comp?.prototype?.isReactComponent || // react + Comp?.prototype?.setState || // rax + Comp?.prototype instanceof Component + ) { + patchDidCatch(Comp, options); + return Comp; + } class Wrapper extends Component { - // constructor(props: any, context: any) { - // super(props, context); - // } - render() { - return createElement(Comp, this.props); + return createElement(Comp, { ...this.props, ref: this.props.forwardRef }); } } (Wrapper as any).displayName = Comp.displayName; - return cloneEnumerableProperty(forwardRef((props: any, ref: any) => { - return createElement(Wrapper, { ...props, forwardRef: ref }); - }), Comp); + patchDidCatch(Wrapper, options); + + return cloneEnumerableProperty( + forwardRef((props: any, ref: any) => { + return createElement(Wrapper, { ...props, forwardRef: ref }); + }), + Comp, + ); } diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index 72821cfd38..2ed476b1c4 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -23,7 +23,6 @@ import { transformStringToFunction, checkPropTypes, getI18n, - canAcceptsRef, getFileCssName, capitalizeFirstLetter, DataHelper, @@ -616,11 +615,8 @@ export default function baseRendererFactory(): IBaseRenderComponent { }); }); - // 对于不可以接收到 ref 的组件需要做特殊处理 - if (!canAcceptsRef(Comp)) { - Comp = compWrapper(Comp); - components[schema.componentName] = Comp; - } + Comp = compWrapper(Comp, { baseRenderer: this }); + components[schema.componentName] = Comp; otherProps.ref = (ref: any) => { this.$(props.fieldId || props.ref, ref); // 收集ref diff --git a/packages/renderer-core/src/renderer/renderer.tsx b/packages/renderer-core/src/renderer/renderer.tsx index 09559b6f89..300b1cd164 100644 --- a/packages/renderer-core/src/renderer/renderer.tsx +++ b/packages/renderer-core/src/renderer/renderer.tsx @@ -105,55 +105,7 @@ export default function rendererFactory(): IRenderComponent { return SetComponent; } - patchDidCatch(SetComponent: any) { - if (!this.isValidComponent(SetComponent)) { - return; - } - if (SetComponent.patchedCatch) { - return; - } - if (!SetComponent.prototype) { - return; - } - SetComponent.patchedCatch = true; - - // Rax 的 getDerivedStateFromError 有 BUG,这里先用 componentDidCatch 来替代 - // @see https://github.com/alibaba/rax/issues/2211 - const originalDidCatch = SetComponent.prototype.componentDidCatch; - SetComponent.prototype.componentDidCatch = function didCatch(this: any, error: Error, errorInfo: any) { - this.setState({ engineRenderError: true, error }); - if (originalDidCatch && typeof originalDidCatch === 'function') { - originalDidCatch.call(this, error, errorInfo); - } - }; - - const engine = this; - const originRender = SetComponent.prototype.render; - SetComponent.prototype.render = function () { - if (this.state && this.state.engineRenderError) { - this.state.engineRenderError = false; - return engine.createElement(engine.getFaultComponent(), { - ...this.props, - error: this.state.error, - componentName: this.props._componentName - }); - } - return originRender.call(this); - }; - if(!(SetComponent.prototype instanceof PureComponent)) { - const originShouldComponentUpdate = SetComponent.prototype.shouldComponentUpdate; - SetComponent.prototype.shouldComponentUpdate = function (nextProps: IRendererProps, nextState: any) { - if (nextState && nextState.engineRenderError) { - return true; - } - return originShouldComponentUpdate ? originShouldComponentUpdate.call(this, nextProps, nextState) : true; - }; - } - } - createElement(SetComponent: any, props: any, children?: any) { - // TODO: enable in runtime mode? - this.patchDidCatch(SetComponent); return (this.props.customCreateElement || createElement)(SetComponent, props, children); } diff --git a/packages/renderer-core/src/types/index.ts b/packages/renderer-core/src/types/index.ts index a49fe89920..afbec272ab 100644 --- a/packages/renderer-core/src/types/index.ts +++ b/packages/renderer-core/src/types/index.ts @@ -335,7 +335,6 @@ export interface IRenderComponent { componentDidCatch(e: any): Promise<void> | void; shouldComponentUpdate(nextProps: IRendererProps): boolean; isValidComponent(SetComponent: any): any; - patchDidCatch(SetComponent: any): void; createElement(SetComponent: any, props: any, children?: any): any; getNotFoundComponent(): any; getFaultComponent(): any; diff --git a/packages/utils/src/is-react.ts b/packages/utils/src/is-react.ts index 07568db981..b19f043f14 100644 --- a/packages/utils/src/is-react.ts +++ b/packages/utils/src/is-react.ts @@ -10,10 +10,10 @@ export function isReactClass(obj: any): obj is ComponentClass<any> { } export function acceptsRef(obj: any): boolean { - return obj?.prototype?.isReactComponent || (obj.$$typeof && obj.$$typeof === REACT_FORWARD_REF_TYPE); + return obj?.prototype?.isReactComponent || isForwardOrMemoForward(obj); } -function isForwardRefType(obj: any): boolean { +export function isForwardRefType(obj: any): boolean { return obj?.$$typeof && obj?.$$typeof === REACT_FORWARD_REF_TYPE; } @@ -21,6 +21,15 @@ function isMemoType(obj: any): boolean { return obj?.$$typeof && obj.$$typeof === REACT_MEMO_TYPE; } +export function isForwardOrMemoForward(obj: any): boolean { + return obj?.$$typeof && ( + // React.forwardRef(..) + isForwardRefType(obj) || + // React.memo(React.forwardRef(..)) + (isMemoType(obj) && isForwardRefType(obj.type)) + ); +} + export function isReactComponent(obj: any): obj is ComponentType<any> { if (!obj) { return false; From a96961f588971805ef0cdb5e07af2ab14475ac74 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Mon, 16 Oct 2023 14:35:10 +0800 Subject: [PATCH 034/219] docs: publish docs 1.1.11 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 3950b35c9c..6c43fe1d0f 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.1.10", + "version": "1.1.11", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 7677ad0166f479fa78c78dfb6d69fb8a3617cbd9 Mon Sep 17 00:00:00 2001 From: rainke <woshihepeng520@163.com> Date: Tue, 17 Oct 2023 17:33:07 +0800 Subject: [PATCH 035/219] =?UTF-8?q?fix:=20hoc=20=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E7=BC=93=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/renderer-core/src/hoc/index.tsx | 22 +++++++++++++++++--- packages/renderer-core/src/renderer/base.tsx | 2 +- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/packages/renderer-core/src/hoc/index.tsx b/packages/renderer-core/src/hoc/index.tsx index aae03045ec..3e7f5ec6a1 100644 --- a/packages/renderer-core/src/hoc/index.tsx +++ b/packages/renderer-core/src/hoc/index.tsx @@ -2,7 +2,12 @@ import { cloneEnumerableProperty } from '@alilc/lowcode-utils'; import adapter from '../adapter'; import { IBaseRendererInstance, IRendererProps } from '../types'; -function patchDidCatch(Comp: any, { baseRenderer }: { baseRenderer: IBaseRendererInstance }) { +interface Options { + baseRenderer: IBaseRendererInstance; + schema: any; +} + +function patchDidCatch(Comp: any, { baseRenderer }: Options) { if (Comp.patchedCatch) { return; } @@ -44,7 +49,9 @@ function patchDidCatch(Comp: any, { baseRenderer }: { baseRenderer: IBaseRendere } } -export function compWrapper(Comp: any, options: { baseRenderer: IBaseRendererInstance }) { +const cache = new Map(); + +export function compWrapper(Comp: any, options: Options) { const { createElement, Component, forwardRef } = adapter.getRuntime(); if ( Comp?.prototype?.isReactComponent || // react @@ -54,6 +61,11 @@ export function compWrapper(Comp: any, options: { baseRenderer: IBaseRendererIns patchDidCatch(Comp, options); return Comp; } + + if (cache.has(options.schema.id)) { + return cache.get(options.schema.id); + } + class Wrapper extends Component { render() { return createElement(Comp, { ...this.props, ref: this.props.forwardRef }); @@ -63,10 +75,14 @@ export function compWrapper(Comp: any, options: { baseRenderer: IBaseRendererIns patchDidCatch(Wrapper, options); - return cloneEnumerableProperty( + const WrapperComponent = cloneEnumerableProperty( forwardRef((props: any, ref: any) => { return createElement(Wrapper, { ...props, forwardRef: ref }); }), Comp, ); + + cache.set(options.schema.id, WrapperComponent); + + return WrapperComponent; } diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index 2ed476b1c4..7b9562fcc6 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -615,7 +615,7 @@ export default function baseRendererFactory(): IBaseRenderComponent { }); }); - Comp = compWrapper(Comp, { baseRenderer: this }); + Comp = compWrapper(Comp, { baseRenderer: this, schema }); components[schema.componentName] = Comp; otherProps.ref = (ref: any) => { From d56ed6bff172f3833f5321073310fac5d54bd247 Mon Sep 17 00:00:00 2001 From: rainke <woshihepeng520@163.com> Date: Mon, 16 Oct 2023 16:59:03 +0800 Subject: [PATCH 036/219] feat: make asset support es module --- packages/designer/src/builtin-simulator/create-simulator.ts | 5 +++-- packages/types/src/assets.ts | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/designer/src/builtin-simulator/create-simulator.ts b/packages/designer/src/builtin-simulator/create-simulator.ts index 15ab3507b5..57369efd89 100644 --- a/packages/designer/src/builtin-simulator/create-simulator.ts +++ b/packages/designer/src/builtin-simulator/create-simulator.ts @@ -56,12 +56,13 @@ export function createSimulator( } const id = asset.id ? ` data-id="${asset.id}"` : ''; const lv = asset.level || level || AssetLevel.Environment; + const scriptType = asset.scriptType ? ` type="${asset.scriptType}"` : ''; if (asset.type === AssetType.JSUrl) { scripts[lv].push( - `<script src="${asset.content}"${id}></script>`, + `<script src="${asset.content}"${id}${scriptType}></script>`, ); } else if (asset.type === AssetType.JSText) { - scripts[lv].push(`<script${id}>${asset.content}</script>`); + scripts[lv].push(`<script${id}${scriptType}>${asset.content}</script>`); } else if (asset.type === AssetType.CSSUrl) { styles[lv].push( `<link rel="stylesheet" href="${asset.content}"${id} />`, diff --git a/packages/types/src/assets.ts b/packages/types/src/assets.ts index 852ed00380..f0e6d35396 100644 --- a/packages/types/src/assets.ts +++ b/packages/types/src/assets.ts @@ -38,6 +38,7 @@ export interface AssetItem { device?: string; level?: AssetLevel; id?: string; + scriptType?: string; } export type AssetList = Array<Asset | undefined | null>; From 96fe876e331d91f36989e9660b86f72b223dc5a4 Mon Sep 17 00:00:00 2001 From: rainke <woshihepeng520@163.com> Date: Fri, 13 Oct 2023 16:57:26 +0800 Subject: [PATCH 037/219] =?UTF-8?q?fix:=20=E5=A4=8D=E5=88=B6=E6=97=B6?= =?UTF-8?q?=E9=98=B2=E6=AD=A2=20ref=20=E9=87=8D=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/designer/src/component-actions.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/designer/src/component-actions.ts b/packages/designer/src/component-actions.ts index 76ead7d9a6..57ad30bf25 100644 --- a/packages/designer/src/component-actions.ts +++ b/packages/designer/src/component-actions.ts @@ -10,6 +10,14 @@ import { } from './icons'; import { componentDefaults, legacyIssues } from './transducers'; +function deduplicateRef(node: IPublicModelNode | null | undefined) { + const currentRef = node?.getPropValue('ref'); + if (currentRef) { + node?.setPropValue('ref', `${node.componentName.toLowerCase()}-${Math.random().toString(36).slice(2, 9)}`); + } + node?.children?.forEach(deduplicateRef); +} + export class ComponentActions { private metadataTransducers: IPublicTypeMetadataTransducer[] = []; @@ -53,6 +61,7 @@ export class ComponentActions { const { document: doc, parent, index } = node; if (parent) { const newNode = doc?.insertNode(parent, node, (index ?? 0) + 1, true); + deduplicateRef(newNode); newNode?.select(); const { isRGL, rglNode } = node?.getRGL(); if (isRGL) { From 79b9a6efa57d1a30559ea8476bbb380b5957d968 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 19 Oct 2023 11:05:41 +0800 Subject: [PATCH 038/219] feat: add theme color document & optimize some theme colors --- docs/docs/guide/expand/editor/cli.md | 2 +- docs/docs/guide/expand/editor/graph.md | 2 +- docs/docs/guide/expand/editor/setter.md | 2 +- docs/docs/guide/expand/editor/theme.md | 91 +++++++++++++++++++ .../bem-tools/insertion.less | 2 +- .../editor-core/src/widgets/tip/style.less | 4 +- .../src/layouts/sub-top-area.tsx | 8 +- .../editor-skeleton/src/layouts/theme.less | 46 +++++++--- .../editor-skeleton/src/layouts/top-area.tsx | 6 +- .../src/layouts/workbench.less | 27 +++--- .../plugin-outline-pane/src/views/style.less | 26 +++--- packages/workspace/src/layouts/workbench.tsx | 2 +- 12 files changed, 165 insertions(+), 53 deletions(-) create mode 100644 docs/docs/guide/expand/editor/theme.md diff --git a/docs/docs/guide/expand/editor/cli.md b/docs/docs/guide/expand/editor/cli.md index 60f44ce875..0577a181db 100644 --- a/docs/docs/guide/expand/editor/cli.md +++ b/docs/docs/guide/expand/editor/cli.md @@ -1,6 +1,6 @@ --- title: 低代码生态脚手架 & 调试机制 -sidebar_position: 8 +sidebar_position: 10 --- ## 脚手架简述 diff --git a/docs/docs/guide/expand/editor/graph.md b/docs/docs/guide/expand/editor/graph.md index 2d5127054e..a45f34baf0 100644 --- a/docs/docs/guide/expand/editor/graph.md +++ b/docs/docs/guide/expand/editor/graph.md @@ -1,6 +1,6 @@ --- title: 图编排扩展 -sidebar_position: 9 +sidebar_position: 8 --- ## 项目运行 ### 前置准备 diff --git a/docs/docs/guide/expand/editor/setter.md b/docs/docs/guide/expand/editor/setter.md index 01fd949bbd..4f0e0219fc 100644 --- a/docs/docs/guide/expand/editor/setter.md +++ b/docs/docs/guide/expand/editor/setter.md @@ -1,6 +1,6 @@ --- title: 设置器扩展 -sidebar_position: 5 +sidebar_position: 7 --- ## 设置器简述 diff --git a/docs/docs/guide/expand/editor/theme.md b/docs/docs/guide/expand/editor/theme.md new file mode 100644 index 0000000000..b62fb4f28c --- /dev/null +++ b/docs/docs/guide/expand/editor/theme.md @@ -0,0 +1,91 @@ +--- +title: 主题色扩展 +sidebar_position: 9 +--- + +## 主题色扩展简述 + +通过主题色扩展,可以定制多种设计器主题。 + +## 主题色扩展说明 + +### 主题色变量 + +- `--color-brand`: 品牌色 +- `--color-brand-light`: 品牌色(light) +- `--color-brand-dark`: 品牌色(dark) +- `--color-icon-normal`: 正常 icon 颜色 +- `--color-icon-hover`: icon hover 态颜色 +- `--color-icon-active`: icon active 态颜色 +- `--color-icon-reverse`: icon 反色 +- `--color-icon-disabled`: icon 禁用态颜色 +- `--color-icon-pane`: icon 面板颜色 +- `--color-line-normal`: 线条颜色 +- `--color-line-darken`: 线条颜色(darken) +- `--color-title`: 标题颜色 +- `--color-text`: 文字颜色 +- `--color-text-dark`: 文字颜色(dark) +- `--color-text-light`: 文字颜色(light) +- `--color-text-reverse`: 反色情况下,文字颜色 +- `--color-text-regular`: 文字颜色(regular) +- `--color-text-disabled`: 禁用态文字颜色 +- `--color-field-label`: field 标签颜色 +- `--color-field-text`: field 文本颜色 +- `--color-field-placeholder`: field placeholder 颜色 +- `--color-field-border`: field 边框颜色 +- `--color-field-border-hover`: hover 态下,field 边框颜色 +- `--color-field-border-active`: active 态下,field 边框颜色 +- `--color-field-background`: field 背景色 +- `--color-success`: success 颜色 +- `--colo-success-dark`: success 颜色(dark) +- `--color-success-light`: success 颜色(light) +- `--color-warning`: warning 颜色 +- `--color-warning-dark`: warning 颜色(dark) +- `--color-warning-light`: warning 颜色(light) +- `--color-information`: information 颜色 +- `--color-information-dark`: information 颜色(dark) +- `--color-information-light`: information 颜色(light) +- `--color-error`: error 颜色 +- `--color-error-dark`: error 颜色(dark) +- `--color-error-light`: error 颜色(light) +- `--color-purple`: purple 颜色 +- `--color-brown`: brown 颜色 +- `--color-pane-background`: 面板背景色 +- `--color-block-background-normal`: 区块背景色 +- `--color-block-background-light`: 区块背景色(light), 作用于画布组件 hover 时遮罩背景色。 +- `--color-block-background-shallow`: 区块背景色 shallow +- `--color-block-background-dark`: 区块背景色(dark) +- `--color-block-background-disabled`: 区块背景色(disabled) +- `--color-block-background-active`: 区块背景色(active) +- `--color-block-background-warning`: 区块背景色(warning) +- `--color-block-background-error`: 区块背景色(error) +- `--color-block-background-success`: 区块背景色(success) +- `--color-block-background-deep-dark`: 区块背景色(deep-dark),作用于多个组件同时拖拽的背景色。 +- `--color-layer-mask-background`: 拖拽元素时,元素原来位置的遮罩背景色 +- `--color-layer-tooltip-background`: tooltip 背景色 +- `--color-background`: 设计器主要背景色 +- `--color-top-area-background`: topArea 背景色,优先级大于 `--color-pane-background` +- `--color-left-area-background`: leftArea 背景色,优先级大于 `--color-pane-background` +- `--color-workspace-left-area-background`: 应用级 leftArea 背景色,优先级大于 `--color-pane-background` +- `--color-workspace-top-area-background`: 应用级 topArea 背景色,优先级大于 `--color-pane-background` +- `--color-workspace-sub-top-area-background`: 应用级二级 topArea 背景色,优先级大于 `--color-pane-background` +- `--workspace-sub-top-area-height`: 应用级二级 topArea 高度 +- `--workspace-sub-top-area-margin`: 应用级二级 topArea margin +- `--workspace-sub-top-area-padding`: 应用级二级 topArea padding + +### 生态使用主题色变量 + +插件、物料、设置器等生态为了支持主题色需要对样式进行改造,需要对生态中的样式升级为 css 变量。例如: + +```css +/* before */ +background: #006cff; + +/* after */ +background: var(--color-brand, #006cff); + +``` + +### fusion 物料进行主题色扩展 + +如果使用了 fusion 组件,可以通过 https://fusion.alibaba-inc.com/ 平台进行主题色定制。 \ No newline at end of file diff --git a/packages/designer/src/builtin-simulator/bem-tools/insertion.less b/packages/designer/src/builtin-simulator/bem-tools/insertion.less index c51e73106f..fff045631a 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/insertion.less +++ b/packages/designer/src/builtin-simulator/bem-tools/insertion.less @@ -23,6 +23,6 @@ } &.invalid { - background-color: var(--color-function-error, red); + background-color: var(--color-error, var(--color-function-error, red)); } } diff --git a/packages/editor-core/src/widgets/tip/style.less b/packages/editor-core/src/widgets/tip/style.less index aa5327f3d4..602886d060 100644 --- a/packages/editor-core/src/widgets/tip/style.less +++ b/packages/editor-core/src/widgets/tip/style.less @@ -188,9 +188,9 @@ } } &.lc-theme-green { - background: var(--color-function-success-dark, #57a672); + background: var(--color-success-dark, var(--color-function-success-dark, #57a672)); .lc-arrow:after { - border-top-color: var(--color-function-success-dark, #57a672); + border-top-color: var(--color-success-dark, var(--color-function-success-dark, #57a672)); } } &.lc-visible { diff --git a/packages/editor-skeleton/src/layouts/sub-top-area.tsx b/packages/editor-skeleton/src/layouts/sub-top-area.tsx index e6bf61871a..cef6aa5b02 100644 --- a/packages/editor-skeleton/src/layouts/sub-top-area.tsx +++ b/packages/editor-skeleton/src/layouts/sub-top-area.tsx @@ -13,7 +13,7 @@ export default class SubTopArea extends Component<{ area: Area; itemClassName?: } return ( - <div className={classNames('lc-sub-top-area engine-actionpane', { + <div className={classNames('lc-workspace-sub-top-area lc-sub-top-area engine-actionpane', { 'lc-area-visible': area.visible, })} > @@ -50,13 +50,13 @@ class Contents extends Component<{ area: Area; itemClassName?: string }> { }); let children = []; if (left && left.length) { - children.push(<div className="lc-sub-top-area-left">{left}</div>); + children.push(<div className="lc-workspace-sub-top-area-left lc-sub-top-area-left">{left}</div>); } if (center && center.length) { - children.push(<div className="lc-sub-top-area-center">{center}</div>); + children.push(<div className="lc-workspace-sub-top-area-center lc-sub-top-area-center">{center}</div>); } if (right && right.length) { - children.push(<div className="lc-sub-top-area-right">{right}</div>); + children.push(<div className="lc-workspace-sub-top-area-right lc-sub-top-area-right">{right}</div>); } return ( <Fragment> diff --git a/packages/editor-skeleton/src/layouts/theme.less b/packages/editor-skeleton/src/layouts/theme.less index 13fc19c847..716ab3a99e 100644 --- a/packages/editor-skeleton/src/layouts/theme.less +++ b/packages/editor-skeleton/src/layouts/theme.less @@ -38,20 +38,20 @@ --color-field-border-active: @normal-alpha-3; --color-field-background: @white-alpha-1; - --color-function-success: @brand-success; - --color-function-success-dark: darken(@brand-success, 10%); - --color-function-success-light: lighten(@brand-success, 10%); - --color-function-warning: @brand-warning; - --color-function-warning-dark: darken(@brand-warning, 10%); - --color-function-warning-light: lighten(@brand-warning, 10%); - --color-function-information: @brand-link-hover; - --color-function-information-dark: darken(@brand-link-hover, 10%); - --color-function-information-light: lighten(@brand-link-hover, 10%); - --color-function-error: @brand-danger; - --color-function-error-dark: darken(@brand-danger, 10%); - --color-function-error-light: lighten(@brand-danger, 10%); - --color-function-purple: rgb(144, 94, 190); - --color-function-brown: #7b605b; + --color-success: @brand-success; + --colo-success-dark: darken(@brand-success, 10%); + --color-success-light: lighten(@brand-success, 10%); + --color-warning: @brand-warning; + --color-warning-dark: darken(@brand-warning, 10%); + --color-warning-light: lighten(@brand-warning, 10%); + --color-information: @brand-link-hover; + --color-information-dark: darken(@brand-link-hover, 10%); + --color-information-light: lighten(@brand-link-hover, 10%); + --color-error: @brand-danger; + --color-error-dark: darken(@brand-danger, 10%); + --color-error-light: lighten(@brand-danger, 10%); + --color-purple: rgb(144, 94, 190); + --color-brown: #7b605b; --color-pane-background: @white-alpha-1; --color-block-background-normal: @white-alpha-1; @@ -70,3 +70,21 @@ --pane-title-bg-color: rgba(31,56,88,.04); } + +// @deprecated 变量 +:root { + --color-function-success: @brand-success; + --color-function-success-dark: darken(@brand-success, 10%); + --color-function-success-light: lighten(@brand-success, 10%); + --color-function-warning: @brand-warning; + --color-function-warning-dark: darken(@brand-warning, 10%); + --color-function-warning-light: lighten(@brand-warning, 10%); + --color-function-information: @brand-link-hover; + --color-function-information-dark: darken(@brand-link-hover, 10%); + --color-function-information-light: lighten(@brand-link-hover, 10%); + --color-function-error: @brand-danger; + --color-function-error-dark: darken(@brand-danger, 10%); + --color-function-error-light: lighten(@brand-danger, 10%); + --color-function-purple: rgb(144, 94, 190); + --color-function-brown: #7b605b; +} diff --git a/packages/editor-skeleton/src/layouts/top-area.tsx b/packages/editor-skeleton/src/layouts/top-area.tsx index 56949cbb7f..f6b84b3e6f 100644 --- a/packages/editor-skeleton/src/layouts/top-area.tsx +++ b/packages/editor-skeleton/src/layouts/top-area.tsx @@ -4,14 +4,14 @@ import { observer } from '@alilc/lowcode-editor-core'; import { Area } from '../area'; @observer -export default class TopArea extends Component<{ area: Area; itemClassName?: string }> { +export default class TopArea extends Component<{ area: Area; itemClassName?: string; className?: string }> { render() { - const { area, itemClassName } = this.props; + const { area, itemClassName, className } = this.props; if (area.isEmpty()) { return null; } return ( - <div className={classNames('lc-top-area engine-actionpane', { + <div className={classNames(className, 'lc-top-area engine-actionpane', { 'lc-area-visible': area.visible, })} > diff --git a/packages/editor-skeleton/src/layouts/workbench.less b/packages/editor-skeleton/src/layouts/workbench.less index 58123ea464..6d0604a1f1 100644 --- a/packages/editor-skeleton/src/layouts/workbench.less +++ b/packages/editor-skeleton/src/layouts/workbench.less @@ -141,7 +141,7 @@ body { flex-direction: column; background-color: var(--color-background); } - .lc-top-area, .lc-sub-top-area { + .lc-top-area, .lc-workspace-sub-top-area { width: 100%; display: none; margin-bottom: 2px; @@ -152,30 +152,34 @@ body { height: var(--top-area-height); } - &.lc-sub-top-area { - background-color: var(--color-sub-top-area-background, var(--color-pane-background)); - height: var(--sub-top-area-height, var(--top-area-height)); - margin: var(--sub-top-area-margin, 0px 0px 2px 0px); - padding: var(--sub-top-area-padding, 8px 12px 8px 16px); + &.lc-workspace-top-area { + background-color: var(--color-workspace-top-area-background, var(--color-pane-background)); + } + + &.lc-workspace-sub-top-area { + background-color: var(--color-workspace-sub-top-area-background, var(--color-pane-background)); + height: var(--workspace-sub-top-area-height, var(--top-area-height)); + margin: var(--workspace-sub-top-area-margin, 0px 0px 2px 0px); + padding: var(--workspace-sub-top-area-padding, 8px 12px 8px 16px); } &.lc-area-visible { display: flex; } - .lc-top-area-left, .lc-sub-top-area-left { + .lc-top-area-left, .lc-workspace-sub-top-area-left { display: flex; align-items: center; max-width: 100%; } - .lc-top-area-center, .lc-sub-top-area-center { + .lc-top-area-center, .lc-workspace-sub-top-area-center { flex: 1; display: flex; justify-content: center; margin: 0 8px; } - .lc-top-area-right, .lc-sub-top-area-right { + .lc-top-area-right, .lc-workspace-sub-top-area-right { display: flex; align-items: center; > * { @@ -275,9 +279,8 @@ body { flex-direction: column; justify-content: space-between; overflow: hidden; - &.lc-left-area { - background-color: var(--color-left-area-background, var(--color-pane-background)); - } + background-color: var(--color-left-area-background, var(--color-pane-background)); + &.lc-workspace-left-area { background-color: var(--color-workspace-left-area-background, var(--color-pane-background)); } diff --git a/packages/plugin-outline-pane/src/views/style.less b/packages/plugin-outline-pane/src/views/style.less index 37f51a170d..15f115ea6b 100644 --- a/packages/plugin-outline-pane/src/views/style.less +++ b/packages/plugin-outline-pane/src/views/style.less @@ -120,20 +120,20 @@ transform: translateZ(0); transition: all 0.2s ease-in-out; &.invalid { - border-color: var(--color-function-error, red); + border-color: var(--color-error, var(--color-function-error, red)); background-color: var(--color-block-background-error, rgba(240, 154, 154, 0.719)); } } .condition-group-container { - border-bottom: 1px solid var(--color-function-brown, #7b605b); + border-bottom: 1px solid var(--color-brown, var(--color-function-brown, #7b605b)); position: relative; &:before { position: absolute; display: block; width: 0; - border-left: 0.5px solid var(--color-function-brown, #7b605b); + border-left: 0.5px solid var(--color-brown, var(--color-function-brown, #7b605b)); height: 100%; top: 0; left: 0; @@ -142,7 +142,7 @@ } > .condition-group-title { text-align: center; - background-color: var(--color-function-brown, #7b605b); + background-color: var(--color-brown, var(--color-function-brown, #7b605b)); height: 14px; > .lc-title { font-size: 12px; @@ -155,13 +155,13 @@ } } .tree-node-slots { - border-bottom: 1px solid var(--color-function-purple, rgb(144, 94, 190)); + border-bottom: 1px solid var(--color-purple, var(--color-function-purple, rgb(144, 94, 190))); position: relative; &::before { position: absolute; display: block; width: 0; - border-left: 0.5px solid var(--color-function-purple, rgb(144, 94, 190)); + border-left: 0.5px solid var(--color-purple, var(--color-function-purple, rgb(144, 94, 190))); height: 100%; top: 0; left: 0; @@ -170,7 +170,7 @@ } > .tree-node-slots-title { text-align: center; - background-color: var(--color-function-purple, rgb(144, 94, 190)); + background-color: var(--color-purple, var(--color-function-purple, rgb(144, 94, 190))); height: 14px; > .lc-title { font-size: 12px; @@ -183,12 +183,12 @@ } &.insertion-at-slots { padding-bottom: @treeNodeHeight; - border-bottom-color: var(--color-function-error-dark, rgb(182, 55, 55)); + border-bottom-color: var(--color-error-dark, var(--color-function-error-dark, rgb(182, 55, 55))); > .tree-node-slots-title { - background-color: var(--color-function-error-dark, rgb(182, 55, 55)); + background-color: var(--color-error-dark, var(--color-function-error-dark, rgb(182, 55, 55))); } &::before { - border-left-color: var(--color-function-error-dark, rgb(182, 55, 55)); + border-left-color: var(--color-error-dark, var(--color-function-error-dark, rgb(182, 55, 55))); } } } @@ -326,13 +326,13 @@ align-items: center; line-height: 0; &.cond { - color: var(--color-function-error, rgb(179, 52, 6)); + color: var(--color-error, var(--color-function-error, rgb(179, 52, 6))); } &.loop { - color: var(--color-function-success, rgb(103, 187, 187)); + color: var(--color-success, var(--color-function-success, rgb(103, 187, 187))); } &.slot { - color: var(--color-function-purple, rgb(211, 90, 211)); + color: var(--color-purple, var(--color-function-purple, rgb(211, 90, 211))); } } } diff --git a/packages/workspace/src/layouts/workbench.tsx b/packages/workspace/src/layouts/workbench.tsx index 9bdbe3f932..2913576e1c 100644 --- a/packages/workspace/src/layouts/workbench.tsx +++ b/packages/workspace/src/layouts/workbench.tsx @@ -47,7 +47,7 @@ export class Workbench extends Component<{ return ( <div className={classNames('lc-workspace-workbench', className, theme)}> <SkeletonContext.Provider value={skeleton}> - <TopArea area={skeleton.topArea} itemClassName={topAreaItemClassName} /> + <TopArea className="lc-workspace-top-area" area={skeleton.topArea} itemClassName={topAreaItemClassName} /> <div className="lc-workspace-workbench-body"> <LeftArea className="lc-workspace-left-area lc-left-area" area={skeleton.leftArea} /> <LeftFloatPane area={skeleton.leftFloatArea} /> From e7a3ba9e9aae210cb67c565c37038373731ea256 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 19 Oct 2023 14:19:47 +0800 Subject: [PATCH 039/219] chore(docs): publish docs 1.1.12 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 6c43fe1d0f..177226a287 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.1.11", + "version": "1.1.12", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 0f02080035923db7b5c39644ad4a41da0f56c892 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Fri, 20 Oct 2023 15:52:31 +0800 Subject: [PATCH 040/219] chore(release): publish 1.2.0 --- lerna.json | 2 +- packages/designer/package.json | 8 ++++---- packages/editor-core/package.json | 6 +++--- packages/editor-skeleton/package.json | 10 +++++----- packages/engine/package.json | 18 +++++++++--------- packages/ignitor/package.json | 2 +- packages/plugin-designer/package.json | 8 ++++---- packages/plugin-outline-pane/package.json | 6 +++--- packages/rax-renderer/package.json | 6 +++--- packages/rax-simulator-renderer/package.json | 10 +++++----- packages/react-renderer/package.json | 4 ++-- packages/react-simulator-renderer/package.json | 10 +++++----- packages/renderer-core/package.json | 8 ++++---- packages/shell/package.json | 14 +++++++------- packages/types/package.json | 2 +- packages/utils/package.json | 4 ++-- packages/workspace/package.json | 12 ++++++------ 17 files changed, 65 insertions(+), 65 deletions(-) diff --git a/lerna.json b/lerna.json index 0bb34d1aee..b76ff2ae85 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "lerna": "4.0.0", - "version": "1.1.10", + "version": "1.2.0", "npmClient": "yarn", "useWorkspaces": true, "packages": [ diff --git a/packages/designer/package.json b/packages/designer/package.json index 1081aef8ff..c32b54a778 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-designer", - "version": "1.1.10", + "version": "1.2.0", "description": "Designer for Ali LowCode Engine", "main": "lib/index.js", "module": "es/index.js", @@ -15,9 +15,9 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-editor-core": "1.1.10", - "@alilc/lowcode-types": "1.1.10", - "@alilc/lowcode-utils": "1.1.10", + "@alilc/lowcode-editor-core": "1.2.0", + "@alilc/lowcode-types": "1.2.0", + "@alilc/lowcode-utils": "1.2.0", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/editor-core/package.json b/packages/editor-core/package.json index e05002469e..bd4899c9a5 100644 --- a/packages/editor-core/package.json +++ b/packages/editor-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-core", - "version": "1.1.10", + "version": "1.2.0", "description": "Core Api for Ali lowCode engine", "license": "MIT", "main": "lib/index.js", @@ -14,8 +14,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.1.10", - "@alilc/lowcode-utils": "1.1.10", + "@alilc/lowcode-types": "1.2.0", + "@alilc/lowcode-utils": "1.2.0", "classnames": "^2.2.6", "debug": "^4.1.1", "intl-messageformat": "^9.3.1", diff --git a/packages/editor-skeleton/package.json b/packages/editor-skeleton/package.json index 2c8efccebf..0b23435f91 100644 --- a/packages/editor-skeleton/package.json +++ b/packages/editor-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-skeleton", - "version": "1.1.10", + "version": "1.2.0", "description": "alibaba lowcode editor skeleton", "main": "lib/index.js", "module": "es/index.js", @@ -19,10 +19,10 @@ ], "dependencies": { "@alifd/next": "^1.20.12", - "@alilc/lowcode-designer": "1.1.10", - "@alilc/lowcode-editor-core": "1.1.10", - "@alilc/lowcode-types": "1.1.10", - "@alilc/lowcode-utils": "1.1.10", + "@alilc/lowcode-designer": "1.2.0", + "@alilc/lowcode-editor-core": "1.2.0", + "@alilc/lowcode-types": "1.2.0", + "@alilc/lowcode-utils": "1.2.0", "classnames": "^2.2.6", "react": "^16.8.1", "react-dom": "^16.8.1" diff --git a/packages/engine/package.json b/packages/engine/package.json index a9521d486b..59ecb02610 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine", - "version": "1.1.10", + "version": "1.2.0", "description": "An enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系", "main": "lib/engine-core.js", "module": "es/engine-core.js", @@ -19,15 +19,15 @@ "license": "MIT", "dependencies": { "@alifd/next": "^1.19.12", - "@alilc/lowcode-designer": "1.1.10", - "@alilc/lowcode-editor-core": "1.1.10", - "@alilc/lowcode-editor-skeleton": "1.1.10", + "@alilc/lowcode-designer": "1.2.0", + "@alilc/lowcode-editor-core": "1.2.0", + "@alilc/lowcode-editor-skeleton": "1.2.0", "@alilc/lowcode-engine-ext": "^1.0.0", - "@alilc/lowcode-plugin-designer": "1.1.10", - "@alilc/lowcode-plugin-outline-pane": "1.1.10", - "@alilc/lowcode-shell": "1.1.10", - "@alilc/lowcode-utils": "1.1.10", - "@alilc/lowcode-workspace": "1.1.10", + "@alilc/lowcode-plugin-designer": "1.2.0", + "@alilc/lowcode-plugin-outline-pane": "1.2.0", + "@alilc/lowcode-shell": "1.2.0", + "@alilc/lowcode-utils": "1.2.0", + "@alilc/lowcode-workspace": "1.2.0", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/ignitor/package.json b/packages/ignitor/package.json index 116f98e5d5..f524eba845 100644 --- a/packages/ignitor/package.json +++ b/packages/ignitor/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-ignitor", - "version": "1.1.10", + "version": "1.2.0", "description": "点火器,bootstrap lce project", "main": "lib/index.js", "private": true, diff --git a/packages/plugin-designer/package.json b/packages/plugin-designer/package.json index 760d57a133..65c931ef37 100644 --- a/packages/plugin-designer/package.json +++ b/packages/plugin-designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-designer", - "version": "1.1.10", + "version": "1.2.0", "description": "alibaba lowcode editor designer plugin", "files": [ "es", @@ -18,9 +18,9 @@ ], "author": "xiayang.xy", "dependencies": { - "@alilc/lowcode-designer": "1.1.10", - "@alilc/lowcode-editor-core": "1.1.10", - "@alilc/lowcode-utils": "1.1.10", + "@alilc/lowcode-designer": "1.2.0", + "@alilc/lowcode-editor-core": "1.2.0", + "@alilc/lowcode-utils": "1.2.0", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/plugin-outline-pane/package.json b/packages/plugin-outline-pane/package.json index 4a71eb26b8..e933128018 100644 --- a/packages/plugin-outline-pane/package.json +++ b/packages/plugin-outline-pane/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-outline-pane", - "version": "1.1.10", + "version": "1.2.0", "description": "Outline pane for Ali lowCode engine", "files": [ "es", @@ -13,8 +13,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.1.10", - "@alilc/lowcode-utils": "1.1.10", + "@alilc/lowcode-types": "1.2.0", + "@alilc/lowcode-utils": "1.2.0", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/rax-renderer/package.json b/packages/rax-renderer/package.json index 90a9b7e08e..7d55b5ae6c 100644 --- a/packages/rax-renderer/package.json +++ b/packages/rax-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-renderer", - "version": "1.1.10", + "version": "1.2.0", "description": "Rax renderer for Ali lowCode engine", "main": "lib/index.js", "module": "es/index.js", @@ -30,8 +30,8 @@ "build": "build-scripts build" }, "dependencies": { - "@alilc/lowcode-renderer-core": "1.1.10", - "@alilc/lowcode-utils": "1.1.10", + "@alilc/lowcode-renderer-core": "1.2.0", + "@alilc/lowcode-utils": "1.2.0", "rax-find-dom-node": "^1.0.1" }, "devDependencies": { diff --git a/packages/rax-simulator-renderer/package.json b/packages/rax-simulator-renderer/package.json index 8ff7f1f0a4..69a029578c 100644 --- a/packages/rax-simulator-renderer/package.json +++ b/packages/rax-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-simulator-renderer", - "version": "1.1.10", + "version": "1.2.0", "description": "rax simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -13,10 +13,10 @@ "build:umd": "build-scripts build --config build.umd.json" }, "dependencies": { - "@alilc/lowcode-designer": "1.1.10", - "@alilc/lowcode-rax-renderer": "1.1.10", - "@alilc/lowcode-types": "1.1.10", - "@alilc/lowcode-utils": "1.1.10", + "@alilc/lowcode-designer": "1.2.0", + "@alilc/lowcode-rax-renderer": "1.2.0", + "@alilc/lowcode-types": "1.2.0", + "@alilc/lowcode-utils": "1.2.0", "classnames": "^2.2.6", "driver-universal": "^3.1.3", "history": "^5.0.0", diff --git a/packages/react-renderer/package.json b/packages/react-renderer/package.json index 1535cb2088..f1d8b5ea54 100644 --- a/packages/react-renderer/package.json +++ b/packages/react-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-renderer", - "version": "1.1.10", + "version": "1.2.0", "description": "react renderer for ali lowcode engine", "main": "lib/index.js", "module": "es/index.js", @@ -22,7 +22,7 @@ ], "dependencies": { "@alifd/next": "^1.21.16", - "@alilc/lowcode-renderer-core": "1.1.10" + "@alilc/lowcode-renderer-core": "1.2.0" }, "devDependencies": { "@alib/build-scripts": "^0.1.18", diff --git a/packages/react-simulator-renderer/package.json b/packages/react-simulator-renderer/package.json index ffb8228dfd..a265c3e88f 100644 --- a/packages/react-simulator-renderer/package.json +++ b/packages/react-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-simulator-renderer", - "version": "1.1.10", + "version": "1.2.0", "description": "react simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -17,10 +17,10 @@ "test:cov": "build-scripts test --config build.test.json --jest-coverage" }, "dependencies": { - "@alilc/lowcode-designer": "1.1.10", - "@alilc/lowcode-react-renderer": "1.1.10", - "@alilc/lowcode-types": "1.1.10", - "@alilc/lowcode-utils": "1.1.10", + "@alilc/lowcode-designer": "1.2.0", + "@alilc/lowcode-react-renderer": "1.2.0", + "@alilc/lowcode-types": "1.2.0", + "@alilc/lowcode-utils": "1.2.0", "classnames": "^2.2.6", "mobx": "^6.3.0", "mobx-react": "^7.2.0", diff --git a/packages/renderer-core/package.json b/packages/renderer-core/package.json index 52b13b86c6..ecfd233809 100644 --- a/packages/renderer-core/package.json +++ b/packages/renderer-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-renderer-core", - "version": "1.1.10", + "version": "1.2.0", "description": "renderer core", "license": "MIT", "main": "lib/index.js", @@ -16,8 +16,8 @@ }, "dependencies": { "@alilc/lowcode-datasource-engine": "^1.0.0", - "@alilc/lowcode-types": "1.1.10", - "@alilc/lowcode-utils": "1.1.10", + "@alilc/lowcode-types": "1.2.0", + "@alilc/lowcode-utils": "1.2.0", "classnames": "^2.2.6", "debug": "^4.1.1", "fetch-jsonp": "^1.1.3", @@ -32,7 +32,7 @@ "devDependencies": { "@alib/build-scripts": "^0.1.18", "@alifd/next": "^1.26.0", - "@alilc/lowcode-designer": "1.1.10", + "@alilc/lowcode-designer": "1.2.0", "@babel/plugin-transform-typescript": "^7.16.8", "@testing-library/react": "^11.2.2", "@types/classnames": "^2.2.11", diff --git a/packages/shell/package.json b/packages/shell/package.json index 09768a06a7..884915877c 100644 --- a/packages/shell/package.json +++ b/packages/shell/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-shell", - "version": "1.1.10", + "version": "1.2.0", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -13,12 +13,12 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.1.10", - "@alilc/lowcode-editor-core": "1.1.10", - "@alilc/lowcode-editor-skeleton": "1.1.10", - "@alilc/lowcode-types": "1.1.10", - "@alilc/lowcode-utils": "1.1.10", - "@alilc/lowcode-workspace": "1.1.10", + "@alilc/lowcode-designer": "1.2.0", + "@alilc/lowcode-editor-core": "1.2.0", + "@alilc/lowcode-editor-skeleton": "1.2.0", + "@alilc/lowcode-types": "1.2.0", + "@alilc/lowcode-utils": "1.2.0", + "@alilc/lowcode-workspace": "1.2.0", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", diff --git a/packages/types/package.json b/packages/types/package.json index fe9cd51235..155242712a 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-types", - "version": "1.1.10", + "version": "1.2.0", "description": "Types for Ali lowCode engine", "files": [ "es", diff --git a/packages/utils/package.json b/packages/utils/package.json index ecf6bff3c0..f9c0005b4d 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-utils", - "version": "1.1.10", + "version": "1.2.0", "description": "Utils for Ali lowCode engine", "files": [ "lib", @@ -14,7 +14,7 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.1.10", + "@alilc/lowcode-types": "1.2.0", "lodash": "^4.17.21", "mobx": "^6.3.0", "react": "^16" diff --git a/packages/workspace/package.json b/packages/workspace/package.json index 8802691d60..7e662af378 100644 --- a/packages/workspace/package.json +++ b/packages/workspace/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-workspace", - "version": "1.1.10", + "version": "1.2.0", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -15,11 +15,11 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.1.10", - "@alilc/lowcode-editor-core": "1.1.10", - "@alilc/lowcode-editor-skeleton": "1.1.10", - "@alilc/lowcode-types": "1.1.10", - "@alilc/lowcode-utils": "1.1.10", + "@alilc/lowcode-designer": "1.2.0", + "@alilc/lowcode-editor-core": "1.2.0", + "@alilc/lowcode-editor-skeleton": "1.2.0", + "@alilc/lowcode-types": "1.2.0", + "@alilc/lowcode-utils": "1.2.0", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", From 11ee97c6dafe1ecb60402488ad72b722005cda55 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 26 Oct 2023 11:24:17 +0800 Subject: [PATCH 041/219] fix: fixed the problem caused by component list being overwritten by Hoc --- packages/renderer-core/src/renderer/base.tsx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index 7b9562fcc6..1980734e43 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -615,9 +615,6 @@ export default function baseRendererFactory(): IBaseRenderComponent { }); }); - Comp = compWrapper(Comp, { baseRenderer: this, schema }); - components[schema.componentName] = Comp; - otherProps.ref = (ref: any) => { this.$(props.fieldId || props.ref, ref); // 收集ref const refProps = props.ref; @@ -701,9 +698,9 @@ export default function baseRendererFactory(): IBaseRenderComponent { */ get __componentHOCs(): IComponentConstruct[] { if (this.__designModeIsDesign) { - return [leafWrapper]; + return [leafWrapper, compWrapper]; } - return []; + return [compWrapper]; } __getSchemaChildrenVirtualDom = (schema: IPublicTypeNodeSchema | undefined, scope: any, Comp: any, condition = true) => { From 055ab68a4b110385d737c0aafd4362d9c86c96e4 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 26 Oct 2023 11:37:30 +0800 Subject: [PATCH 042/219] fix: fix document.onMountNode parameters --- packages/designer/src/document/document-model.ts | 9 ++++++++- packages/shell/src/model/document-model.ts | 9 +++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/designer/src/document/document-model.ts b/packages/designer/src/document/document-model.ts index 9521fef383..edca8fd818 100644 --- a/packages/designer/src/document/document-model.ts +++ b/packages/designer/src/document/document-model.ts @@ -74,7 +74,6 @@ export interface IDocumentModel extends Omit<IPublicModelDocumentModel< 'onRemoveNode' | 'onChangeDetecting' | 'onChangeSelection' | - 'onMountNode' | 'onChangeNodeProp' | 'onImportSchema' | 'isDetectingNode' | @@ -414,6 +413,14 @@ export class DocumentModel implements IDocumentModel { return node ? !node.isPurged : false; } + onMountNode(fn: (payload: { node: INode }) => void) { + this.designer.editor.eventBus.on('node.add', fn as any); + + return () => { + this.designer.editor.eventBus.off('node.add', fn as any); + }; + } + /** * 根据 schema 创建一个节点 */ diff --git a/packages/shell/src/model/document-model.ts b/packages/shell/src/model/document-model.ts index 2c5c7b632e..bd0ccaf75e 100644 --- a/packages/shell/src/model/document-model.ts +++ b/packages/shell/src/model/document-model.ts @@ -252,10 +252,11 @@ export class DocumentModel implements IPublicModelDocumentModel { * 当前 document 新增节点事件,此时节点已经挂载到 document 上 */ onMountNode(fn: (payload: { node: IPublicModelNode }) => void): IPublicTypeDisposable { - this[editorSymbol].eventBus.on('node.add', fn as any); - return () => { - this[editorSymbol].eventBus.off('node.add', fn as any); - }; + return this[documentSymbol].onMountNode(({ + node, + }) => { + fn({ node: ShellNode.create(node)! }); + }); } /** From b3b2a03642da21f4747108d1da77488f9655dcfc Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Fri, 27 Oct 2023 13:14:57 +0800 Subject: [PATCH 043/219] chore(release): publish 1.2.1 --- lerna.json | 2 +- packages/designer/package.json | 8 ++++---- packages/editor-core/package.json | 6 +++--- packages/editor-skeleton/package.json | 10 +++++----- packages/engine/package.json | 18 +++++++++--------- packages/ignitor/package.json | 2 +- packages/plugin-designer/package.json | 8 ++++---- packages/plugin-outline-pane/package.json | 6 +++--- packages/rax-renderer/package.json | 6 +++--- packages/rax-simulator-renderer/package.json | 10 +++++----- packages/react-renderer/package.json | 4 ++-- packages/react-simulator-renderer/package.json | 10 +++++----- packages/renderer-core/package.json | 8 ++++---- packages/shell/package.json | 14 +++++++------- packages/types/package.json | 2 +- packages/utils/package.json | 4 ++-- packages/workspace/package.json | 12 ++++++------ 17 files changed, 65 insertions(+), 65 deletions(-) diff --git a/lerna.json b/lerna.json index b76ff2ae85..8201f484d6 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "lerna": "4.0.0", - "version": "1.2.0", + "version": "1.2.1", "npmClient": "yarn", "useWorkspaces": true, "packages": [ diff --git a/packages/designer/package.json b/packages/designer/package.json index c32b54a778..2f57c80c38 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-designer", - "version": "1.2.0", + "version": "1.2.1", "description": "Designer for Ali LowCode Engine", "main": "lib/index.js", "module": "es/index.js", @@ -15,9 +15,9 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-editor-core": "1.2.0", - "@alilc/lowcode-types": "1.2.0", - "@alilc/lowcode-utils": "1.2.0", + "@alilc/lowcode-editor-core": "1.2.1", + "@alilc/lowcode-types": "1.2.1", + "@alilc/lowcode-utils": "1.2.1", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/editor-core/package.json b/packages/editor-core/package.json index bd4899c9a5..060f986ed3 100644 --- a/packages/editor-core/package.json +++ b/packages/editor-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-core", - "version": "1.2.0", + "version": "1.2.1", "description": "Core Api for Ali lowCode engine", "license": "MIT", "main": "lib/index.js", @@ -14,8 +14,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.2.0", - "@alilc/lowcode-utils": "1.2.0", + "@alilc/lowcode-types": "1.2.1", + "@alilc/lowcode-utils": "1.2.1", "classnames": "^2.2.6", "debug": "^4.1.1", "intl-messageformat": "^9.3.1", diff --git a/packages/editor-skeleton/package.json b/packages/editor-skeleton/package.json index 0b23435f91..0f55e637db 100644 --- a/packages/editor-skeleton/package.json +++ b/packages/editor-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-skeleton", - "version": "1.2.0", + "version": "1.2.1", "description": "alibaba lowcode editor skeleton", "main": "lib/index.js", "module": "es/index.js", @@ -19,10 +19,10 @@ ], "dependencies": { "@alifd/next": "^1.20.12", - "@alilc/lowcode-designer": "1.2.0", - "@alilc/lowcode-editor-core": "1.2.0", - "@alilc/lowcode-types": "1.2.0", - "@alilc/lowcode-utils": "1.2.0", + "@alilc/lowcode-designer": "1.2.1", + "@alilc/lowcode-editor-core": "1.2.1", + "@alilc/lowcode-types": "1.2.1", + "@alilc/lowcode-utils": "1.2.1", "classnames": "^2.2.6", "react": "^16.8.1", "react-dom": "^16.8.1" diff --git a/packages/engine/package.json b/packages/engine/package.json index 59ecb02610..29ba8c36f6 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine", - "version": "1.2.0", + "version": "1.2.1", "description": "An enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系", "main": "lib/engine-core.js", "module": "es/engine-core.js", @@ -19,15 +19,15 @@ "license": "MIT", "dependencies": { "@alifd/next": "^1.19.12", - "@alilc/lowcode-designer": "1.2.0", - "@alilc/lowcode-editor-core": "1.2.0", - "@alilc/lowcode-editor-skeleton": "1.2.0", + "@alilc/lowcode-designer": "1.2.1", + "@alilc/lowcode-editor-core": "1.2.1", + "@alilc/lowcode-editor-skeleton": "1.2.1", "@alilc/lowcode-engine-ext": "^1.0.0", - "@alilc/lowcode-plugin-designer": "1.2.0", - "@alilc/lowcode-plugin-outline-pane": "1.2.0", - "@alilc/lowcode-shell": "1.2.0", - "@alilc/lowcode-utils": "1.2.0", - "@alilc/lowcode-workspace": "1.2.0", + "@alilc/lowcode-plugin-designer": "1.2.1", + "@alilc/lowcode-plugin-outline-pane": "1.2.1", + "@alilc/lowcode-shell": "1.2.1", + "@alilc/lowcode-utils": "1.2.1", + "@alilc/lowcode-workspace": "1.2.1", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/ignitor/package.json b/packages/ignitor/package.json index f524eba845..cdf2928b56 100644 --- a/packages/ignitor/package.json +++ b/packages/ignitor/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-ignitor", - "version": "1.2.0", + "version": "1.2.1", "description": "点火器,bootstrap lce project", "main": "lib/index.js", "private": true, diff --git a/packages/plugin-designer/package.json b/packages/plugin-designer/package.json index 65c931ef37..9b64b0709f 100644 --- a/packages/plugin-designer/package.json +++ b/packages/plugin-designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-designer", - "version": "1.2.0", + "version": "1.2.1", "description": "alibaba lowcode editor designer plugin", "files": [ "es", @@ -18,9 +18,9 @@ ], "author": "xiayang.xy", "dependencies": { - "@alilc/lowcode-designer": "1.2.0", - "@alilc/lowcode-editor-core": "1.2.0", - "@alilc/lowcode-utils": "1.2.0", + "@alilc/lowcode-designer": "1.2.1", + "@alilc/lowcode-editor-core": "1.2.1", + "@alilc/lowcode-utils": "1.2.1", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/plugin-outline-pane/package.json b/packages/plugin-outline-pane/package.json index e933128018..8295094fe0 100644 --- a/packages/plugin-outline-pane/package.json +++ b/packages/plugin-outline-pane/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-outline-pane", - "version": "1.2.0", + "version": "1.2.1", "description": "Outline pane for Ali lowCode engine", "files": [ "es", @@ -13,8 +13,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.2.0", - "@alilc/lowcode-utils": "1.2.0", + "@alilc/lowcode-types": "1.2.1", + "@alilc/lowcode-utils": "1.2.1", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/rax-renderer/package.json b/packages/rax-renderer/package.json index 7d55b5ae6c..ed7434b942 100644 --- a/packages/rax-renderer/package.json +++ b/packages/rax-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-renderer", - "version": "1.2.0", + "version": "1.2.1", "description": "Rax renderer for Ali lowCode engine", "main": "lib/index.js", "module": "es/index.js", @@ -30,8 +30,8 @@ "build": "build-scripts build" }, "dependencies": { - "@alilc/lowcode-renderer-core": "1.2.0", - "@alilc/lowcode-utils": "1.2.0", + "@alilc/lowcode-renderer-core": "1.2.1", + "@alilc/lowcode-utils": "1.2.1", "rax-find-dom-node": "^1.0.1" }, "devDependencies": { diff --git a/packages/rax-simulator-renderer/package.json b/packages/rax-simulator-renderer/package.json index 69a029578c..383cc29895 100644 --- a/packages/rax-simulator-renderer/package.json +++ b/packages/rax-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-simulator-renderer", - "version": "1.2.0", + "version": "1.2.1", "description": "rax simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -13,10 +13,10 @@ "build:umd": "build-scripts build --config build.umd.json" }, "dependencies": { - "@alilc/lowcode-designer": "1.2.0", - "@alilc/lowcode-rax-renderer": "1.2.0", - "@alilc/lowcode-types": "1.2.0", - "@alilc/lowcode-utils": "1.2.0", + "@alilc/lowcode-designer": "1.2.1", + "@alilc/lowcode-rax-renderer": "1.2.1", + "@alilc/lowcode-types": "1.2.1", + "@alilc/lowcode-utils": "1.2.1", "classnames": "^2.2.6", "driver-universal": "^3.1.3", "history": "^5.0.0", diff --git a/packages/react-renderer/package.json b/packages/react-renderer/package.json index f1d8b5ea54..142e90ebb6 100644 --- a/packages/react-renderer/package.json +++ b/packages/react-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-renderer", - "version": "1.2.0", + "version": "1.2.1", "description": "react renderer for ali lowcode engine", "main": "lib/index.js", "module": "es/index.js", @@ -22,7 +22,7 @@ ], "dependencies": { "@alifd/next": "^1.21.16", - "@alilc/lowcode-renderer-core": "1.2.0" + "@alilc/lowcode-renderer-core": "1.2.1" }, "devDependencies": { "@alib/build-scripts": "^0.1.18", diff --git a/packages/react-simulator-renderer/package.json b/packages/react-simulator-renderer/package.json index a265c3e88f..18b57e28fe 100644 --- a/packages/react-simulator-renderer/package.json +++ b/packages/react-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-simulator-renderer", - "version": "1.2.0", + "version": "1.2.1", "description": "react simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -17,10 +17,10 @@ "test:cov": "build-scripts test --config build.test.json --jest-coverage" }, "dependencies": { - "@alilc/lowcode-designer": "1.2.0", - "@alilc/lowcode-react-renderer": "1.2.0", - "@alilc/lowcode-types": "1.2.0", - "@alilc/lowcode-utils": "1.2.0", + "@alilc/lowcode-designer": "1.2.1", + "@alilc/lowcode-react-renderer": "1.2.1", + "@alilc/lowcode-types": "1.2.1", + "@alilc/lowcode-utils": "1.2.1", "classnames": "^2.2.6", "mobx": "^6.3.0", "mobx-react": "^7.2.0", diff --git a/packages/renderer-core/package.json b/packages/renderer-core/package.json index ecfd233809..3d4e3c7e09 100644 --- a/packages/renderer-core/package.json +++ b/packages/renderer-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-renderer-core", - "version": "1.2.0", + "version": "1.2.1", "description": "renderer core", "license": "MIT", "main": "lib/index.js", @@ -16,8 +16,8 @@ }, "dependencies": { "@alilc/lowcode-datasource-engine": "^1.0.0", - "@alilc/lowcode-types": "1.2.0", - "@alilc/lowcode-utils": "1.2.0", + "@alilc/lowcode-types": "1.2.1", + "@alilc/lowcode-utils": "1.2.1", "classnames": "^2.2.6", "debug": "^4.1.1", "fetch-jsonp": "^1.1.3", @@ -32,7 +32,7 @@ "devDependencies": { "@alib/build-scripts": "^0.1.18", "@alifd/next": "^1.26.0", - "@alilc/lowcode-designer": "1.2.0", + "@alilc/lowcode-designer": "1.2.1", "@babel/plugin-transform-typescript": "^7.16.8", "@testing-library/react": "^11.2.2", "@types/classnames": "^2.2.11", diff --git a/packages/shell/package.json b/packages/shell/package.json index 884915877c..36ea05d7b1 100644 --- a/packages/shell/package.json +++ b/packages/shell/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-shell", - "version": "1.2.0", + "version": "1.2.1", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -13,12 +13,12 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.2.0", - "@alilc/lowcode-editor-core": "1.2.0", - "@alilc/lowcode-editor-skeleton": "1.2.0", - "@alilc/lowcode-types": "1.2.0", - "@alilc/lowcode-utils": "1.2.0", - "@alilc/lowcode-workspace": "1.2.0", + "@alilc/lowcode-designer": "1.2.1", + "@alilc/lowcode-editor-core": "1.2.1", + "@alilc/lowcode-editor-skeleton": "1.2.1", + "@alilc/lowcode-types": "1.2.1", + "@alilc/lowcode-utils": "1.2.1", + "@alilc/lowcode-workspace": "1.2.1", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", diff --git a/packages/types/package.json b/packages/types/package.json index 155242712a..2d66d2f621 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-types", - "version": "1.2.0", + "version": "1.2.1", "description": "Types for Ali lowCode engine", "files": [ "es", diff --git a/packages/utils/package.json b/packages/utils/package.json index f9c0005b4d..c2433f1521 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-utils", - "version": "1.2.0", + "version": "1.2.1", "description": "Utils for Ali lowCode engine", "files": [ "lib", @@ -14,7 +14,7 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.2.0", + "@alilc/lowcode-types": "1.2.1", "lodash": "^4.17.21", "mobx": "^6.3.0", "react": "^16" diff --git a/packages/workspace/package.json b/packages/workspace/package.json index 7e662af378..a5d7d4ceae 100644 --- a/packages/workspace/package.json +++ b/packages/workspace/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-workspace", - "version": "1.2.0", + "version": "1.2.1", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -15,11 +15,11 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.2.0", - "@alilc/lowcode-editor-core": "1.2.0", - "@alilc/lowcode-editor-skeleton": "1.2.0", - "@alilc/lowcode-types": "1.2.0", - "@alilc/lowcode-utils": "1.2.0", + "@alilc/lowcode-designer": "1.2.1", + "@alilc/lowcode-editor-core": "1.2.1", + "@alilc/lowcode-editor-skeleton": "1.2.1", + "@alilc/lowcode-types": "1.2.1", + "@alilc/lowcode-utils": "1.2.1", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", From 95a48e057f856201cb3cbf7c5046128da7e64df6 Mon Sep 17 00:00:00 2001 From: Rainke <woshihepeng520@163.com> Date: Wed, 1 Nov 2023 10:37:14 +0800 Subject: [PATCH 044/219] =?UTF-8?q?fix:=20import=20schema=20=E4=B9=8B?= =?UTF-8?q?=E5=90=8E=20cache=20=E5=88=A4=E6=96=AD=E9=94=99=E8=AF=AF(#2596)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/renderer-core/src/hoc/index.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/renderer-core/src/hoc/index.tsx b/packages/renderer-core/src/hoc/index.tsx index 3e7f5ec6a1..4851ea486f 100644 --- a/packages/renderer-core/src/hoc/index.tsx +++ b/packages/renderer-core/src/hoc/index.tsx @@ -49,7 +49,7 @@ function patchDidCatch(Comp: any, { baseRenderer }: Options) { } } -const cache = new Map(); +const cache = new Map<string, { Comp: any; WrapperComponent: any }>(); export function compWrapper(Comp: any, options: Options) { const { createElement, Component, forwardRef } = adapter.getRuntime(); @@ -62,8 +62,8 @@ export function compWrapper(Comp: any, options: Options) { return Comp; } - if (cache.has(options.schema.id)) { - return cache.get(options.schema.id); + if (cache.has(options.schema.id) && cache.get(options.schema.id)?.Comp === Comp) { + return cache.get(options.schema.id)?.WrapperComponent; } class Wrapper extends Component { @@ -82,7 +82,7 @@ export function compWrapper(Comp: any, options: Options) { Comp, ); - cache.set(options.schema.id, WrapperComponent); + cache.set(options.schema.id, { WrapperComponent, Comp }); return WrapperComponent; } From c5ba2f3ef1ce52f7a2fae9743a2cd11022563f7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= <liujup@foxmail.com> Date: Fri, 3 Nov 2023 14:01:58 +0800 Subject: [PATCH 045/219] docs: update useEditor.md --- docs/docs/guide/create/useEditor.md | 56 ----------------------------- 1 file changed, 56 deletions(-) diff --git a/docs/docs/guide/create/useEditor.md b/docs/docs/guide/create/useEditor.md index cbb38f77de..8df4158a6c 100644 --- a/docs/docs/guide/create/useEditor.md +++ b/docs/docs/guide/create/useEditor.md @@ -105,8 +105,6 @@ sidebar_position: 0 ### 初始化低代码编辑器 -#### 方法 2.1 使用 init 进行初始化 - 正确引入后,我们可以直接通过 window 上的变量进行引用,如 `window.AliLowCodeEngine.init`。您可以直接通过此方式初始化低代码引擎: ```javascript @@ -144,59 +142,5 @@ init 的功能包括但不限于: > 本节中的低代码编辑器例子可以在 demo 中找到:[https://github.com/alibaba/lowcode-demo/blob/main/demo-general/src/index.ts](https://github.com/alibaba/lowcode-demo/blob/main/demo-general/src/index.ts) - -#### 方法 2.2 使用 skeletonCabin.Workbench 方式初始化 - -`init()` 内部会调用 `ReactDOM.render()` 函数,因此这样初始化的内容没有办法与外部的 React 组件进行通信,也就没有办法在一些自定义的 plugin 中获取 redux 上的全局数据等内容。 - -因此,这种场景下您可以通过 `skeletonCabin.Workbench` 进行初始化。 - -> 注:**不需要**同时使用 2.1 和 2.2 的方法。根据使用场景,当且只当有需要插件和外界进行一定通信时,才需要使用 2.2 提供的方法。 - - -```javascript -import React, { useState, useEffect } from 'react'; -import { project, plugins, common, skeleton } from '@alilc/lowcode-engine'; - -// 此处略去若干依赖引用 - -async function registerPlugins() { - // 此处略去若干插件注册 -} -function EditorView() { - /** 插件是否已初始化成功,因为必须要等插件初始化后才能渲染 Workbench */ - const [hasPluginInited, setHasPluginInited] = useState(false); - - useEffect(() => { - plugins.init().then(() => { - setHasPluginInited(true); - }).catch(err => console.error(err)); - }, []); - - if (!hasPluginInited) { - return null; - } - const Workbench = common.skeletonCabin.Workbench; - return <Workbench />; -} - -(async function main() { - await registerPlugins(); - config.setConfig({ - enableCondition: true, - enableCanvasLock: true, - supportVariableGlobally: true, - requestHandlersMap: { - fetch: createFetchHandler() - } - }); - - ReactDOM.render(<EditorView />, document.getElementById('lce-container')!); -})(); -``` - -> 本节中的低代码编辑器类似的例子可以在 demo 中找到:[https://github.com/alibaba/lowcode-demo/blob/main/demo-custom-initialization/src/index.tsx](https://github.com/alibaba/lowcode-demo/blob/main/demo-custom-initialization/src/index.tsx) - - ## 配置低代码编辑器 详见[低代码扩展简述](/site/docs/guide/expand/editor/summary)章节。 From c65c17f779fc38648e76dc033c19bffc85365a5c Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Fri, 3 Nov 2023 14:05:04 +0800 Subject: [PATCH 046/219] docs: publish docs 1.1.13 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 177226a287..bdc734c71e 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.1.12", + "version": "1.1.13", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 97eb477746c95eab15dccc6ec728159e9edb19a3 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 7 Nov 2023 16:05:50 +0800 Subject: [PATCH 047/219] feat: update engine classes exports --- packages/engine/src/modules/classes.ts | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/packages/engine/src/modules/classes.ts b/packages/engine/src/modules/classes.ts index d68ea43de2..3b7627deb0 100644 --- a/packages/engine/src/modules/classes.ts +++ b/packages/engine/src/modules/classes.ts @@ -1,4 +1,4 @@ -import { +export { Project, Skeleton, DocumentModel, @@ -12,20 +12,5 @@ import { SimulatorHost, SkeletonItem, } from '@alilc/lowcode-shell'; -import { Node as InnerNode } from '@alilc/lowcode-designer'; +export { Node as InnerNode } from '@alilc/lowcode-designer'; -export default { - Project, - Skeleton, - DocumentModel, - Node, - NodeChildren, - History, - SettingPropEntry, - SettingTopEntry, - InnerNode, - Selection, - Prop, - SimulatorHost, - SkeletonItem, -}; From e3611dcf06a0a24b691fab00734ce4cecb501f25 Mon Sep 17 00:00:00 2001 From: keuby <knightchen@knx.com.cn> Date: Tue, 7 Nov 2023 17:20:13 +0800 Subject: [PATCH 048/219] feat(utils|types): add esmodule support for component meta resources (#2603) * feat(utils): support script type param for assest loader * feat(types): update AssestsJson type --- .../src/shell/type/remote-component-description.ts | 6 +++++- packages/utils/src/asset.ts | 10 +++++----- packages/utils/src/script.ts | 9 ++++++--- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/packages/types/src/shell/type/remote-component-description.ts b/packages/types/src/shell/type/remote-component-description.ts index 7ba5324391..2337203657 100644 --- a/packages/types/src/shell/type/remote-component-description.ts +++ b/packages/types/src/shell/type/remote-component-description.ts @@ -1,17 +1,21 @@ +import { Asset } from '../../assets'; import { IPublicTypeComponentMetadata, IPublicTypeReference } from './'; /** * 远程物料描述 */ export interface IPublicTypeRemoteComponentDescription extends IPublicTypeComponentMetadata { + /** * 组件描述导出名字,可以通过 window[exportName] 获取到组件描述的 Object 内容; */ exportName?: string; + /** * 组件描述的资源链接; */ - url?: string; + url?: Asset; + /** * 组件 (库) 的 npm 信息; */ diff --git a/packages/utils/src/asset.ts b/packages/utils/src/asset.ts index ad05221248..3400f965b4 100644 --- a/packages/utils/src/asset.ts +++ b/packages/utils/src/asset.ts @@ -214,6 +214,8 @@ function parseAsset(scripts: any, styles: any, asset: Asset | undefined | null, } export class AssetLoader { + private stylePoints = new Map<string, StylePoint>(); + async load(asset: Asset) { const styles: any = {}; const scripts: any = {}; @@ -237,11 +239,9 @@ export class AssetLoader { await Promise.all( styleQueue.map(({ content, level, type, id }) => this.loadStyle(content, level!, type === AssetType.CSSUrl, id)), ); - await Promise.all(scriptQueue.map(({ content, type }) => this.loadScript(content, type === AssetType.JSUrl))); + await Promise.all(scriptQueue.map(({ content, type, scriptType }) => this.loadScript(content, type === AssetType.JSUrl, scriptType))); } - private stylePoints = new Map<string, StylePoint>(); - private loadStyle(content: string | undefined | null, level: AssetLevel, isUrl?: boolean, id?: string) { if (!content) { return; @@ -259,11 +259,11 @@ export class AssetLoader { return isUrl ? point.applyUrl(content) : point.applyText(content); } - private loadScript(content: string | undefined | null, isUrl?: boolean) { + private loadScript(content: string | undefined | null, isUrl?: boolean, scriptType?: string) { if (!content) { return; } - return isUrl ? load(content) : evaluate(content); + return isUrl ? load(content, scriptType) : evaluate(content, scriptType); } // todo 补充类型 diff --git a/packages/utils/src/script.ts b/packages/utils/src/script.ts index 7c772f03f9..25159b198c 100644 --- a/packages/utils/src/script.ts +++ b/packages/utils/src/script.ts @@ -1,14 +1,15 @@ import { createDefer } from './create-defer'; -export function evaluate(script: string) { +export function evaluate(script: string, scriptType?: string) { const scriptEl = document.createElement('script'); + scriptType && (scriptEl.type = scriptType); scriptEl.text = script; document.head.appendChild(scriptEl); document.head.removeChild(scriptEl); } -export function load(url: string) { - const node: any = document.createElement('script'); +export function load(url: string, scriptType?: string) { + const node = document.createElement('script'); // node.setAttribute('crossorigin', 'anonymous'); @@ -34,6 +35,8 @@ export function load(url: string) { // `async=false` is required to make sure all js resources execute sequentially. node.async = false; + scriptType && (node.type = scriptType); + document.head.appendChild(node); return i.promise(); From de8dab5cb38b6c1c248e35f9c445d24bdbf1babb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= <liujup@foxmail.com> Date: Thu, 9 Nov 2023 18:15:39 +0800 Subject: [PATCH 049/219] docs: update index.md --- docs/docs/article/index.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/docs/article/index.md b/docs/docs/article/index.md index 2f6f2cee3f..e62f8f9d87 100644 --- a/docs/docs/article/index.md +++ b/docs/docs/article/index.md @@ -1,4 +1,5 @@ # 官方文章 +- [2023/11/09 UIPaaS | 基于 LowCodeEngine 的低代码平台孵化器](https://mp.weixin.qq.com/s/mKuv3_Wvgt5T3AGErUGBQQ) - [2023/04/04 什么?低代码引擎可以开发应用了](https://mp.weixin.qq.com/s/dwi40gJjGBHW9MVpag5Oxg) - [2023/03/23 低代码引擎 LowCodeEngine 茁壮成长的一年](https://mp.weixin.qq.com/s/DDt4LQLFUBQ2-F5ehZGBKg) - [2023/02/21 基于 LowCodeEngine 的低代码组件体系的建设和实践](https://mp.weixin.qq.com/s/rnvbGHImGt6oJuX2wCtaqw) @@ -10,4 +11,4 @@ - [2022/04/07 磁贴布局在钉钉宜搭报表设计引擎中的实现](https://mp.weixin.qq.com/s/PSTut5ahAB8nlJ9kBpBaxw) - [2022/03/23 阿里低代码引擎 LowCodeEngine 正式开源!](https://mp.weixin.qq.com/s/T66LghtWLz2Oh048XqaniA) - [2022/01/10 阿里低代码引擎和生态建设实战及思考](https://mp.weixin.qq.com/s/MI6MrUKKydtnSdO4xq6jwA) -- [2021/04/14 2B 领域下的低代码探索之路](https://mp.weixin.qq.com/s/HAxrMHLT43dPH488RiEIdw) \ No newline at end of file +- [2021/04/14 2B 领域下的低代码探索之路](https://mp.weixin.qq.com/s/HAxrMHLT43dPH488RiEIdw) From 9f78f8c54a697a2d7b4102474fd2c0eb9c956e63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= <liujup@foxmail.com> Date: Thu, 9 Nov 2023 16:22:24 +0800 Subject: [PATCH 050/219] Update material.md --- docs/docs/api/material.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/docs/docs/api/material.md b/docs/docs/api/material.md index 2bf99577cb..8b1214476b 100644 --- a/docs/docs/api/material.md +++ b/docs/docs/api/material.md @@ -340,6 +340,31 @@ function addonCombine(metadata: TransformedComponentMetadata) { material.registerMetadataTransducer(addonCombine, 1, 'parse-func'); ``` +删除高级 Tab + +```typescript +import { material } from '@alilc/lowcode-engine'; +import { IPublicTypeFieldConfig } from '@alilc/lowcode-types'; + +material.registerMetadataTransducer((transducer) => { + const combined: IPublicTypeFieldConfig[] = []; + + transducer.configure.combined?.forEach(d => { + if (d.name !== '#advanced') { + combined.push(d); + } + }); + + return { + ...transducer, + configure: { + ...transducer.configure, + combined, + } + }; +}, 111, 'parse-func'); +``` + #### getRegisteredMetadataTransducers 获取所有物料元数据管道函数 From f5c874b4bfb3c8859750911609f0b6bb3670d8bf Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 9 Nov 2023 11:30:02 +0800 Subject: [PATCH 051/219] chore(ignitor): change build config --- packages/ignitor/build.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/ignitor/build.json b/packages/ignitor/build.json index a29eaf0266..218373247c 100644 --- a/packages/ignitor/build.json +++ b/packages/ignitor/build.json @@ -1,15 +1,15 @@ { "entry": { - "engine-core": "../engine/src/index.ts", - "react-simulator-renderer": "../react-simulator-renderer/src/index.ts", - "rax-simulator-renderer": "../rax-simulator-renderer/src/index.ts" + "AliLowCodeEngine": "../engine/src/index.ts", + "ReactSimulatorRenderer": "../react-simulator-renderer/src/index.ts", + "RaxSimulatorRenderer": "../rax-simulator-renderer/src/index.ts" }, "vendor": false, "devServer": { "liveReload": false, "hot": false }, - "library": "AliLowCodeEngine", + "library": "[name]", "publicPath": "/", "externals": { "react": "var window.React", From 3b14a79d1b474e538e8fae33ca38c9920ebebc31 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Fri, 10 Nov 2023 10:03:01 +0800 Subject: [PATCH 052/219] docs: publish docs 1.1.14 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index bdc734c71e..7479c7c84e 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.1.13", + "version": "1.1.14", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 6320867cada5e0b851a2836aeadbb3b54f8f7f6d Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 10 Nov 2023 14:20:24 +0800 Subject: [PATCH 053/219] docs: update Node to IPublicModelNode --- docs/docs/api/configOptions.md | 2 +- docs/docs/api/model/dragon.md | 2 +- docs/docs/api/model/modal-nodes-manager.md | 4 ++-- docs/docs/api/model/node.md | 2 +- docs/docs/guide/expand/editor/pluginContextMenu.md | 6 +++--- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/docs/api/configOptions.md b/docs/docs/api/configOptions.md index 467655f68c..aaea28261d 100644 --- a/docs/docs/api/configOptions.md +++ b/docs/docs/api/configOptions.md @@ -113,7 +113,7 @@ config.set('enableCondition', false) 类型定义 ```typescript - focusNodeSelector?: (rootNode: Node) => Node; + focusNodeSelector?: (rootNode: IPublicModelNode) => Node; ``` #### supportVariableGlobally - 全局变量配置 diff --git a/docs/docs/api/model/dragon.md b/docs/docs/api/model/dragon.md index 995fd1b1f4..c6feca4329 100644 --- a/docs/docs/api/model/dragon.md +++ b/docs/docs/api/model/dragon.md @@ -101,7 +101,7 @@ from(shell: Element, boost: (e: MouseEvent) => IPublicTypeDragNodeDataObject | n * @param dragObject 拖拽对象 * @param boostEvent 拖拽初始时事件 */ -boost(dragObject: IPublicTypeDragObject, boostEvent: MouseEvent | DragEvent, fromRglNode?: Node | IPublicModelNode): void; +boost(dragObject: IPublicTypeDragObject, boostEvent: MouseEvent | DragEvent, fromRglNode?: IPublicModelNode): void; ``` ### addSensor diff --git a/docs/docs/api/model/modal-nodes-manager.md b/docs/docs/api/model/modal-nodes-manager.md index fbab6a83a5..fead53f0a1 100644 --- a/docs/docs/api/model/modal-nodes-manager.md +++ b/docs/docs/api/model/modal-nodes-manager.md @@ -71,7 +71,7 @@ hideModalNodes(): void; /** * 设置指定节点为可见态 * set specific model node as visible - * @param node Node + * @param node IPublicModelNode */ setVisible(node: IPublicModelNode): void; ``` @@ -86,7 +86,7 @@ setVisible(node: IPublicModelNode): void; /** * 设置指定节点为不可见态 * set specific model node as invisible - * @param node Node + * @param node IPublicModelNode */ setInvisible(node: IPublicModelNode): void; ``` diff --git a/docs/docs/api/model/node.md b/docs/docs/api/model/node.md index 697eefd088..43de96a33d 100644 --- a/docs/docs/api/model/node.md +++ b/docs/docs/api/model/node.md @@ -673,6 +673,6 @@ getRGL(): { isRGLContainerNode: boolean; isRGLNode: boolean; isRGL: boolean; - rglNode: Node | null; + rglNode: IPublicModelNode | null; } ``` \ No newline at end of file diff --git a/docs/docs/guide/expand/editor/pluginContextMenu.md b/docs/docs/guide/expand/editor/pluginContextMenu.md index cd293b73e7..962c913e7e 100644 --- a/docs/docs/guide/expand/editor/pluginContextMenu.md +++ b/docs/docs/guide/expand/editor/pluginContextMenu.md @@ -12,7 +12,7 @@ sidebar_position: 6 ```typescript import { plugins } from '@alilc/lowcode-engine'; -import { IPublicModelPluginContext } from '@alilc/lowcode-types'; +import { IPublicModelPluginContext, IPublicModelNode } from '@alilc/lowcode-types'; import { Icon, Message } from '@alifd/next'; const addHelloAction = (ctx: IPublicModelPluginContext) => { @@ -23,11 +23,11 @@ const addHelloAction = (ctx: IPublicModelPluginContext) => { content: { icon: <Icon type="atm" />, title: 'hello', - action(node: Node) { + action(node: IPublicModelNode) { Message.show('Welcome to Low-Code engine'); }, }, - condition: (node: Node) => { + condition: (node: IPublicModelNode) => { return node.componentMeta.componentName === 'NextTable'; }, important: true, From d64c7d56dfc5ac67be56039a124ae897555569de Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Mon, 13 Nov 2023 12:41:45 +0800 Subject: [PATCH 054/219] chore(release): publish 1.2.2 --- lerna.json | 2 +- packages/designer/package.json | 8 ++++---- packages/editor-core/package.json | 6 +++--- packages/editor-skeleton/package.json | 10 +++++----- packages/engine/package.json | 18 +++++++++--------- packages/ignitor/package.json | 2 +- packages/plugin-designer/package.json | 8 ++++---- packages/plugin-outline-pane/package.json | 6 +++--- packages/rax-renderer/package.json | 6 +++--- packages/rax-simulator-renderer/package.json | 10 +++++----- packages/react-renderer/package.json | 4 ++-- packages/react-simulator-renderer/package.json | 10 +++++----- packages/renderer-core/package.json | 8 ++++---- packages/shell/package.json | 14 +++++++------- packages/types/package.json | 2 +- packages/utils/package.json | 4 ++-- packages/workspace/package.json | 12 ++++++------ 17 files changed, 65 insertions(+), 65 deletions(-) diff --git a/lerna.json b/lerna.json index 8201f484d6..34be89faa8 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "lerna": "4.0.0", - "version": "1.2.1", + "version": "1.2.2", "npmClient": "yarn", "useWorkspaces": true, "packages": [ diff --git a/packages/designer/package.json b/packages/designer/package.json index 2f57c80c38..69a402ed22 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-designer", - "version": "1.2.1", + "version": "1.2.2", "description": "Designer for Ali LowCode Engine", "main": "lib/index.js", "module": "es/index.js", @@ -15,9 +15,9 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-editor-core": "1.2.1", - "@alilc/lowcode-types": "1.2.1", - "@alilc/lowcode-utils": "1.2.1", + "@alilc/lowcode-editor-core": "1.2.2", + "@alilc/lowcode-types": "1.2.2", + "@alilc/lowcode-utils": "1.2.2", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/editor-core/package.json b/packages/editor-core/package.json index 060f986ed3..de9d30bc8b 100644 --- a/packages/editor-core/package.json +++ b/packages/editor-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-core", - "version": "1.2.1", + "version": "1.2.2", "description": "Core Api for Ali lowCode engine", "license": "MIT", "main": "lib/index.js", @@ -14,8 +14,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.2.1", - "@alilc/lowcode-utils": "1.2.1", + "@alilc/lowcode-types": "1.2.2", + "@alilc/lowcode-utils": "1.2.2", "classnames": "^2.2.6", "debug": "^4.1.1", "intl-messageformat": "^9.3.1", diff --git a/packages/editor-skeleton/package.json b/packages/editor-skeleton/package.json index 0f55e637db..fe2d0d43ff 100644 --- a/packages/editor-skeleton/package.json +++ b/packages/editor-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-skeleton", - "version": "1.2.1", + "version": "1.2.2", "description": "alibaba lowcode editor skeleton", "main": "lib/index.js", "module": "es/index.js", @@ -19,10 +19,10 @@ ], "dependencies": { "@alifd/next": "^1.20.12", - "@alilc/lowcode-designer": "1.2.1", - "@alilc/lowcode-editor-core": "1.2.1", - "@alilc/lowcode-types": "1.2.1", - "@alilc/lowcode-utils": "1.2.1", + "@alilc/lowcode-designer": "1.2.2", + "@alilc/lowcode-editor-core": "1.2.2", + "@alilc/lowcode-types": "1.2.2", + "@alilc/lowcode-utils": "1.2.2", "classnames": "^2.2.6", "react": "^16.8.1", "react-dom": "^16.8.1" diff --git a/packages/engine/package.json b/packages/engine/package.json index 29ba8c36f6..3ea47f79da 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine", - "version": "1.2.1", + "version": "1.2.2", "description": "An enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系", "main": "lib/engine-core.js", "module": "es/engine-core.js", @@ -19,15 +19,15 @@ "license": "MIT", "dependencies": { "@alifd/next": "^1.19.12", - "@alilc/lowcode-designer": "1.2.1", - "@alilc/lowcode-editor-core": "1.2.1", - "@alilc/lowcode-editor-skeleton": "1.2.1", + "@alilc/lowcode-designer": "1.2.2", + "@alilc/lowcode-editor-core": "1.2.2", + "@alilc/lowcode-editor-skeleton": "1.2.2", "@alilc/lowcode-engine-ext": "^1.0.0", - "@alilc/lowcode-plugin-designer": "1.2.1", - "@alilc/lowcode-plugin-outline-pane": "1.2.1", - "@alilc/lowcode-shell": "1.2.1", - "@alilc/lowcode-utils": "1.2.1", - "@alilc/lowcode-workspace": "1.2.1", + "@alilc/lowcode-plugin-designer": "1.2.2", + "@alilc/lowcode-plugin-outline-pane": "1.2.2", + "@alilc/lowcode-shell": "1.2.2", + "@alilc/lowcode-utils": "1.2.2", + "@alilc/lowcode-workspace": "1.2.2", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/ignitor/package.json b/packages/ignitor/package.json index cdf2928b56..d737a7c868 100644 --- a/packages/ignitor/package.json +++ b/packages/ignitor/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-ignitor", - "version": "1.2.1", + "version": "1.2.2", "description": "点火器,bootstrap lce project", "main": "lib/index.js", "private": true, diff --git a/packages/plugin-designer/package.json b/packages/plugin-designer/package.json index 9b64b0709f..fe653568bb 100644 --- a/packages/plugin-designer/package.json +++ b/packages/plugin-designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-designer", - "version": "1.2.1", + "version": "1.2.2", "description": "alibaba lowcode editor designer plugin", "files": [ "es", @@ -18,9 +18,9 @@ ], "author": "xiayang.xy", "dependencies": { - "@alilc/lowcode-designer": "1.2.1", - "@alilc/lowcode-editor-core": "1.2.1", - "@alilc/lowcode-utils": "1.2.1", + "@alilc/lowcode-designer": "1.2.2", + "@alilc/lowcode-editor-core": "1.2.2", + "@alilc/lowcode-utils": "1.2.2", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/plugin-outline-pane/package.json b/packages/plugin-outline-pane/package.json index 8295094fe0..2540ca5ad4 100644 --- a/packages/plugin-outline-pane/package.json +++ b/packages/plugin-outline-pane/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-outline-pane", - "version": "1.2.1", + "version": "1.2.2", "description": "Outline pane for Ali lowCode engine", "files": [ "es", @@ -13,8 +13,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.2.1", - "@alilc/lowcode-utils": "1.2.1", + "@alilc/lowcode-types": "1.2.2", + "@alilc/lowcode-utils": "1.2.2", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/rax-renderer/package.json b/packages/rax-renderer/package.json index ed7434b942..60ea0c6981 100644 --- a/packages/rax-renderer/package.json +++ b/packages/rax-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-renderer", - "version": "1.2.1", + "version": "1.2.2", "description": "Rax renderer for Ali lowCode engine", "main": "lib/index.js", "module": "es/index.js", @@ -30,8 +30,8 @@ "build": "build-scripts build" }, "dependencies": { - "@alilc/lowcode-renderer-core": "1.2.1", - "@alilc/lowcode-utils": "1.2.1", + "@alilc/lowcode-renderer-core": "1.2.2", + "@alilc/lowcode-utils": "1.2.2", "rax-find-dom-node": "^1.0.1" }, "devDependencies": { diff --git a/packages/rax-simulator-renderer/package.json b/packages/rax-simulator-renderer/package.json index 383cc29895..520ff32c89 100644 --- a/packages/rax-simulator-renderer/package.json +++ b/packages/rax-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-simulator-renderer", - "version": "1.2.1", + "version": "1.2.2", "description": "rax simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -13,10 +13,10 @@ "build:umd": "build-scripts build --config build.umd.json" }, "dependencies": { - "@alilc/lowcode-designer": "1.2.1", - "@alilc/lowcode-rax-renderer": "1.2.1", - "@alilc/lowcode-types": "1.2.1", - "@alilc/lowcode-utils": "1.2.1", + "@alilc/lowcode-designer": "1.2.2", + "@alilc/lowcode-rax-renderer": "1.2.2", + "@alilc/lowcode-types": "1.2.2", + "@alilc/lowcode-utils": "1.2.2", "classnames": "^2.2.6", "driver-universal": "^3.1.3", "history": "^5.0.0", diff --git a/packages/react-renderer/package.json b/packages/react-renderer/package.json index 142e90ebb6..a35039fc3c 100644 --- a/packages/react-renderer/package.json +++ b/packages/react-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-renderer", - "version": "1.2.1", + "version": "1.2.2", "description": "react renderer for ali lowcode engine", "main": "lib/index.js", "module": "es/index.js", @@ -22,7 +22,7 @@ ], "dependencies": { "@alifd/next": "^1.21.16", - "@alilc/lowcode-renderer-core": "1.2.1" + "@alilc/lowcode-renderer-core": "1.2.2" }, "devDependencies": { "@alib/build-scripts": "^0.1.18", diff --git a/packages/react-simulator-renderer/package.json b/packages/react-simulator-renderer/package.json index 18b57e28fe..413b1825f8 100644 --- a/packages/react-simulator-renderer/package.json +++ b/packages/react-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-simulator-renderer", - "version": "1.2.1", + "version": "1.2.2", "description": "react simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -17,10 +17,10 @@ "test:cov": "build-scripts test --config build.test.json --jest-coverage" }, "dependencies": { - "@alilc/lowcode-designer": "1.2.1", - "@alilc/lowcode-react-renderer": "1.2.1", - "@alilc/lowcode-types": "1.2.1", - "@alilc/lowcode-utils": "1.2.1", + "@alilc/lowcode-designer": "1.2.2", + "@alilc/lowcode-react-renderer": "1.2.2", + "@alilc/lowcode-types": "1.2.2", + "@alilc/lowcode-utils": "1.2.2", "classnames": "^2.2.6", "mobx": "^6.3.0", "mobx-react": "^7.2.0", diff --git a/packages/renderer-core/package.json b/packages/renderer-core/package.json index 3d4e3c7e09..3b96ef40b3 100644 --- a/packages/renderer-core/package.json +++ b/packages/renderer-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-renderer-core", - "version": "1.2.1", + "version": "1.2.2", "description": "renderer core", "license": "MIT", "main": "lib/index.js", @@ -16,8 +16,8 @@ }, "dependencies": { "@alilc/lowcode-datasource-engine": "^1.0.0", - "@alilc/lowcode-types": "1.2.1", - "@alilc/lowcode-utils": "1.2.1", + "@alilc/lowcode-types": "1.2.2", + "@alilc/lowcode-utils": "1.2.2", "classnames": "^2.2.6", "debug": "^4.1.1", "fetch-jsonp": "^1.1.3", @@ -32,7 +32,7 @@ "devDependencies": { "@alib/build-scripts": "^0.1.18", "@alifd/next": "^1.26.0", - "@alilc/lowcode-designer": "1.2.1", + "@alilc/lowcode-designer": "1.2.2", "@babel/plugin-transform-typescript": "^7.16.8", "@testing-library/react": "^11.2.2", "@types/classnames": "^2.2.11", diff --git a/packages/shell/package.json b/packages/shell/package.json index 36ea05d7b1..7e20192352 100644 --- a/packages/shell/package.json +++ b/packages/shell/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-shell", - "version": "1.2.1", + "version": "1.2.2", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -13,12 +13,12 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.2.1", - "@alilc/lowcode-editor-core": "1.2.1", - "@alilc/lowcode-editor-skeleton": "1.2.1", - "@alilc/lowcode-types": "1.2.1", - "@alilc/lowcode-utils": "1.2.1", - "@alilc/lowcode-workspace": "1.2.1", + "@alilc/lowcode-designer": "1.2.2", + "@alilc/lowcode-editor-core": "1.2.2", + "@alilc/lowcode-editor-skeleton": "1.2.2", + "@alilc/lowcode-types": "1.2.2", + "@alilc/lowcode-utils": "1.2.2", + "@alilc/lowcode-workspace": "1.2.2", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", diff --git a/packages/types/package.json b/packages/types/package.json index 2d66d2f621..c4fa290036 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-types", - "version": "1.2.1", + "version": "1.2.2", "description": "Types for Ali lowCode engine", "files": [ "es", diff --git a/packages/utils/package.json b/packages/utils/package.json index c2433f1521..fab7828f13 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-utils", - "version": "1.2.1", + "version": "1.2.2", "description": "Utils for Ali lowCode engine", "files": [ "lib", @@ -14,7 +14,7 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.2.1", + "@alilc/lowcode-types": "1.2.2", "lodash": "^4.17.21", "mobx": "^6.3.0", "react": "^16" diff --git a/packages/workspace/package.json b/packages/workspace/package.json index a5d7d4ceae..4724323797 100644 --- a/packages/workspace/package.json +++ b/packages/workspace/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-workspace", - "version": "1.2.1", + "version": "1.2.2", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -15,11 +15,11 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.2.1", - "@alilc/lowcode-editor-core": "1.2.1", - "@alilc/lowcode-editor-skeleton": "1.2.1", - "@alilc/lowcode-types": "1.2.1", - "@alilc/lowcode-utils": "1.2.1", + "@alilc/lowcode-designer": "1.2.2", + "@alilc/lowcode-editor-core": "1.2.2", + "@alilc/lowcode-editor-skeleton": "1.2.2", + "@alilc/lowcode-types": "1.2.2", + "@alilc/lowcode-utils": "1.2.2", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", From 04adda02fb415e2f56e6ee3e7f20652c2de20668 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 13 Nov 2023 12:30:47 +0800 Subject: [PATCH 055/219] =?UTF-8?q?docs:=20add=20faq-Slot=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E6=B8=B2=E6=9F=93=E6=8A=A5=E9=94=99=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/docs/faq/faq023.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 docs/docs/faq/faq023.md diff --git a/docs/docs/faq/faq023.md b/docs/docs/faq/faq023.md new file mode 100644 index 0000000000..e03f7118e0 --- /dev/null +++ b/docs/docs/faq/faq023.md @@ -0,0 +1,31 @@ +--- +title: Slot组件渲染报错问题 +sidebar_position: 23 +tags: [FAQ] +--- + +## 问题描述 +在低代码引擎的页面渲染过程中,可能会遇到一个关于Slot组件的报错,提示“Slot找不到”。实际上,在渲染态时不应使用Slot组件。 + +## 问题原因 +低代码引擎渲染分为两个状态:设计态和渲染态。 +- **设计态**:为了帮助插槽进行可视化设计,引入了Slot组件。 +- **渲染态**:在此状态下,不需要使用Slot组件。 + +这个问题通常是因为在渲染态错误地使用了设计态的schema。 + +## 解决方案 +1. **区分设计态和渲染态**:通过`project.exportSchema(TransformStage.Save)`的参数来区分。 + - `TransformStage.Save`代表渲染态的schema,其中不包含Slot组件。 + - 【默认值】`TransformStage.Render`代表设计态的schema,其中包含Slot组件。 +2. **使用正确的API和参数**:确保在渲染态使用正确的schema,避免引用设计态的Slot组件。 +3. **处理脏数据问题**:如果问题是由脏数据导致,清除数据并重新拖拽组件以恢复正常。 + +## 注意事项 +- 确保在代码和配置中正确区分设计态和渲染态。 +- 如果遇到持续的问题,检查是否有脏数据或配置错误,并进行相应的清理和调整。 + +## 相关链接 +- Issue链接:[Issue #1798](https://github.com/alibaba/lowcode-engine/issues/1798) + +--- From 938c71fb462b37fb154e1b8fdfaa0319d4f0f075 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Mon, 13 Nov 2023 12:57:02 +0800 Subject: [PATCH 056/219] chore(docs): publish docs 1.1.15 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 7479c7c84e..27d1a17d04 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.1.14", + "version": "1.1.15", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 621245393f5ca405d86c90501e51288f2f324d5c Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 13 Nov 2023 12:25:50 +0800 Subject: [PATCH 057/219] test(utils): add ut to package/utils --- packages/utils/jest.config.js | 1 + packages/utils/jest.setup.js | 1 + packages/utils/package.json | 7 +- .../check-types/is-action-content-object.ts | 3 +- .../utils/src/check-types/is-custom-view.ts | 6 +- .../src/check-types/is-drag-any-object.ts | 6 +- .../check-types/is-drag-node-data-object.ts | 6 +- .../src/check-types/is-drag-node-object.ts | 6 +- .../src/check-types/is-dynamic-setter.ts | 7 +- packages/utils/src/check-types/is-function.ts | 3 + .../utils/src/check-types/is-i18n-data.ts | 11 +- .../utils/src/check-types/is-isfunction.ts | 24 +- packages/utils/src/check-types/is-jsblock.ts | 9 +- .../utils/src/check-types/is-jsexpression.ts | 6 +- packages/utils/src/check-types/is-jsslot.ts | 6 +- .../is-location-children-detail.ts | 6 +- .../utils/src/check-types/is-location-data.ts | 6 +- .../check-types/is-lowcode-project-schema.ts | 15 +- .../utils/src/check-types/is-node-schema.ts | 6 +- packages/utils/src/check-types/is-node.ts | 6 +- packages/utils/src/check-types/is-object.ts | 3 + .../check-types/is-procode-component-type.ts | 6 +- .../src/check-types/is-project-schema.ts | 8 +- .../utils/src/check-types/is-setter-config.ts | 7 +- .../utils/src/check-types/is-setting-field.ts | 9 +- .../utils/src/clone-enumerable-property.ts | 4 +- packages/utils/src/is-object.ts | 2 +- packages/utils/src/is-react.ts | 38 +- packages/utils/src/logger.ts | 4 +- packages/utils/src/misc.ts | 15 +- packages/utils/src/navtive-selection.ts | 3 +- packages/utils/src/script.ts | 5 +- packages/utils/src/svg-icon.tsx | 2 +- .../src/__snapshots__/is-react.test.tsx.snap | 10 + .../build-components/buildComponents.test.ts | 342 ---------- .../build-components/buildComponents.test.tsx | 616 ++++++++++++++++++ .../is-action-content-object.test.ts | 20 + .../src/check-types/is-custom-view.test.tsx | 26 + .../test/src/check-types/is-dom-text.test.ts | 13 + .../check-types/is-drag-any-object.test.ts | 32 + .../is-drag-node-data-object.test.ts | 29 + .../check-types/is-drag-node-object.test.ts | 36 + .../src/check-types/is-dynamic-setter.test.ts | 28 + .../test/src/check-types/is-i18n-data.test.ts | 27 + .../src/check-types/is-isfunction.test.ts | 61 ++ .../test/src/check-types/is-jsblock.test.ts | 22 + .../src/check-types/is-jsexpression.test.ts | 39 ++ .../test/src/check-types/is-jsslot.test.ts | 37 ++ .../is-location-children-detail.test.ts | 27 + .../src/check-types/is-location-data.test.ts | 44 ++ .../is-lowcode-component-type.test.ts | 21 + .../is-lowcode-project-schema.test.ts | 42 ++ .../src/check-types/is-node-schema.test.ts | 43 ++ .../test/src/check-types/is-node.test.ts | 19 + .../is-procode-component-type.test.ts | 13 + .../src/check-types/is-project-schema.test.ts | 28 + .../src/check-types/is-setter-config.test.ts | 26 + .../src/check-types/is-setting-field.test.ts | 18 + .../src/check-types/is-title-config.test.ts | 18 + packages/utils/test/src/clone-deep.test.ts | 30 + .../src/clone-enumerable-property.test.ts | 30 + .../utils/test/src/create-content.test.tsx | 38 ++ packages/utils/test/src/create-defer.test.ts | 16 + packages/utils/test/src/is-object.test.ts | 45 ++ packages/utils/test/src/is-react.test.ts | 38 -- packages/utils/test/src/is-react.test.tsx | 316 +++++++++ packages/utils/test/src/is-shaken.test.ts | 45 ++ packages/utils/test/src/misc.test.ts | 319 ++++++++- .../utils/test/src/navtive-selection.test.ts | 18 + packages/utils/test/src/schema.test.ts | 130 +++- packages/utils/test/src/script.test.ts | 47 ++ packages/utils/test/src/svg-icon.test.tsx | 35 + .../test/src/transaction-manager.test.ts | 58 ++ packages/utils/test/src/unique-id.test.ts | 11 + 74 files changed, 2621 insertions(+), 439 deletions(-) create mode 100644 packages/utils/jest.setup.js create mode 100644 packages/utils/src/check-types/is-function.ts create mode 100644 packages/utils/src/check-types/is-object.ts create mode 100644 packages/utils/test/src/__snapshots__/is-react.test.tsx.snap delete mode 100644 packages/utils/test/src/build-components/buildComponents.test.ts create mode 100644 packages/utils/test/src/build-components/buildComponents.test.tsx create mode 100644 packages/utils/test/src/check-types/is-action-content-object.test.ts create mode 100644 packages/utils/test/src/check-types/is-custom-view.test.tsx create mode 100644 packages/utils/test/src/check-types/is-dom-text.test.ts create mode 100644 packages/utils/test/src/check-types/is-drag-any-object.test.ts create mode 100644 packages/utils/test/src/check-types/is-drag-node-data-object.test.ts create mode 100644 packages/utils/test/src/check-types/is-drag-node-object.test.ts create mode 100644 packages/utils/test/src/check-types/is-dynamic-setter.test.ts create mode 100644 packages/utils/test/src/check-types/is-i18n-data.test.ts create mode 100644 packages/utils/test/src/check-types/is-isfunction.test.ts create mode 100644 packages/utils/test/src/check-types/is-jsblock.test.ts create mode 100644 packages/utils/test/src/check-types/is-jsexpression.test.ts create mode 100644 packages/utils/test/src/check-types/is-jsslot.test.ts create mode 100644 packages/utils/test/src/check-types/is-location-children-detail.test.ts create mode 100644 packages/utils/test/src/check-types/is-location-data.test.ts create mode 100644 packages/utils/test/src/check-types/is-lowcode-component-type.test.ts create mode 100644 packages/utils/test/src/check-types/is-lowcode-project-schema.test.ts create mode 100644 packages/utils/test/src/check-types/is-node-schema.test.ts create mode 100644 packages/utils/test/src/check-types/is-node.test.ts create mode 100644 packages/utils/test/src/check-types/is-procode-component-type.test.ts create mode 100644 packages/utils/test/src/check-types/is-project-schema.test.ts create mode 100644 packages/utils/test/src/check-types/is-setter-config.test.ts create mode 100644 packages/utils/test/src/check-types/is-setting-field.test.ts create mode 100644 packages/utils/test/src/check-types/is-title-config.test.ts create mode 100644 packages/utils/test/src/clone-deep.test.ts create mode 100644 packages/utils/test/src/clone-enumerable-property.test.ts create mode 100644 packages/utils/test/src/create-content.test.tsx create mode 100644 packages/utils/test/src/create-defer.test.ts create mode 100644 packages/utils/test/src/is-object.test.ts delete mode 100644 packages/utils/test/src/is-react.test.ts create mode 100644 packages/utils/test/src/is-react.test.tsx create mode 100644 packages/utils/test/src/is-shaken.test.ts create mode 100644 packages/utils/test/src/navtive-selection.test.ts create mode 100644 packages/utils/test/src/script.test.ts create mode 100644 packages/utils/test/src/svg-icon.test.tsx create mode 100644 packages/utils/test/src/transaction-manager.test.ts create mode 100644 packages/utils/test/src/unique-id.test.ts diff --git a/packages/utils/jest.config.js b/packages/utils/jest.config.js index 328ea622eb..0631fa00c9 100644 --- a/packages/utils/jest.config.js +++ b/packages/utils/jest.config.js @@ -11,6 +11,7 @@ const jestConfig = { '!**/node_modules/**', '!**/vendor/**', ], + setupFilesAfterEnv: ['./jest.setup.js'], }; // 只对本仓库内的 pkg 做 mapping diff --git a/packages/utils/jest.setup.js b/packages/utils/jest.setup.js new file mode 100644 index 0000000000..7b0828bfa8 --- /dev/null +++ b/packages/utils/jest.setup.js @@ -0,0 +1 @@ +import '@testing-library/jest-dom'; diff --git a/packages/utils/package.json b/packages/utils/package.json index fab7828f13..af76e9e2f6 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -9,7 +9,7 @@ "main": "lib/index.js", "module": "es/index.js", "scripts": { - "test": "build-scripts test --config build.test.json", + "test": "build-scripts test --config build.test.json --jest-coverage", "build": "build-scripts build" }, "dependencies": { @@ -21,8 +21,11 @@ }, "devDependencies": { "@alib/build-scripts": "^0.1.18", + "@testing-library/jest-dom": "^6.1.4", + "@testing-library/react": "^11.2.7", "@types/node": "^13.7.1", - "@types/react": "^16" + "@types/react": "^16", + "react-dom": "^16.14.0" }, "publishConfig": { "access": "public", diff --git a/packages/utils/src/check-types/is-action-content-object.ts b/packages/utils/src/check-types/is-action-content-object.ts index 4e9a6545a4..8fe31b5bd7 100644 --- a/packages/utils/src/check-types/is-action-content-object.ts +++ b/packages/utils/src/check-types/is-action-content-object.ts @@ -1,5 +1,6 @@ import { IPublicTypeActionContentObject } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; export function isActionContentObject(obj: any): obj is IPublicTypeActionContentObject { - return obj && typeof obj === 'object'; + return isObject(obj); } diff --git a/packages/utils/src/check-types/is-custom-view.ts b/packages/utils/src/check-types/is-custom-view.ts index 89ea9f10e4..4cf921d9c5 100644 --- a/packages/utils/src/check-types/is-custom-view.ts +++ b/packages/utils/src/check-types/is-custom-view.ts @@ -2,7 +2,9 @@ import { isValidElement } from 'react'; import { isReactComponent } from '../is-react'; import { IPublicTypeCustomView } from '@alilc/lowcode-types'; - export function isCustomView(obj: any): obj is IPublicTypeCustomView { - return obj && (isValidElement(obj) || isReactComponent(obj)); + if (!obj) { + return false; + } + return isValidElement(obj) || isReactComponent(obj); } diff --git a/packages/utils/src/check-types/is-drag-any-object.ts b/packages/utils/src/check-types/is-drag-any-object.ts index 34f140f4a5..8711b4e333 100644 --- a/packages/utils/src/check-types/is-drag-any-object.ts +++ b/packages/utils/src/check-types/is-drag-any-object.ts @@ -1,5 +1,9 @@ import { IPublicEnumDragObjectType } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; export function isDragAnyObject(obj: any): boolean { - return obj && obj.type !== IPublicEnumDragObjectType.NodeData && obj.type !== IPublicEnumDragObjectType.Node; + if (!isObject(obj)) { + return false; + } + return obj.type !== IPublicEnumDragObjectType.NodeData && obj.type !== IPublicEnumDragObjectType.Node; } \ No newline at end of file diff --git a/packages/utils/src/check-types/is-drag-node-data-object.ts b/packages/utils/src/check-types/is-drag-node-data-object.ts index 4b08f67fa6..aa62f5b1c9 100644 --- a/packages/utils/src/check-types/is-drag-node-data-object.ts +++ b/packages/utils/src/check-types/is-drag-node-data-object.ts @@ -1,5 +1,9 @@ import { IPublicEnumDragObjectType, IPublicTypeDragNodeDataObject } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; export function isDragNodeDataObject(obj: any): obj is IPublicTypeDragNodeDataObject { - return obj && obj.type === IPublicEnumDragObjectType.NodeData; + if (!isObject(obj)) { + return false; + } + return obj.type === IPublicEnumDragObjectType.NodeData; } \ No newline at end of file diff --git a/packages/utils/src/check-types/is-drag-node-object.ts b/packages/utils/src/check-types/is-drag-node-object.ts index 1b6c131e93..3a29ec967f 100644 --- a/packages/utils/src/check-types/is-drag-node-object.ts +++ b/packages/utils/src/check-types/is-drag-node-object.ts @@ -1,5 +1,9 @@ import { IPublicEnumDragObjectType, IPublicModelNode, IPublicTypeDragNodeObject } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; export function isDragNodeObject<Node = IPublicModelNode>(obj: any): obj is IPublicTypeDragNodeObject<Node> { - return obj && obj.type === IPublicEnumDragObjectType.Node; + if (!isObject(obj)) { + return false; + } + return obj.type === IPublicEnumDragObjectType.Node; } \ No newline at end of file diff --git a/packages/utils/src/check-types/is-dynamic-setter.ts b/packages/utils/src/check-types/is-dynamic-setter.ts index 43a8cb8beb..35f8ff3892 100644 --- a/packages/utils/src/check-types/is-dynamic-setter.ts +++ b/packages/utils/src/check-types/is-dynamic-setter.ts @@ -1,7 +1,10 @@ +import { isFunction } from '../is-function'; import { isReactClass } from '../is-react'; import { IPublicTypeDynamicSetter } from '@alilc/lowcode-types'; - export function isDynamicSetter(obj: any): obj is IPublicTypeDynamicSetter { - return obj && typeof obj === 'function' && !isReactClass(obj); + if (!isFunction(obj)) { + return false; + } + return !isReactClass(obj); } diff --git a/packages/utils/src/check-types/is-function.ts b/packages/utils/src/check-types/is-function.ts new file mode 100644 index 0000000000..d7d3b4c27d --- /dev/null +++ b/packages/utils/src/check-types/is-function.ts @@ -0,0 +1,3 @@ +export function isFunction(obj: any): obj is Function { + return obj && typeof obj === 'function'; +} \ No newline at end of file diff --git a/packages/utils/src/check-types/is-i18n-data.ts b/packages/utils/src/check-types/is-i18n-data.ts index f4a7b6f7aa..793295d240 100644 --- a/packages/utils/src/check-types/is-i18n-data.ts +++ b/packages/utils/src/check-types/is-i18n-data.ts @@ -1,8 +1,9 @@ - -// type checks - -import { IPublicTypeI18nData } from "@alilc/lowcode-types"; +import { IPublicTypeI18nData } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; export function isI18nData(obj: any): obj is IPublicTypeI18nData { - return obj && obj.type === 'i18n'; + if (!isObject(obj)) { + return false; + } + return obj.type === 'i18n'; } diff --git a/packages/utils/src/check-types/is-isfunction.ts b/packages/utils/src/check-types/is-isfunction.ts index a6d5da9008..64b8676637 100644 --- a/packages/utils/src/check-types/is-isfunction.ts +++ b/packages/utils/src/check-types/is-isfunction.ts @@ -1,10 +1,26 @@ +import { IPublicTypeJSFunction } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; + +interface InnerJsFunction { + type: 'JSExpression'; + source: string; + value: string; + extType: 'function'; +} + /** * 内部版本 的 { type: 'JSExpression', source: '', value: '', extType: 'function' } 能力上等同于 JSFunction */ -export function isInnerJsFunction(data: any) { - return data && data.type === 'JSExpression' && data.extType === 'function'; +export function isInnerJsFunction(data: any): data is InnerJsFunction { + if (!isObject(data)) { + return false; + } + return data.type === 'JSExpression' && data.extType === 'function'; } -export function isJSFunction(data: any): boolean { - return typeof data === 'object' && data && data.type === 'JSFunction' || isInnerJsFunction(data); +export function isJSFunction(data: any): data is IPublicTypeJSFunction { + if (!isObject(data)) { + return false; + } + return data.type === 'JSFunction' || isInnerJsFunction(data); } diff --git a/packages/utils/src/check-types/is-jsblock.ts b/packages/utils/src/check-types/is-jsblock.ts index 4c3b28f525..858f5c09cd 100644 --- a/packages/utils/src/check-types/is-jsblock.ts +++ b/packages/utils/src/check-types/is-jsblock.ts @@ -1,4 +1,9 @@ +import { IPublicTypeJSBlock } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; -export function isJSBlock(data: any): boolean { - return data && data.type === 'JSBlock'; +export function isJSBlock(data: any): data is IPublicTypeJSBlock { + if (!isObject(data)) { + return false; + } + return data.type === 'JSBlock'; } diff --git a/packages/utils/src/check-types/is-jsexpression.ts b/packages/utils/src/check-types/is-jsexpression.ts index 949d0f00da..16b8f4ac2a 100644 --- a/packages/utils/src/check-types/is-jsexpression.ts +++ b/packages/utils/src/check-types/is-jsexpression.ts @@ -1,4 +1,5 @@ import { IPublicTypeJSExpression } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; /** * 为了避免把 { type: 'JSExpression', extType: 'function' } 误判为表达式,故增加如下逻辑。 @@ -11,5 +12,8 @@ import { IPublicTypeJSExpression } from '@alilc/lowcode-types'; * @returns */ export function isJSExpression(data: any): data is IPublicTypeJSExpression { - return data && data.type === 'JSExpression' && data.extType !== 'function'; + if (!isObject(data)) { + return false; + } + return data.type === 'JSExpression' && data.extType !== 'function'; } diff --git a/packages/utils/src/check-types/is-jsslot.ts b/packages/utils/src/check-types/is-jsslot.ts index 1a8f09def5..1fb1d819d7 100644 --- a/packages/utils/src/check-types/is-jsslot.ts +++ b/packages/utils/src/check-types/is-jsslot.ts @@ -1,5 +1,9 @@ import { IPublicTypeJSSlot } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; export function isJSSlot(data: any): data is IPublicTypeJSSlot { - return data && data.type === 'JSSlot'; + if (!isObject(data)) { + return false; + } + return data.type === 'JSSlot'; } diff --git a/packages/utils/src/check-types/is-location-children-detail.ts b/packages/utils/src/check-types/is-location-children-detail.ts index c6d2819d30..cc093c4e4a 100644 --- a/packages/utils/src/check-types/is-location-children-detail.ts +++ b/packages/utils/src/check-types/is-location-children-detail.ts @@ -1,5 +1,9 @@ import { IPublicTypeLocationChildrenDetail, IPublicTypeLocationDetailType } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; export function isLocationChildrenDetail(obj: any): obj is IPublicTypeLocationChildrenDetail { - return obj && obj.type === IPublicTypeLocationDetailType.Children; + if (!isObject(obj)) { + return false; + } + return obj.type === IPublicTypeLocationDetailType.Children; } \ No newline at end of file diff --git a/packages/utils/src/check-types/is-location-data.ts b/packages/utils/src/check-types/is-location-data.ts index 8bb3103461..dabd493fa8 100644 --- a/packages/utils/src/check-types/is-location-data.ts +++ b/packages/utils/src/check-types/is-location-data.ts @@ -1,5 +1,9 @@ import { IPublicTypeLocationData } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; export function isLocationData(obj: any): obj is IPublicTypeLocationData { - return obj && obj.target && obj.detail; + if (!isObject(obj)) { + return false; + } + return 'target' in obj && 'detail' in obj; } \ No newline at end of file diff --git a/packages/utils/src/check-types/is-lowcode-project-schema.ts b/packages/utils/src/check-types/is-lowcode-project-schema.ts index 0fffaea2fc..230911f0f3 100644 --- a/packages/utils/src/check-types/is-lowcode-project-schema.ts +++ b/packages/utils/src/check-types/is-lowcode-project-schema.ts @@ -1,6 +1,15 @@ -import { IPublicTypeComponentSchema, IPublicTypeProjectSchema } from "@alilc/lowcode-types"; -import { isComponentSchema } from "./is-component-schema"; +import { IPublicTypeComponentSchema, IPublicTypeProjectSchema } from '@alilc/lowcode-types'; +import { isComponentSchema } from './is-component-schema'; +import { isObject } from '../is-object'; export function isLowcodeProjectSchema(data: any): data is IPublicTypeProjectSchema<IPublicTypeComponentSchema> { - return data && data.componentsTree && data.componentsTree.length && isComponentSchema(data.componentsTree[0]); + if (!isObject(data)) { + return false; + } + + if (!('componentsTree' in data) || data.componentsTree.length === 0) { + return false; + } + + return isComponentSchema(data.componentsTree[0]); } diff --git a/packages/utils/src/check-types/is-node-schema.ts b/packages/utils/src/check-types/is-node-schema.ts index bfc3ff3f2b..253c05a080 100644 --- a/packages/utils/src/check-types/is-node-schema.ts +++ b/packages/utils/src/check-types/is-node-schema.ts @@ -1,5 +1,9 @@ import { IPublicTypeNodeSchema } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; export function isNodeSchema(data: any): data is IPublicTypeNodeSchema { - return data && data.componentName && !data.isNode; + if (!isObject(data)) { + return false; + } + return 'componentName' in data && !data.isNode; } diff --git a/packages/utils/src/check-types/is-node.ts b/packages/utils/src/check-types/is-node.ts index 14c2e2f74e..b4690ddff9 100644 --- a/packages/utils/src/check-types/is-node.ts +++ b/packages/utils/src/check-types/is-node.ts @@ -1,5 +1,9 @@ import { IPublicModelNode } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; export function isNode<Node = IPublicModelNode>(node: any): node is Node { - return node && node.isNode; + if (!isObject(node)) { + return false; + } + return node.isNode; } \ No newline at end of file diff --git a/packages/utils/src/check-types/is-object.ts b/packages/utils/src/check-types/is-object.ts new file mode 100644 index 0000000000..56ceb7d979 --- /dev/null +++ b/packages/utils/src/check-types/is-object.ts @@ -0,0 +1,3 @@ +export function isObject(obj: any): boolean { + return obj && typeof obj === 'object'; +} \ No newline at end of file diff --git a/packages/utils/src/check-types/is-procode-component-type.ts b/packages/utils/src/check-types/is-procode-component-type.ts index 5c768dd943..46618dcd5a 100644 --- a/packages/utils/src/check-types/is-procode-component-type.ts +++ b/packages/utils/src/check-types/is-procode-component-type.ts @@ -1,6 +1,10 @@ import { IPublicTypeComponentMap, IPublicTypeProCodeComponent } from '@alilc/lowcode-types'; - +import { isObject } from '../is-object'; export function isProCodeComponentType(desc: IPublicTypeComponentMap): desc is IPublicTypeProCodeComponent { + if (!isObject(desc)) { + return false; + } + return 'package' in desc; } diff --git a/packages/utils/src/check-types/is-project-schema.ts b/packages/utils/src/check-types/is-project-schema.ts index b228d481e0..d217acd9ee 100644 --- a/packages/utils/src/check-types/is-project-schema.ts +++ b/packages/utils/src/check-types/is-project-schema.ts @@ -1,5 +1,9 @@ -import { IPublicTypeProjectSchema } from "@alilc/lowcode-types"; +import { IPublicTypeProjectSchema } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; export function isProjectSchema(data: any): data is IPublicTypeProjectSchema { - return data && data.componentsTree; + if (!isObject(data)) { + return false; + } + return 'componentsTree' in data; } diff --git a/packages/utils/src/check-types/is-setter-config.ts b/packages/utils/src/check-types/is-setter-config.ts index d631d237f1..98d835f32c 100644 --- a/packages/utils/src/check-types/is-setter-config.ts +++ b/packages/utils/src/check-types/is-setter-config.ts @@ -1,7 +1,10 @@ import { IPublicTypeSetterConfig } from '@alilc/lowcode-types'; import { isCustomView } from './is-custom-view'; - +import { isObject } from '../is-object'; export function isSetterConfig(obj: any): obj is IPublicTypeSetterConfig { - return obj && typeof obj === 'object' && 'componentName' in obj && !isCustomView(obj); + if (!isObject(obj)) { + return false; + } + return 'componentName' in obj && !isCustomView(obj); } diff --git a/packages/utils/src/check-types/is-setting-field.ts b/packages/utils/src/check-types/is-setting-field.ts index 67a183a959..0d6e21d848 100644 --- a/packages/utils/src/check-types/is-setting-field.ts +++ b/packages/utils/src/check-types/is-setting-field.ts @@ -1,5 +1,10 @@ -import { IPublicModelSettingField } from "@alilc/lowcode-types"; +import { IPublicModelSettingField } from '@alilc/lowcode-types'; +import { isObject } from '../is-object'; export function isSettingField(obj: any): obj is IPublicModelSettingField { - return obj && obj.isSettingField; + if (!isObject(obj)) { + return false; + } + + return 'isSettingField' in obj && obj.isSettingField; } diff --git a/packages/utils/src/clone-enumerable-property.ts b/packages/utils/src/clone-enumerable-property.ts index 414f8dccdd..eb09e177fc 100644 --- a/packages/utils/src/clone-enumerable-property.ts +++ b/packages/utils/src/clone-enumerable-property.ts @@ -11,8 +11,8 @@ const excludePropertyNames = [ 'arguments', ]; -export function cloneEnumerableProperty(target: any, origin: any) { - const compExtraPropertyNames = Object.keys(origin).filter(d => !excludePropertyNames.includes(d)); +export function cloneEnumerableProperty(target: any, origin: any, excludes = excludePropertyNames) { + const compExtraPropertyNames = Object.keys(origin).filter(d => !excludes.includes(d)); compExtraPropertyNames.forEach((d: string) => { (target as any)[d] = origin[d]; diff --git a/packages/utils/src/is-object.ts b/packages/utils/src/is-object.ts index 50b580e5a1..c8d764458b 100644 --- a/packages/utils/src/is-object.ts +++ b/packages/utils/src/is-object.ts @@ -1,4 +1,4 @@ -export function isObject(value: any): value is Record<string, unknown> { +export function isObject(value: any): value is Record<string, any> { return value !== null && typeof value === 'object'; } diff --git a/packages/utils/src/is-react.ts b/packages/utils/src/is-react.ts index b19f043f14..1d6c939ea1 100644 --- a/packages/utils/src/is-react.ts +++ b/packages/utils/src/is-react.ts @@ -2,27 +2,49 @@ import { ComponentClass, Component, FunctionComponent, ComponentType, createElem import { cloneEnumerableProperty } from './clone-enumerable-property'; const hasSymbol = typeof Symbol === 'function' && Symbol.for; -const REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0; -const REACT_MEMO_TYPE = hasSymbol ? Symbol.for('react.memo') : 0xead3; +export const REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0; +export const REACT_MEMO_TYPE = hasSymbol ? Symbol.for('react.memo') : 0xead3; export function isReactClass(obj: any): obj is ComponentClass<any> { - return obj && obj.prototype && (obj.prototype.isReactComponent || obj.prototype instanceof Component); + if (!obj) { + return false; + } + if (obj.prototype && (obj.prototype.isReactComponent || obj.prototype instanceof Component)) { + return true; + } + return false; } export function acceptsRef(obj: any): boolean { - return obj?.prototype?.isReactComponent || isForwardOrMemoForward(obj); + if (!obj) { + return false; + } + if (obj?.prototype?.isReactComponent || isForwardOrMemoForward(obj)) { + return true; + } + + return false; } export function isForwardRefType(obj: any): boolean { - return obj?.$$typeof && obj?.$$typeof === REACT_FORWARD_REF_TYPE; + if (!obj || !obj?.$$typeof) { + return false; + } + return obj?.$$typeof === REACT_FORWARD_REF_TYPE; } -function isMemoType(obj: any): boolean { - return obj?.$$typeof && obj.$$typeof === REACT_MEMO_TYPE; +export function isMemoType(obj: any): boolean { + if (!obj || !obj?.$$typeof) { + return false; + } + return obj.$$typeof === REACT_MEMO_TYPE; } export function isForwardOrMemoForward(obj: any): boolean { - return obj?.$$typeof && ( + if (!obj || !obj?.$$typeof) { + return false; + } + return ( // React.forwardRef(..) isForwardRefType(obj) || // React.memo(React.forwardRef(..)) diff --git a/packages/utils/src/logger.ts b/packages/utils/src/logger.ts index 4c8f375ecd..3eb43eedbe 100644 --- a/packages/utils/src/logger.ts +++ b/packages/utils/src/logger.ts @@ -88,7 +88,7 @@ const shouldOutput = ( const output = (logLevel: string, bizName: string) => { return (...args: any[]) => { - return outputFunction[logLevel].apply(console, getLogArgs(args, bizName, logLevel)); + return outputFunction[logLevel]?.apply(console, getLogArgs(args, bizName, logLevel)); }; }; @@ -142,7 +142,6 @@ const defaultOptions: Options = { bizName: '*', }; - class Logger { bizName: string; targetBizName: string; @@ -192,7 +191,6 @@ class Logger { } } - export { Logger }; export function getLogger(config: { level: Level; bizName: string }): Logger { diff --git a/packages/utils/src/misc.ts b/packages/utils/src/misc.ts index 89f121065b..28833ef321 100644 --- a/packages/utils/src/misc.ts +++ b/packages/utils/src/misc.ts @@ -2,6 +2,9 @@ import { isI18NObject } from './is-object'; import { get } from 'lodash'; import { IPublicEnumTransformStage, IPublicModelComponentMeta } from '@alilc/lowcode-types'; +import { Logger } from './logger'; + +const logger = new Logger({ level: 'warn', bizName: 'utils' }); interface Variable { type: 'variable'; @@ -10,7 +13,10 @@ interface Variable { } export function isVariable(obj: any): obj is Variable { - return obj && obj.type === 'variable'; + if (!obj || typeof obj !== 'object') { + return false; + } + return obj.type === 'variable'; } export function isUseI18NSetter(prototype: any, propName: string) { @@ -103,12 +109,15 @@ export function invariant(check: any, message: string, thing?: any) { export function deprecate(fail: any, message: string, alterative?: string) { if (fail) { - console.warn(`Deprecation: ${message}` + (alterative ? `, use ${alterative} instead.` : '')); + logger.warn(`Deprecation: ${message}` + (alterative ? `, use ${alterative} instead.` : '')); } } export function isRegExp(obj: any): obj is RegExp { - return obj && obj.test && obj.exec && obj.compile; + if (!obj || typeof obj !== 'object') { + return false; + } + return 'test' in obj && 'exec' in obj && 'compile' in obj; } /** diff --git a/packages/utils/src/navtive-selection.ts b/packages/utils/src/navtive-selection.ts index 76f51f48aa..b8e5257734 100644 --- a/packages/utils/src/navtive-selection.ts +++ b/packages/utils/src/navtive-selection.ts @@ -1,4 +1,5 @@ -let nativeSelectionEnabled = true; +export let nativeSelectionEnabled = true; + const preventSelection = (e: Event) => { if (nativeSelectionEnabled) { return null; diff --git a/packages/utils/src/script.ts b/packages/utils/src/script.ts index 25159b198c..c4c476fac4 100644 --- a/packages/utils/src/script.ts +++ b/packages/utils/src/script.ts @@ -1,4 +1,7 @@ import { createDefer } from './create-defer'; +import { Logger } from './logger'; + +const logger = new Logger({ level: 'warn', bizName: 'utils' }); export function evaluate(script: string, scriptType?: string) { const scriptEl = document.createElement('script'); @@ -53,7 +56,7 @@ export function newFunction(args: string, code: string) { // eslint-disable-next-line no-new-func return new Function(args, code); } catch (e) { - console.warn('Caught error, Cant init func'); + logger.warn('Caught error, Cant init func'); return null; } } diff --git a/packages/utils/src/svg-icon.tsx b/packages/utils/src/svg-icon.tsx index f75724b064..2513f7bcab 100644 --- a/packages/utils/src/svg-icon.tsx +++ b/packages/utils/src/svg-icon.tsx @@ -1,4 +1,4 @@ -import { ReactNode } from 'react'; +import React, { ReactNode } from 'react'; const SizePresets: any = { xsmall: 8, diff --git a/packages/utils/test/src/__snapshots__/is-react.test.tsx.snap b/packages/utils/test/src/__snapshots__/is-react.test.tsx.snap new file mode 100644 index 0000000000..14ef394533 --- /dev/null +++ b/packages/utils/test/src/__snapshots__/is-react.test.tsx.snap @@ -0,0 +1,10 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`wrapReactClass should render the FunctionComponent with props 1`] = ` +<FunctionComponent + prop1="value1" + prop2="value2" +> + Child Text +</FunctionComponent> +`; diff --git a/packages/utils/test/src/build-components/buildComponents.test.ts b/packages/utils/test/src/build-components/buildComponents.test.ts deleted file mode 100644 index e854890da4..0000000000 --- a/packages/utils/test/src/build-components/buildComponents.test.ts +++ /dev/null @@ -1,342 +0,0 @@ - -import { buildComponents } from "../../../src/build-components"; - -function Button() {}; - -function WrapButton() {}; - -function ButtonGroup() {}; - -function WrapButtonGroup() {}; - -ButtonGroup.Button = Button; - -Button.displayName = "Button"; -ButtonGroup.displayName = "ButtonGroup"; -ButtonGroup.prototype.isReactComponent = true; -Button.prototype.isReactComponent = true; - -jest.mock('../../../src/is-react', () => { - const original = jest.requireActual('../../../src/is-react'); - return { - ...original, - wrapReactClass(view) { - return view; - } - } -}) - -describe('build-component', () => { - it('basic button', () => { - expect( - buildComponents( - { - '@alilc/button': { - Button, - } - }, - { - Button: { - componentName: 'Button', - package: '@alilc/button', - destructuring: true, - exportName: 'Button', - subName: 'Button', - } - }, - () => {}, - )) - .toEqual({ - Button, - }); - }); - - it('component is a __esModule', () => { - expect( - buildComponents( - { - '@alilc/button': { - __esModule: true, - default: Button, - } - }, - { - Button: { - componentName: 'Button', - package: '@alilc/button', - } - }, - () => {}, - )) - .toEqual({ - Button, - }); - }) - - it('basic warp button', () => { - expect( - buildComponents( - { - '@alilc/button': { - WrapButton, - } - }, - { - WrapButton: { - componentName: 'WrapButton', - package: '@alilc/button', - destructuring: true, - exportName: 'WrapButton', - subName: 'WrapButton', - } - }, - () => {}, - )) - .toEqual({ - WrapButton, - }); - }); - - it('destructuring is false button', () => { - expect( - buildComponents( - { - '@alilc/button': Button - }, - { - Button: { - componentName: 'Button', - package: '@alilc/button', - destructuring: false, - } - }, - () => {}, - )) - .toEqual({ - Button, - }); - }); - - it('Button and ButtonGroup', () => { - expect( - buildComponents( - { - '@alilc/button': { - Button, - ButtonGroup, - } - }, - { - Button: { - componentName: 'Button', - package: '@alilc/button', - destructuring: true, - exportName: 'Button', - subName: 'Button', - }, - ButtonGroup: { - componentName: 'ButtonGroup', - package: '@alilc/button', - destructuring: true, - exportName: 'ButtonGroup', - subName: 'ButtonGroup', - } - }, - () => {}, - )) - .toEqual({ - Button, - ButtonGroup, - }); - }); - - it('ButtonGroup and ButtonGroup.Button', () => { - expect( - buildComponents( - { - '@alilc/button': { - ButtonGroup, - } - }, - { - Button: { - componentName: 'Button', - package: '@alilc/button', - destructuring: true, - exportName: 'ButtonGroup', - subName: 'ButtonGroup.Button', - }, - ButtonGroup: { - componentName: 'ButtonGroup', - package: '@alilc/button', - destructuring: true, - exportName: 'ButtonGroup', - subName: 'ButtonGroup', - } - }, - () => {}, - )) - .toEqual({ - Button, - ButtonGroup, - }); - }); - - it('ButtonGroup.default and ButtonGroup.Button', () => { - expect( - buildComponents( - { - '@alilc/button': ButtonGroup, - }, - { - Button: { - componentName: 'Button', - package: '@alilc/button', - destructuring: true, - exportName: 'Button', - subName: 'Button', - }, - ButtonGroup: { - componentName: 'ButtonGroup', - package: '@alilc/button', - destructuring: true, - exportName: 'default', - subName: 'default', - } - }, - () => {}, - )) - .toEqual({ - Button, - ButtonGroup, - }); - }); - - it('no npm component', () => { - expect( - buildComponents( - { - '@alilc/button': Button, - }, - { - Button: null, - }, - () => {}, - )) - .toEqual({}); - }); - - it('no npm component and global button', () => { - window.Button = Button; - expect( - buildComponents( - {}, - { - Button: null, - }, - () => {}, - )) - .toEqual({ - Button, - }); - window.Button = null; - }); - - it('componentsMap value is component funtion', () => { - expect( - buildComponents( - {}, - { - Button, - }, - () => {}, - )) - .toEqual({ - Button, - }); - }); - - - it('componentsMap value is component', () => { - expect( - buildComponents( - {}, - { - Button: WrapButton, - }, - () => {}, - )) - .toEqual({ - Button: WrapButton, - }); - }); - - it('componentsMap value is mix component', () => { - expect( - buildComponents( - {}, - { - Button: { - WrapButton, - Button, - ButtonGroup, - }, - }, - () => {}, - )) - .toEqual({ - Button: { - WrapButton, - Button, - ButtonGroup, - }, - }); - }); - - it('componentsMap value is Lowcode Component', () => { - expect( - buildComponents( - {}, - { - Button: { - componentName: 'Component', - schema: {}, - }, - }, - (component) => { - return component as any; - }, - )) - .toEqual({ - Button: { - componentsMap: [], - componentsTree: [ - { - componentName: 'Component', - schema: {}, - } - ], - version: "", - }, - }); - }) -}); - -describe('build div component', () => { - it('build div component', () => { - const components = buildComponents( - { - '@alilc/div': 'div' - }, - { - div: { - componentName: 'div', - package: '@alilc/div' - } - }, - () => {}, - ); - - expect(components['div']).not.toBeNull(); - }) -}) \ No newline at end of file diff --git a/packages/utils/test/src/build-components/buildComponents.test.tsx b/packages/utils/test/src/build-components/buildComponents.test.tsx new file mode 100644 index 0000000000..a50a68b396 --- /dev/null +++ b/packages/utils/test/src/build-components/buildComponents.test.tsx @@ -0,0 +1,616 @@ +import React from 'react'; +import { + accessLibrary, + generateHtmlComp, + getSubComponent, + buildComponents, + getProjectUtils, +} from "../../../src/build-components"; + +function Button() {}; + +function WrapButton() {}; + +function ButtonGroup() {}; + +function WrapButtonGroup() {}; + +ButtonGroup.Button = Button; + +Button.displayName = "Button"; +ButtonGroup.displayName = "ButtonGroup"; +ButtonGroup.prototype.isReactComponent = true; +Button.prototype.isReactComponent = true; + +jest.mock('../../../src/is-react', () => { + const original = jest.requireActual('../../../src/is-react'); + return { + ...original, + wrapReactClass(view) { + return view; + } + } +}); + +describe('accessLibrary', () => { + it('should return a library object when given a library object', () => { + const libraryObject = { key: 'value' }; + const result = accessLibrary(libraryObject); + expect(result).toEqual(libraryObject); + }); + + it('should generate an HTML component when given a string library name', () => { + const libraryName = 'div'; + const result = accessLibrary(libraryName); + + // You can write more specific assertions to validate the generated component + expect(result).toBeDefined(); + }); + + // Add more test cases to cover other scenarios +}); + +describe('generateHtmlComp', () => { + it('should generate an HTML component for valid HTML tags', () => { + const htmlTags = ['a', 'img', 'div', 'span', 'svg']; + htmlTags.forEach((tag) => { + const result = generateHtmlComp(tag); + + // You can write more specific assertions to validate the generated component + expect(result).toBeDefined(); + }); + }); + + it('should return undefined for an invalid HTML tag', () => { + const invalidTag = 'invalidtag'; + const result = generateHtmlComp(invalidTag); + expect(result).toBeUndefined(); + }); + + // Add more test cases to cover other scenarios +}); + +describe('getSubComponent', () => { + it('should return the root library if paths are empty', () => { + const library = { component: 'RootComponent' }; + const paths = []; + const result = getSubComponent(library, paths); + expect(result).toEqual(library); + }); + + it('should return the specified sub-component', () => { + const library = { + components: { + Button: 'ButtonComponent', + Text: 'TextComponent', + }, + }; + const paths = ['components', 'Button']; + const result = getSubComponent(library, paths); + expect(result).toEqual('ButtonComponent'); + }); + + it('should handle missing keys in the path', () => { + const library = { + components: { + Button: 'ButtonComponent', + }, + }; + const paths = ['components', 'Text']; + const result = getSubComponent(library, paths); + expect(result).toEqual({ + Button: 'ButtonComponent', + }); + }); + + it('should handle exceptions and return null', () => { + const library = 'ButtonComponent'; + const paths = ['components', 'Button']; + // Simulate an exception by providing a non-object in place of 'ButtonComponent' + const result = getSubComponent(library, paths); + expect(result).toBeNull(); + }); + + it('should handle the "default" key as the first path element', () => { + const library = { + default: 'DefaultComponent', + }; + const paths = ['default']; + const result = getSubComponent(library, paths); + expect(result).toEqual('DefaultComponent'); + }); +}); + +describe('getProjectUtils', () => { + it('should return an empty object when given empty metadata and library map', () => { + const libraryMap = {}; + const utilsMetadata = []; + const result = getProjectUtils(libraryMap, utilsMetadata); + expect(result).toEqual({}); + }); + + it('should return project utilities based on metadata and library map', () => { + const libraryMap = { + 'package1': 'library1', + 'package2': 'library2', + }; + + const utilsMetadata = [ + { + name: 'util1', + npm: { + package: 'package1', + }, + }, + { + name: 'util2', + npm: { + package: 'package2', + }, + }, + ]; + + global['library1'] = { name: 'library1' }; + global['library2'] = { name: 'library2' }; + + const result = getProjectUtils(libraryMap, utilsMetadata); + + // Define the expected output based on the mocked accessLibrary + const expectedOutput = { + 'util1': { name: 'library1' }, + 'util2': { name: 'library2' }, + }; + + expect(result).toEqual(expectedOutput); + + global['library1'] = null; + global['library1'] = null; + }); + + it('should handle metadata with destructuring', () => { + const libraryMap = { + 'package1': { destructuring: true, util1: 'library1', util2: 'library2' }, + }; + + const utilsMetadata = [ + { + name: 'util1', + npm: { + package: 'package1', + destructuring: true, + }, + }, + ]; + + const result = getProjectUtils(libraryMap, utilsMetadata); + + // Define the expected output based on the mocked accessLibrary + const expectedOutput = { + 'util1': 'library1', + 'util2': 'library2', + }; + + expect(result).toEqual(expectedOutput); + }); +}); + +describe('buildComponents', () => { + it('should create components from component map with React components', () => { + const libraryMap = {}; + const componentsMap = { + Button: () => <button>Button</button>, + Text: () => <p>Text</p>, + }; + + const createComponent = (schema) => { + // Mock createComponent function + return schema.componentsTree.map((component) => component.component); + }; + + const result = buildComponents(libraryMap, componentsMap, createComponent); + + expect(result.Button).toBeDefined(); + expect(result.Text).toBeDefined(); + }); + + it('should create components from component map with component schemas', () => { + const libraryMap = {}; + const componentsMap = { + Button: { + componentsTree: [ + { + componentName: 'Component' + } + ] + }, + Text: { + componentsTree: [ + { + componentName: 'Component' + } + ] + }, + }; + + const createComponent = (schema) => { + // Mock createComponent function + return schema.componentsTree.map((component) => component.component); + }; + + const result = buildComponents(libraryMap, componentsMap, createComponent); + + expect(result.Button).toBeDefined(); + expect(result.Text).toBeDefined(); + }); + + it('should create components from component map with React components and schemas', () => { + const libraryMap = {}; + const componentsMap = { + Button: () => <button>Button</button>, + Text: { + type: 'ComponentSchema', + // Add component schema properties here + }, + }; + + const createComponent = (schema) => { + // Mock createComponent function + return schema.componentsTree.map((component) => component.component); + }; + + const result = buildComponents(libraryMap, componentsMap, createComponent); + + expect(result.Button).toBeDefined(); + expect(result.Text).toBeDefined(); + }); + + it('should create components from component map with library mappings', () => { + const libraryMap = { + 'libraryName1': 'library1', + 'libraryName2': 'library2', + }; + const componentsMap = { + Button: { + package: 'libraryName1', + version: '1.0', + exportName: 'ButtonComponent', + }, + Text: { + package: 'libraryName2', + version: '2.0', + exportName: 'TextComponent', + }, + }; + + const createComponent = (schema) => { + // Mock createComponent function + return schema.componentsTree.map((component) => component.component); + }; + + global['library1'] = () => <button>ButtonComponent</button>; + global['library2'] = () => () => <p>TextComponent</p>; + + const result = buildComponents(libraryMap, componentsMap, createComponent); + + expect(result.Button).toBeDefined(); + expect(result.Text).toBeDefined(); + + global['library1'] = null; + global['library2'] = null; + }); +}); + +describe('build-component', () => { + it('basic button', () => { + expect( + buildComponents( + { + '@alilc/button': { + Button, + } + }, + { + Button: { + componentName: 'Button', + package: '@alilc/button', + destructuring: true, + exportName: 'Button', + subName: 'Button', + } + }, + () => {}, + )) + .toEqual({ + Button, + }); + }); + + it('component is a __esModule', () => { + expect( + buildComponents( + { + '@alilc/button': { + __esModule: true, + default: Button, + } + }, + { + Button: { + componentName: 'Button', + package: '@alilc/button', + } + }, + () => {}, + )) + .toEqual({ + Button, + }); + }) + + it('basic warp button', () => { + expect( + buildComponents( + { + '@alilc/button': { + WrapButton, + } + }, + { + WrapButton: { + componentName: 'WrapButton', + package: '@alilc/button', + destructuring: true, + exportName: 'WrapButton', + subName: 'WrapButton', + } + }, + () => {}, + )) + .toEqual({ + WrapButton, + }); + }); + + it('destructuring is false button', () => { + expect( + buildComponents( + { + '@alilc/button': Button + }, + { + Button: { + componentName: 'Button', + package: '@alilc/button', + destructuring: false, + } + }, + () => {}, + )) + .toEqual({ + Button, + }); + }); + + it('Button and ButtonGroup', () => { + expect( + buildComponents( + { + '@alilc/button': { + Button, + ButtonGroup, + } + }, + { + Button: { + componentName: 'Button', + package: '@alilc/button', + destructuring: true, + exportName: 'Button', + subName: 'Button', + }, + ButtonGroup: { + componentName: 'ButtonGroup', + package: '@alilc/button', + destructuring: true, + exportName: 'ButtonGroup', + subName: 'ButtonGroup', + } + }, + () => {}, + )) + .toEqual({ + Button, + ButtonGroup, + }); + }); + + it('ButtonGroup and ButtonGroup.Button', () => { + expect( + buildComponents( + { + '@alilc/button': { + ButtonGroup, + } + }, + { + Button: { + componentName: 'Button', + package: '@alilc/button', + destructuring: true, + exportName: 'ButtonGroup', + subName: 'ButtonGroup.Button', + }, + ButtonGroup: { + componentName: 'ButtonGroup', + package: '@alilc/button', + destructuring: true, + exportName: 'ButtonGroup', + subName: 'ButtonGroup', + } + }, + () => {}, + )) + .toEqual({ + Button, + ButtonGroup, + }); + }); + + it('ButtonGroup.default and ButtonGroup.Button', () => { + expect( + buildComponents( + { + '@alilc/button': ButtonGroup, + }, + { + Button: { + componentName: 'Button', + package: '@alilc/button', + destructuring: true, + exportName: 'Button', + subName: 'Button', + }, + ButtonGroup: { + componentName: 'ButtonGroup', + package: '@alilc/button', + destructuring: true, + exportName: 'default', + subName: 'default', + } + }, + () => {}, + )) + .toEqual({ + Button, + ButtonGroup, + }); + }); + + it('no npm component', () => { + expect( + buildComponents( + { + '@alilc/button': Button, + }, + { + Button: null, + }, + () => {}, + )) + .toEqual({}); + }); + + it('no npm component and global button', () => { + window.Button = Button; + expect( + buildComponents( + {}, + { + Button: null, + }, + () => {}, + )) + .toEqual({ + Button, + }); + window.Button = null; + }); + + it('componentsMap value is component funtion', () => { + expect( + buildComponents( + {}, + { + Button, + }, + () => {}, + )) + .toEqual({ + Button, + }); + }); + + + it('componentsMap value is component', () => { + expect( + buildComponents( + {}, + { + Button: WrapButton, + }, + () => {}, + )) + .toEqual({ + Button: WrapButton, + }); + }); + + it('componentsMap value is mix component', () => { + expect( + buildComponents( + {}, + { + Button: { + WrapButton, + Button, + ButtonGroup, + }, + }, + () => {}, + )) + .toEqual({ + Button: { + WrapButton, + Button, + ButtonGroup, + }, + }); + }); + + it('componentsMap value is Lowcode Component', () => { + expect( + buildComponents( + {}, + { + Button: { + componentName: 'Component', + schema: {}, + }, + }, + (component) => { + return component as any; + }, + )) + .toEqual({ + Button: { + componentsMap: [], + componentsTree: [ + { + componentName: 'Component', + schema: {}, + } + ], + version: "", + }, + }); + }) +}); + +describe('build div component', () => { + it('build div component', () => { + const components = buildComponents( + { + '@alilc/div': 'div' + }, + { + div: { + componentName: 'div', + package: '@alilc/div' + } + }, + () => {}, + ); + + expect(components['div']).not.toBeNull(); + }) +}) \ No newline at end of file diff --git a/packages/utils/test/src/check-types/is-action-content-object.test.ts b/packages/utils/test/src/check-types/is-action-content-object.test.ts new file mode 100644 index 0000000000..08b95788d1 --- /dev/null +++ b/packages/utils/test/src/check-types/is-action-content-object.test.ts @@ -0,0 +1,20 @@ +import { isActionContentObject } from '../../../src/check-types/is-action-content-object'; + +describe('isActionContentObject', () => { + test('should return true for an object', () => { + const obj = { prop: 'value' }; + expect(isActionContentObject(obj)).toBe(true); + }); + + test('should return false for a non-object', () => { + expect(isActionContentObject('not an object')).toBe(false); + expect(isActionContentObject(123)).toBe(false); + expect(isActionContentObject(null)).toBe(false); + expect(isActionContentObject(undefined)).toBe(false); + }); + + test('should return false for an empty object', () => { + const obj = {}; + expect(isActionContentObject(obj)).toBe(true); + }); +}); diff --git a/packages/utils/test/src/check-types/is-custom-view.test.tsx b/packages/utils/test/src/check-types/is-custom-view.test.tsx new file mode 100644 index 0000000000..62c08780e6 --- /dev/null +++ b/packages/utils/test/src/check-types/is-custom-view.test.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import { isCustomView } from '../../../src/check-types/is-custom-view'; +import { IPublicTypeCustomView } from '@alilc/lowcode-types'; + +describe('isCustomView', () => { + test('should return true when obj is a valid React element', () => { + const obj: IPublicTypeCustomView = <div>Hello, World!</div>; + expect(isCustomView(obj)).toBe(true); + }); + + test('should return true when obj is a valid React component', () => { + const MyComponent: React.FC = () => <div>Hello, World!</div>; + const obj: IPublicTypeCustomView = MyComponent; + expect(isCustomView(obj)).toBe(true); + }); + + test('should return false when obj is null or undefined', () => { + expect(isCustomView(null)).toBe(false); + expect(isCustomView(undefined)).toBe(false); + }); + + test('should return false when obj is not a valid React element or component', () => { + const obj: IPublicTypeCustomView = 'not a valid object'; + expect(isCustomView(obj)).toBe(false); + }); +}); diff --git a/packages/utils/test/src/check-types/is-dom-text.test.ts b/packages/utils/test/src/check-types/is-dom-text.test.ts new file mode 100644 index 0000000000..50dce0fb7a --- /dev/null +++ b/packages/utils/test/src/check-types/is-dom-text.test.ts @@ -0,0 +1,13 @@ +import { isDOMText } from '../../../src/check-types/is-dom-text'; + +describe('isDOMText', () => { + it('should return true when the input is a string', () => { + const result = isDOMText('Hello World'); + expect(result).toBe(true); + }); + + it('should return false when the input is not a string', () => { + const result = isDOMText(123); + expect(result).toBe(false); + }); +}); diff --git a/packages/utils/test/src/check-types/is-drag-any-object.test.ts b/packages/utils/test/src/check-types/is-drag-any-object.test.ts new file mode 100644 index 0000000000..6a835f2be3 --- /dev/null +++ b/packages/utils/test/src/check-types/is-drag-any-object.test.ts @@ -0,0 +1,32 @@ +import { isDragAnyObject } from '../../../src/check-types/is-drag-any-object'; +import { IPublicEnumDragObjectType } from '@alilc/lowcode-types'; + +describe('isDragAnyObject', () => { + it('should return false if obj is null', () => { + const result = isDragAnyObject(null); + expect(result).toBe(false); + }); + + it('should return false if obj is number', () => { + const result = isDragAnyObject(2); + expect(result).toBe(false); + }); + + it('should return false if obj.type is NodeData', () => { + const obj = { type: IPublicEnumDragObjectType.NodeData }; + const result = isDragAnyObject(obj); + expect(result).toBe(false); + }); + + it('should return false if obj.type is Node', () => { + const obj = { type: IPublicEnumDragObjectType.Node }; + const result = isDragAnyObject(obj); + expect(result).toBe(false); + }); + + it('should return true if obj.type is anything else', () => { + const obj = { type: 'SomeOtherType' }; + const result = isDragAnyObject(obj); + expect(result).toBe(true); + }); +}); diff --git a/packages/utils/test/src/check-types/is-drag-node-data-object.test.ts b/packages/utils/test/src/check-types/is-drag-node-data-object.test.ts new file mode 100644 index 0000000000..92867843a2 --- /dev/null +++ b/packages/utils/test/src/check-types/is-drag-node-data-object.test.ts @@ -0,0 +1,29 @@ +import { IPublicEnumDragObjectType, IPublicTypeDragNodeDataObject } from '@alilc/lowcode-types'; +import { isDragNodeDataObject } from '../../../src/check-types/is-drag-node-data-object'; + +describe('isDragNodeDataObject', () => { + test('should return true for valid IPublicTypeDragNodeDataObject', () => { + const obj: IPublicTypeDragNodeDataObject = { + type: IPublicEnumDragObjectType.NodeData, + // 其他属性... + }; + + expect(isDragNodeDataObject(obj)).toBe(true); + }); + + test('should return false for invalid IPublicTypeDragNodeDataObject', () => { + const obj: any = { + type: 'InvalidType', + // 其他属性... + }; + + expect(isDragNodeDataObject(obj)).toBe(false); + }); + + test('should return false for null or undefined', () => { + expect(isDragNodeDataObject(null)).toBe(false); + expect(isDragNodeDataObject(undefined)).toBe(false); + }); + + // 可以添加更多测试用例... +}); diff --git a/packages/utils/test/src/check-types/is-drag-node-object.test.ts b/packages/utils/test/src/check-types/is-drag-node-object.test.ts new file mode 100644 index 0000000000..3561c87885 --- /dev/null +++ b/packages/utils/test/src/check-types/is-drag-node-object.test.ts @@ -0,0 +1,36 @@ +import { IPublicEnumDragObjectType } from '@alilc/lowcode-types'; +import { isDragNodeObject } from '../../../src/check-types/is-drag-node-object'; + +describe('isDragNodeObject', () => { + it('should return true if the object is of IPublicTypeDragNodeObject type and has type IPublicEnumDragObjectType.Node', () => { + const obj = { + type: IPublicEnumDragObjectType.Node, + //... other properties + }; + + expect(isDragNodeObject(obj)).toBe(true); + }); + + it('should return false if the object is not of IPublicTypeDragNodeObject type', () => { + const obj = { + type: IPublicEnumDragObjectType.OtherType, + //... other properties + }; + + expect(isDragNodeObject(obj)).toBe(false); + }); + + it('should return false if the object is of IPublicTypeDragNodeObject type but type is not IPublicEnumDragObjectType.Node', () => { + const obj = { + type: IPublicEnumDragObjectType.OtherType, + //... other properties + }; + + expect(isDragNodeObject(obj)).toBe(false); + }); + + it('should return false if the object is null or undefined', () => { + expect(isDragNodeObject(null)).toBe(false); + expect(isDragNodeObject(undefined)).toBe(false); + }); +}); diff --git a/packages/utils/test/src/check-types/is-dynamic-setter.test.ts b/packages/utils/test/src/check-types/is-dynamic-setter.test.ts new file mode 100644 index 0000000000..72f55367d0 --- /dev/null +++ b/packages/utils/test/src/check-types/is-dynamic-setter.test.ts @@ -0,0 +1,28 @@ +import { Component } from 'react'; +import { isDynamicSetter } from '../../../src/check-types/is-dynamic-setter'; + +describe('isDynamicSetter', () => { + it('returns true if input is a dynamic setter function', () => { + const dynamicSetter = (value: any) => { + // some implementation + }; + + expect(isDynamicSetter(dynamicSetter)).toBeTruthy(); + }); + + it('returns false if input is not a dynamic setter function', () => { + expect(isDynamicSetter('not a function')).toBeFalsy(); + expect(isDynamicSetter(null)).toBeFalsy(); + expect(isDynamicSetter(undefined)).toBeFalsy(); + expect(isDynamicSetter(2)).toBeFalsy(); + expect(isDynamicSetter(0)).toBeFalsy(); + }); + + it('returns false if input is a React class', () => { + class ReactClass extends Component { + // some implementation + } + + expect(isDynamicSetter(ReactClass)).toBeFalsy(); + }); +}); diff --git a/packages/utils/test/src/check-types/is-i18n-data.test.ts b/packages/utils/test/src/check-types/is-i18n-data.test.ts new file mode 100644 index 0000000000..2e903a2ed2 --- /dev/null +++ b/packages/utils/test/src/check-types/is-i18n-data.test.ts @@ -0,0 +1,27 @@ +import { isI18nData } from '../../../src/check-types/is-i18n-data'; +import { IPublicTypeI18nData } from "@alilc/lowcode-types"; + +describe('isI18nData', () => { + it('should return true for valid i18n data', () => { + const i18nData: IPublicTypeI18nData = { + type: 'i18n', + // add any other required properties here + }; + + expect(isI18nData(i18nData)).toBe(true); + }); + + it('should return false for invalid i18n data', () => { + const invalidData = { + type: 'some-other-type', + // add any other properties here + }; + + expect(isI18nData(invalidData)).toBe(false); + }); + + it('should return false for undefined or null', () => { + expect(isI18nData(undefined)).toBe(false); + expect(isI18nData(null)).toBe(false); + }); +}); diff --git a/packages/utils/test/src/check-types/is-isfunction.test.ts b/packages/utils/test/src/check-types/is-isfunction.test.ts new file mode 100644 index 0000000000..5154282285 --- /dev/null +++ b/packages/utils/test/src/check-types/is-isfunction.test.ts @@ -0,0 +1,61 @@ +import { isInnerJsFunction, isJSFunction } from '../../../src/check-types/is-isfunction'; + +describe('isInnerJsFunction', () => { + test('should return true for valid input', () => { + const data = { + type: 'JSExpression', + source: '', + value: '', + extType: 'function' + }; + + expect(isInnerJsFunction(data)).toBe(true); + }); + + test('should return false for invalid input', () => { + const data = { + type: 'JSExpression', + source: '', + value: '', + extType: 'object' + }; + + expect(isInnerJsFunction(data)).toBe(false); + expect(isInnerJsFunction(null)).toBe(false); + expect(isInnerJsFunction(undefined)).toBe(false); + expect(isInnerJsFunction(1)).toBe(false); + expect(isInnerJsFunction(0)).toBe(false); + expect(isInnerJsFunction('string')).toBe(false); + expect(isInnerJsFunction('')).toBe(false); + }); +}); + +describe('isJSFunction', () => { + test('should return true for valid input', () => { + const data = { + type: 'JSFunction', + }; + + expect(isJSFunction(data)).toBe(true); + }); + + test('should return true for inner js function', () => { + const data = { + type: 'JSExpression', + source: '', + value: '', + extType: 'function' + }; + + expect(isJSFunction(data)).toBe(true); + }); + + test('should return false for invalid input', () => { + expect(isJSFunction(null)).toBe(false); + expect(isJSFunction(undefined)).toBe(false); + expect(isJSFunction('string')).toBe(false); + expect(isJSFunction('')).toBe(false); + expect(isJSFunction(0)).toBe(false); + expect(isJSFunction(2)).toBe(false); + }); +}); diff --git a/packages/utils/test/src/check-types/is-jsblock.test.ts b/packages/utils/test/src/check-types/is-jsblock.test.ts new file mode 100644 index 0000000000..e44e9eb705 --- /dev/null +++ b/packages/utils/test/src/check-types/is-jsblock.test.ts @@ -0,0 +1,22 @@ +import { isJSBlock } from '../../../src/check-types/is-jsblock'; + +describe('isJSBlock', () => { + it('should return false if data is null or undefined', () => { + expect(isJSBlock(null)).toBe(false); + expect(isJSBlock(undefined)).toBe(false); + }); + + it('should return false if data is not an object', () => { + expect(isJSBlock('JSBlock')).toBe(false); + expect(isJSBlock(123)).toBe(false); + expect(isJSBlock(true)).toBe(false); + }); + + it('should return false if data.type is not "JSBlock"', () => { + expect(isJSBlock({ type: 'InvalidType' })).toBe(false); + }); + + it('should return true if data is an object and data.type is "JSBlock"', () => { + expect(isJSBlock({ type: 'JSBlock' })).toBe(true); + }); +}); diff --git a/packages/utils/test/src/check-types/is-jsexpression.test.ts b/packages/utils/test/src/check-types/is-jsexpression.test.ts new file mode 100644 index 0000000000..dd8509a3b3 --- /dev/null +++ b/packages/utils/test/src/check-types/is-jsexpression.test.ts @@ -0,0 +1,39 @@ +import { isJSExpression } from '../../../src/check-types/is-jsexpression'; + +describe('isJSExpression', () => { + it('should return true if the input is a valid JSExpression object', () => { + const validJSExpression = { + type: 'JSExpression', + extType: 'variable', + }; + + const result = isJSExpression(validJSExpression); + + expect(result).toBe(true); + }); + + it('should return false if the input is not a valid JSExpression object', () => { + const invalidJSExpression = { + type: 'JSExpression', + extType: 'function', + }; + + const result = isJSExpression(invalidJSExpression); + + expect(result).toBe(false); + }); + + it('should return false if the input is null', () => { + const result = isJSExpression(null); + + expect(result).toBe(false); + }); + + it('should return false if the input is undefined', () => { + const result = isJSExpression(undefined); + + expect(result).toBe(false); + }); + + // 添加其他需要的测试 +}); diff --git a/packages/utils/test/src/check-types/is-jsslot.test.ts b/packages/utils/test/src/check-types/is-jsslot.test.ts new file mode 100644 index 0000000000..5c130cddfd --- /dev/null +++ b/packages/utils/test/src/check-types/is-jsslot.test.ts @@ -0,0 +1,37 @@ +import { isJSSlot } from '../../../src/check-types/is-jsslot'; +import { IPublicTypeJSSlot } from '@alilc/lowcode-types'; + +describe('isJSSlot', () => { + it('should return true when input is of type IPublicTypeJSSlot', () => { + const input: IPublicTypeJSSlot = { + type: 'JSSlot', + // other properties of IPublicTypeJSSlot + }; + + const result = isJSSlot(input); + + expect(result).toBe(true); + }); + + it('should return false when input is not of type IPublicTypeJSSlot', () => { + const input = { + type: 'OtherType', + // other properties + }; + + const result = isJSSlot(input); + + expect(result).toBe(false); + }); + + it('should return false when input is null or undefined', () => { + const input1 = null; + const input2 = undefined; + + const result1 = isJSSlot(input1); + const result2 = isJSSlot(input2); + + expect(result1).toBe(false); + expect(result2).toBe(false); + }); +}); diff --git a/packages/utils/test/src/check-types/is-location-children-detail.test.ts b/packages/utils/test/src/check-types/is-location-children-detail.test.ts new file mode 100644 index 0000000000..f209e8e63f --- /dev/null +++ b/packages/utils/test/src/check-types/is-location-children-detail.test.ts @@ -0,0 +1,27 @@ +import { isLocationChildrenDetail } from '../../../src/check-types/is-location-children-detail'; +import { IPublicTypeLocationChildrenDetail, IPublicTypeLocationDetailType } from '@alilc/lowcode-types'; + +describe('isLocationChildrenDetail', () => { + it('should return true when obj is IPublicTypeLocationChildrenDetail', () => { + const obj: IPublicTypeLocationChildrenDetail = { + type: IPublicTypeLocationDetailType.Children, + // 添加其他必要的属性 + }; + + expect(isLocationChildrenDetail(obj)).toBe(true); + }); + + it('should return false when obj is not IPublicTypeLocationChildrenDetail', () => { + const obj = { + type: 'other', + // 添加其他必要的属性 + }; + + expect(isLocationChildrenDetail(obj)).toBe(false); + expect(isLocationChildrenDetail(null)).toBe(false); + expect(isLocationChildrenDetail(undefined)).toBe(false); + expect(isLocationChildrenDetail('string')).toBe(false); + expect(isLocationChildrenDetail(0)).toBe(false); + expect(isLocationChildrenDetail(2)).toBe(false); + }); +}); diff --git a/packages/utils/test/src/check-types/is-location-data.test.ts b/packages/utils/test/src/check-types/is-location-data.test.ts new file mode 100644 index 0000000000..ba2e2c8be0 --- /dev/null +++ b/packages/utils/test/src/check-types/is-location-data.test.ts @@ -0,0 +1,44 @@ +import { isLocationData } from '../../../src/check-types/is-location-data'; +import { IPublicTypeLocationData } from '@alilc/lowcode-types'; + +describe('isLocationData', () => { + it('should return true when obj is valid location data', () => { + const obj: IPublicTypeLocationData = { + target: 'some target', + detail: 'some detail', + }; + + const result = isLocationData(obj); + + expect(result).toBe(true); + }); + + it('should return false when obj is missing target or detail', () => { + const obj1 = { + target: 'some target', + // missing detail + }; + + const obj2 = { + // missing target + detail: 'some detail', + }; + + const result1 = isLocationData(obj1); + const result2 = isLocationData(obj2); + + expect(result1).toBe(false); + expect(result2).toBe(false); + }); + + it('should return false when obj is null or undefined', () => { + const obj1 = null; + const obj2 = undefined; + + const result1 = isLocationData(obj1); + const result2 = isLocationData(obj2); + + expect(result1).toBe(false); + expect(result2).toBe(false); + }); +}); diff --git a/packages/utils/test/src/check-types/is-lowcode-component-type.test.ts b/packages/utils/test/src/check-types/is-lowcode-component-type.test.ts new file mode 100644 index 0000000000..35b76f00b5 --- /dev/null +++ b/packages/utils/test/src/check-types/is-lowcode-component-type.test.ts @@ -0,0 +1,21 @@ +import { isLowCodeComponentType } from '../../../src/check-types/is-lowcode-component-type'; +import { IPublicTypeLowCodeComponent, IPublicTypeProCodeComponent } from '@alilc/lowcode-types'; + +describe('isLowCodeComponentType', () => { + test('should return true for a low code component type', () => { + const desc: IPublicTypeLowCodeComponent = { + // create a valid low code component description + }; + + expect(isLowCodeComponentType(desc)).toBe(true); + }); + + test('should return false for a pro code component type', () => { + const desc: IPublicTypeProCodeComponent = { + // create a valid pro code component description + package: 'pro-code' + }; + + expect(isLowCodeComponentType(desc)).toBe(false); + }); +}); diff --git a/packages/utils/test/src/check-types/is-lowcode-project-schema.test.ts b/packages/utils/test/src/check-types/is-lowcode-project-schema.test.ts new file mode 100644 index 0000000000..bb750ed88b --- /dev/null +++ b/packages/utils/test/src/check-types/is-lowcode-project-schema.test.ts @@ -0,0 +1,42 @@ +import { isLowcodeProjectSchema } from "../../../src/check-types/is-lowcode-project-schema"; + +describe("isLowcodeProjectSchema", () => { + it("should return false when data is null", () => { + const result = isLowcodeProjectSchema(null); + expect(result).toBe(false); + }); + + it("should return false when data is undefined", () => { + const result = isLowcodeProjectSchema(undefined); + expect(result).toBe(false); + }); + + it("should return false when data is not an object", () => { + const result = isLowcodeProjectSchema("not an object"); + expect(result).toBe(false); + }); + + it("should return false when componentsTree is missing", () => { + const data = { someKey: "someValue" }; + const result = isLowcodeProjectSchema(data); + expect(result).toBe(false); + }); + + it("should return false when componentsTree is an empty array", () => { + const data = { componentsTree: [] }; + const result = isLowcodeProjectSchema(data); + expect(result).toBe(false); + }); + + it("should return false when the first element of componentsTree is not a component schema", () => { + const data = { componentsTree: [{}] }; + const result = isLowcodeProjectSchema(data); + expect(result).toBe(false); + }); + + it("should return true when all conditions are met", () => { + const data = { componentsTree: [{ prop: "value", componentName: 'Component' }] }; + const result = isLowcodeProjectSchema(data); + expect(result).toBe(true); + }); +}); diff --git a/packages/utils/test/src/check-types/is-node-schema.test.ts b/packages/utils/test/src/check-types/is-node-schema.test.ts new file mode 100644 index 0000000000..b5a4e39acb --- /dev/null +++ b/packages/utils/test/src/check-types/is-node-schema.test.ts @@ -0,0 +1,43 @@ +import { isNodeSchema } from '../../../src/check-types/is-node-schema'; + +describe('isNodeSchema', () => { + // 测试正常情况 + it('should return true for valid IPublicTypeNodeSchema', () => { + const validData = { + componentName: 'Component', + isNode: false, + }; + expect(isNodeSchema(validData)).toBe(true); + }); + + // 测试 null 或 undefined + it('should return false for null or undefined', () => { + expect(isNodeSchema(null)).toBe(false); + expect(isNodeSchema(undefined)).toBe(false); + }); + + // 测试没有componentName属性的情况 + it('should return false if componentName is missing', () => { + const invalidData = { + isNode: false, + }; + expect(isNodeSchema(invalidData)).toBe(false); + }); + + // 测试isNode为true的情况 + it('should return false if isNode is true', () => { + const invalidData = { + componentName: 'Component', + isNode: true, + }; + expect(isNodeSchema(invalidData)).toBe(false); + }); + + // 测试其他数据类型的情况 + it('should return false for other data types', () => { + expect(isNodeSchema('string')).toBe(false); + expect(isNodeSchema(123)).toBe(false); + expect(isNodeSchema([])).toBe(false); + expect(isNodeSchema({})).toBe(false); + }); +}); diff --git a/packages/utils/test/src/check-types/is-node.test.ts b/packages/utils/test/src/check-types/is-node.test.ts new file mode 100644 index 0000000000..d6d8dfc03d --- /dev/null +++ b/packages/utils/test/src/check-types/is-node.test.ts @@ -0,0 +1,19 @@ +import { isNode } from '../../../src/check-types/is-node'; + +describe('isNode', () => { + it('should return true for a valid node', () => { + const node = { isNode: true }; + expect(isNode(node)).toBeTruthy(); + }); + + it('should return false for an invalid node', () => { + const node = { isNode: false }; + expect(isNode(node)).toBeFalsy(); + }); + + it('should return false for an undefined node', () => { + expect(isNode(undefined)).toBeFalsy(); + }); + + // Add more test cases if needed +}); diff --git a/packages/utils/test/src/check-types/is-procode-component-type.test.ts b/packages/utils/test/src/check-types/is-procode-component-type.test.ts new file mode 100644 index 0000000000..58f435b98a --- /dev/null +++ b/packages/utils/test/src/check-types/is-procode-component-type.test.ts @@ -0,0 +1,13 @@ +import { isProCodeComponentType } from '../../../src/check-types/is-procode-component-type'; + +describe('isProCodeComponentType', () => { + it('should return true if the given desc object contains "package" property', () => { + const desc = { package: 'packageName' }; + expect(isProCodeComponentType(desc)).toBe(true); + }); + + it('should return false if the given desc object does not contain "package" property', () => { + const desc = { name: 'componentName' }; + expect(isProCodeComponentType(desc)).toBe(false); + }); +}); diff --git a/packages/utils/test/src/check-types/is-project-schema.test.ts b/packages/utils/test/src/check-types/is-project-schema.test.ts new file mode 100644 index 0000000000..0ec3f47408 --- /dev/null +++ b/packages/utils/test/src/check-types/is-project-schema.test.ts @@ -0,0 +1,28 @@ +import { IPublicTypeProjectSchema } from "@alilc/lowcode-types"; +import { isProjectSchema } from "../../../src/check-types/is-project-schema"; + +describe("isProjectSchema", () => { + it("should return true if data has componentsTree property", () => { + const data: IPublicTypeProjectSchema = { + // ... + componentsTree: { + // ... + }, + }; + expect(isProjectSchema(data)).toBe(true); + }); + + it("should return false if data does not have componentsTree property", () => { + const data = { + // ... + }; + expect(isProjectSchema(data)).toBe(false); + }); + + it("should return false if data is null or undefined", () => { + expect(isProjectSchema(null)).toBe(false); + expect(isProjectSchema(undefined)).toBe(false); + }); + + // 更多的测试用例... +}); diff --git a/packages/utils/test/src/check-types/is-setter-config.test.ts b/packages/utils/test/src/check-types/is-setter-config.test.ts new file mode 100644 index 0000000000..eee234658d --- /dev/null +++ b/packages/utils/test/src/check-types/is-setter-config.test.ts @@ -0,0 +1,26 @@ +import { isSetterConfig } from '../../../src/check-types/is-setter-config'; + +describe('isSetterConfig', () => { + test('should return true for valid setter config', () => { + const config = { + componentName: 'MyComponent', + // Add other required properties here + }; + + expect(isSetterConfig(config)).toBe(true); + }); + + test('should return false for invalid setter config', () => { + const config = { + // Missing componentName property + }; + + expect(isSetterConfig(config)).toBe(false); + expect(isSetterConfig(null)).toBe(false); + expect(isSetterConfig(undefined)).toBe(false); + expect(isSetterConfig(0)).toBe(false); + expect(isSetterConfig(2)).toBe(false); + }); + + // Add more test cases for different scenarios you want to cover +}); diff --git a/packages/utils/test/src/check-types/is-setting-field.test.ts b/packages/utils/test/src/check-types/is-setting-field.test.ts new file mode 100644 index 0000000000..5f9bbd6239 --- /dev/null +++ b/packages/utils/test/src/check-types/is-setting-field.test.ts @@ -0,0 +1,18 @@ +import { isSettingField } from "../../../src/check-types/is-setting-field"; + +describe("isSettingField", () => { + it("should return true for an object that has isSettingField property", () => { + const obj = { isSettingField: true }; + expect(isSettingField(obj)).toBe(true); + }); + + it("should return false for an object that does not have isSettingField property", () => { + const obj = { foo: "bar" }; + expect(isSettingField(obj)).toBe(false); + }); + + it("should return false for a falsy value", () => { + const obj = null; + expect(isSettingField(obj)).toBe(false); + }); +}); diff --git a/packages/utils/test/src/check-types/is-title-config.test.ts b/packages/utils/test/src/check-types/is-title-config.test.ts new file mode 100644 index 0000000000..4aa6d219cb --- /dev/null +++ b/packages/utils/test/src/check-types/is-title-config.test.ts @@ -0,0 +1,18 @@ +import { isTitleConfig } from '../../../src/check-types/is-title-config'; + +describe('isTitleConfig', () => { + it('should return true for valid config object', () => { + const config = { title: 'My Title' }; + expect(isTitleConfig(config)).toBe(true); + }); + + it('should return false for invalid config object', () => { + const config = { title: 'My Title', type: 'i18n' , i18nData: {} }; + expect(isTitleConfig(config)).toBe(false); + }); + + it('should return false for non-object input', () => { + const config = 'invalid'; + expect(isTitleConfig(config)).toBe(false); + }); +}); diff --git a/packages/utils/test/src/clone-deep.test.ts b/packages/utils/test/src/clone-deep.test.ts new file mode 100644 index 0000000000..58fabc6f68 --- /dev/null +++ b/packages/utils/test/src/clone-deep.test.ts @@ -0,0 +1,30 @@ +import { cloneDeep } from '../../src/clone-deep'; + +describe('cloneDeep', () => { + it('should clone null', () => { + const src = null; + expect(cloneDeep(src)).toBeNull(); + }); + + it('should clone undefined', () => { + const src = undefined; + expect(cloneDeep(src)).toBeUndefined(); + }); + + it('should clone an array', () => { + const src = [1, 2, 3, 4]; + expect(cloneDeep(src)).toEqual(src); + }); + + it('should clone an object', () => { + const src = { name: 'John', age: 25 }; + expect(cloneDeep(src)).toEqual(src); + }); + + it('should deep clone nested objects', () => { + const src = { person: { name: 'John', age: 25 } }; + const cloned = cloneDeep(src); + expect(cloned).toEqual(src); + expect(cloned.person).not.toBe(src.person); + }); +}); \ No newline at end of file diff --git a/packages/utils/test/src/clone-enumerable-property.test.ts b/packages/utils/test/src/clone-enumerable-property.test.ts new file mode 100644 index 0000000000..2eff09e44c --- /dev/null +++ b/packages/utils/test/src/clone-enumerable-property.test.ts @@ -0,0 +1,30 @@ +import { cloneEnumerableProperty } from '../../src/clone-enumerable-property'; + +describe('cloneEnumerableProperty', () => { + test('should clone enumerable properties from origin to target', () => { + // Arrange + const target = {}; + const origin = { prop1: 1, prop2: 'hello', prop3: true }; + + // Act + const result = cloneEnumerableProperty(target, origin); + + // Assert + expect(result).toBe(target); + expect(result).toEqual(origin); + }); + + test('should exclude properties specified in excludePropertyNames', () => { + // Arrange + const target = {}; + const origin = { prop1: 1, prop2: 'hello', prop3: true }; + const excludePropertyNames = ['prop2']; + + // Act + const result = cloneEnumerableProperty(target, origin, excludePropertyNames); + + // Assert + expect(result).toBe(target); + expect(result).toEqual({ prop1: 1, prop3: true }); + }); +}); \ No newline at end of file diff --git a/packages/utils/test/src/create-content.test.tsx b/packages/utils/test/src/create-content.test.tsx new file mode 100644 index 0000000000..c41fb0f0da --- /dev/null +++ b/packages/utils/test/src/create-content.test.tsx @@ -0,0 +1,38 @@ +import React from 'react'; +import { createContent } from '../../src/create-content'; + +const MyComponent = () => { + return <div>MyComponent</div> +} +describe('createContent', () => { + test('should return the same content if it is a valid React element', () => { + const content = <div>Hello</div>; + const result = createContent(content); + + expect(result).toEqual(content); + }); + + test('should clone the element with props if props are provided', () => { + const content = <div></div>; + const props = { className: 'my-class' }; + const result = createContent(content, props); + + expect(result.props).toEqual(props); + }); + + test('should create an element with props if the content is a React component', () => { + const content = MyComponent; + const props = { className: 'my-class' }; + const result = createContent(content, props); + + expect(result.type).toEqual(content); + expect(result.props).toEqual(props); + }); + + test('should return the content if it is not a React element or a React component', () => { + const content = 'Hello'; + const result = createContent(content); + + expect(result).toEqual(content); + }); +}); diff --git a/packages/utils/test/src/create-defer.test.ts b/packages/utils/test/src/create-defer.test.ts new file mode 100644 index 0000000000..c6ab9207a9 --- /dev/null +++ b/packages/utils/test/src/create-defer.test.ts @@ -0,0 +1,16 @@ +import { createDefer } from '../../src/create-defer'; + +describe('createDefer', () => { + it('should resolve with given value', async () => { + const defer = createDefer<number>(); + defer.resolve(42); + const result = await defer.promise(); + expect(result).toBe(42); + }); + + it('should reject with given reason', async () => { + const defer = createDefer<number>(); + defer.reject('error'); + await expect(defer.promise()).rejects.toEqual('error'); + }); +}); diff --git a/packages/utils/test/src/is-object.test.ts b/packages/utils/test/src/is-object.test.ts new file mode 100644 index 0000000000..7ae984b8f8 --- /dev/null +++ b/packages/utils/test/src/is-object.test.ts @@ -0,0 +1,45 @@ +import { isObject, isI18NObject } from '../../src/is-object'; + +describe('isObject', () => { + it('should return true for an object', () => { + const obj = { key: 'value' }; + const result = isObject(obj); + expect(result).toBe(true); + }); + + it('should return false for null', () => { + const result = isObject(null); + expect(result).toBe(false); + }); + + it('should return false for a non-object value', () => { + const value = 42; // Not an object + const result = isObject(value); + expect(result).toBe(false); + }); +}); + +describe('isI18NObject', () => { + it('should return true for an I18N object', () => { + const i18nObject = { type: 'i18n', data: 'some data' }; + const result = isI18NObject(i18nObject); + expect(result).toBe(true); + }); + + it('should return false for a non-I18N object', () => { + const nonI18nObject = { type: 'other', data: 'some data' }; + const result = isI18NObject(nonI18nObject); + expect(result).toBe(false); + }); + + it('should return false for null', () => { + const result = isI18NObject(null); + expect(result).toBe(false); + }); + + it('should return false for a non-object value', () => { + const value = 42; // Not an object + const result = isI18NObject(value); + expect(result).toBe(false); + }); +}); diff --git a/packages/utils/test/src/is-react.test.ts b/packages/utils/test/src/is-react.test.ts deleted file mode 100644 index 74c88c9330..0000000000 --- a/packages/utils/test/src/is-react.test.ts +++ /dev/null @@ -1,38 +0,0 @@ -import React from "react"; -import { isReactComponent, wrapReactClass } from "../../src/is-react"; - -class reactDemo extends React.Component { - -} - -const reactMemo = React.memo(reactDemo); - -const reactForwardRef = React.forwardRef((props, ref): any => { - return ''; -}); - -describe('is-react-ut', () => { - it('isReactComponent', () => { - expect(isReactComponent(null)).toBeFalsy(); - expect(isReactComponent(() => {})).toBeTruthy(); - expect(isReactComponent({ - $$typeof: Symbol.for('react.memo') - })).toBeTruthy(); - expect(isReactComponent({ - $$typeof: Symbol.for('react.forward_ref') - })).toBeTruthy(); - expect(isReactComponent(reactDemo)).toBeTruthy(); - expect(isReactComponent(reactMemo)).toBeTruthy(); - expect(isReactComponent(reactForwardRef)).toBeTruthy(); - - }); - - it('wrapReactClass', () => { - const wrap = wrapReactClass(() => {}); - expect(isReactComponent(wrap)).toBeTruthy(); - - const fun = () => {}; - fun.displayName = 'mock'; - expect(wrapReactClass(fun).displayName).toBe('mock'); - }) -}) \ No newline at end of file diff --git a/packages/utils/test/src/is-react.test.tsx b/packages/utils/test/src/is-react.test.tsx new file mode 100644 index 0000000000..9ed2bd6c38 --- /dev/null +++ b/packages/utils/test/src/is-react.test.tsx @@ -0,0 +1,316 @@ +import React, { Component, createElement } from "react"; +import { + isReactComponent, + wrapReactClass, + isForwardOrMemoForward, + isMemoType, + isForwardRefType, + acceptsRef, + isReactClass, + REACT_MEMO_TYPE, + REACT_FORWARD_REF_TYPE, + } from "../../src/is-react"; + +class reactDemo extends React.Component { + +} + +const reactMemo = React.memo(reactDemo); + +const reactForwardRef = React.forwardRef((props, ref): any => { + return ''; +}); + +describe('is-react-ut', () => { + it('isReactComponent', () => { + expect(isReactComponent(null)).toBeFalsy(); + expect(isReactComponent(() => {})).toBeTruthy(); + expect(isReactComponent({ + $$typeof: Symbol.for('react.memo') + })).toBeTruthy(); + expect(isReactComponent({ + $$typeof: Symbol.for('react.forward_ref') + })).toBeTruthy(); + expect(isReactComponent(reactDemo)).toBeTruthy(); + expect(isReactComponent(reactMemo)).toBeTruthy(); + expect(isReactComponent(reactForwardRef)).toBeTruthy(); + + }); + + it('wrapReactClass', () => { + const wrap = wrapReactClass(() => {}); + expect(isReactComponent(wrap)).toBeTruthy(); + + const fun = () => {}; + fun.displayName = 'mock'; + expect(wrapReactClass(fun).displayName).toBe('mock'); + }) +}) + +describe('wrapReactClass', () => { + it('should wrap a FunctionComponent', () => { + // Create a mock FunctionComponent + const MockComponent: React.FunctionComponent = (props) => { + return <div>{props.children}</div>; + }; + + // Wrap the FunctionComponent using wrapReactClass + const WrappedComponent = wrapReactClass(MockComponent); + const instance = new WrappedComponent(); + + // Check if the WrappedComponent extends Component + expect(instance instanceof React.Component).toBe(true); + }); + + it('should render the FunctionComponent with props', () => { + // Create a mock FunctionComponent + const MockComponent: React.FunctionComponent = (props) => { + return <div>{props.children}</div>; + }; + + MockComponent.displayName = 'FunctionComponent'; + + // Wrap the FunctionComponent using wrapReactClass + const WrappedComponent = wrapReactClass(MockComponent); + + // Create some test props + const testProps = { prop1: 'value1', prop2: 'value2' }; + + // Render the WrappedComponent with test props + const rendered = createElement(WrappedComponent, testProps, 'Child Text'); + + // Check if the WrappedComponent renders the FunctionComponent with props + expect(rendered).toMatchSnapshot(); + }); +}); + +describe('isReactComponent', () => { + it('should identify a class component as a React component', () => { + class ClassComponent extends React.Component { + render() { + return <div>Class Component</div>; + } + } + + expect(isReactComponent(ClassComponent)).toBe(true); + }); + + it('should identify a functional component as a React component', () => { + const FunctionalComponent = () => { + return <div>Functional Component</div>; + }; + + expect(isReactComponent(FunctionalComponent)).toBe(true); + }); + + it('should identify a forward ref component as a React component', () => { + const ForwardRefComponent = React.forwardRef((props, ref) => { + return <div ref={ref}>Forward Ref Component</div>; + }); + + expect(isReactComponent(ForwardRefComponent)).toBe(true); + }); + + it('should identify a memo component as a React component', () => { + const MemoComponent = React.memo(() => { + return <div>Memo Component</div>; + }); + + expect(isReactComponent(MemoComponent)).toBe(true); + }); + + it('should return false for non-React components', () => { + const plainObject = { prop: 'value' }; + const notAComponent = 'Not a component'; + + expect(isReactComponent(plainObject)).toBe(false); + expect(isReactComponent(notAComponent)).toBe(false); + }); + + it('should return false for null or undefined', () => { + const nullValue = null; + const undefinedValue = undefined; + + expect(isReactComponent(nullValue)).toBe(false); + expect(isReactComponent(undefinedValue)).toBe(false); + }); +}); + +describe('isForwardOrMemoForward', () => { + it('should return true for a forwardRef component', () => { + const forwardRefComponent = React.forwardRef(() => { + return <div>ForwardRef Component</div>; + }); + + expect(isForwardOrMemoForward(forwardRefComponent)).toBe(true); + }); + + it('should return true for a memoized forwardRef component', () => { + const forwardRefComponent = React.forwardRef(() => { + return <div>ForwardRef Component</div>; + }); + + const memoizedComponent = React.memo(forwardRefComponent); + + expect(isForwardOrMemoForward(memoizedComponent)).toBe(true); + }); + + it('should return false for a memoized component that is not a forwardRef', () => { + const memoizedComponent = React.memo(() => { + return <div>Memoized Component</div>; + }); + + expect(isForwardOrMemoForward(memoizedComponent)).toBe(false); + }); + + it('should return false for a plain object', () => { + const plainObject = { prop: 'value' }; + + expect(isForwardOrMemoForward(plainObject)).toBe(false); + }); + + it('should return false for null or undefined', () => { + const nullValue = null; + const undefinedValue = undefined; + + expect(isForwardOrMemoForward(nullValue)).toBe(false); + expect(isForwardOrMemoForward(undefinedValue)).toBe(false); + }); +}); + +describe('isMemoType', () => { + it('should return true for an object with $$typeof matching REACT_MEMO_TYPE', () => { + const memoTypeObject = { $$typeof: REACT_MEMO_TYPE }; + + expect(isMemoType(memoTypeObject)).toBe(true); + }); + + it('should return false for an object with $$typeof not matching REACT_MEMO_TYPE', () => { + const otherTypeObject = { $$typeof: Symbol.for('other.type') }; + + expect(isMemoType(otherTypeObject)).toBe(false); + }); + + it('should return false for an object with no $$typeof property', () => { + const noTypeObject = { key: 'value' }; + + expect(isMemoType(noTypeObject)).toBe(false); + }); + + it('should return false for null or undefined', () => { + const nullValue = null; + const undefinedValue = undefined; + + expect(isMemoType(nullValue)).toBe(false); + expect(isMemoType(undefinedValue)).toBe(false); + }); +}); + +describe('isForwardRefType', () => { + it('should return true for an object with $$typeof matching REACT_FORWARD_REF_TYPE', () => { + const forwardRefTypeObject = { $$typeof: REACT_FORWARD_REF_TYPE }; + + expect(isForwardRefType(forwardRefTypeObject)).toBe(true); + }); + + it('should return false for an object with $$typeof not matching REACT_FORWARD_REF_TYPE', () => { + const otherTypeObject = { $$typeof: Symbol.for('other.type') }; + + expect(isForwardRefType(otherTypeObject)).toBe(false); + }); + + it('should return false for an object with no $$typeof property', () => { + const noTypeObject = { key: 'value' }; + + expect(isForwardRefType(noTypeObject)).toBe(false); + }); + + it('should return false for null or undefined', () => { + const nullValue = null; + const undefinedValue = undefined; + + expect(isForwardRefType(nullValue)).toBe(false); + expect(isForwardRefType(undefinedValue)).toBe(false); + }); +}); + +describe('acceptsRef', () => { + it('should return true for an object with isReactComponent in its prototype', () => { + const objWithIsReactComponent = { + prototype: { + isReactComponent: true, + }, + }; + + expect(acceptsRef(objWithIsReactComponent)).toBe(true); + }); + + it('should return true for an object that is forwardRef or memoized forwardRef', () => { + const forwardRefObject = React.forwardRef(() => { + return null; + }); + + const memoizedForwardRefObject = React.memo(forwardRefObject); + + expect(acceptsRef(forwardRefObject)).toBe(true); + expect(acceptsRef(memoizedForwardRefObject)).toBe(true); + }); + + it('should return false for an object without isReactComponent in its prototype', () => { + const objWithoutIsReactComponent = { + prototype: { + someOtherProperty: true, + }, + }; + + expect(acceptsRef(objWithoutIsReactComponent)).toBe(false); + }); + + it('should return false for null or undefined', () => { + const nullValue = null; + const undefinedValue = undefined; + + expect(acceptsRef(nullValue)).toBe(false); + expect(acceptsRef(undefinedValue)).toBe(false); + }); +}); + +describe('isReactClass', () => { + it('should return true for an object with isReactComponent in its prototype', () => { + class ReactClassComponent extends Component { + render() { + return null; + } + } + + expect(isReactClass(ReactClassComponent)).toBe(true); + }); + + it('should return true for an object with Component in its prototype chain', () => { + class CustomComponent extends Component { + render() { + return null; + } + } + + expect(isReactClass(CustomComponent)).toBe(true); + }); + + it('should return false for an object without isReactComponent in its prototype', () => { + class NonReactComponent { + render() { + return null; + } + } + + expect(isReactClass(NonReactComponent)).toBe(false); + }); + + it('should return false for null or undefined', () => { + const nullValue = null; + const undefinedValue = undefined; + + expect(isReactClass(nullValue)).toBe(false); + expect(isReactClass(undefinedValue)).toBe(false); + }); +}); \ No newline at end of file diff --git a/packages/utils/test/src/is-shaken.test.ts b/packages/utils/test/src/is-shaken.test.ts new file mode 100644 index 0000000000..35a27af5f6 --- /dev/null +++ b/packages/utils/test/src/is-shaken.test.ts @@ -0,0 +1,45 @@ +import { isShaken } from '../../src/is-shaken'; + +describe('isShaken', () => { + it('should return true if e1 has shaken property', () => { + const e1: any = { shaken: true }; + const e2: MouseEvent | DragEvent = { target: null } as MouseEvent | DragEvent; + + expect(isShaken(e1, e2)).toBe(true); + }); + + it('should return true if e1.target and e2.target are different', () => { + const e1: MouseEvent | DragEvent = { target: {} } as MouseEvent | DragEvent; + const e2: MouseEvent | DragEvent = { target: {} } as MouseEvent | DragEvent; + + expect(isShaken(e1, e2)).toBe(true); + }); + + it('should return false if e1 and e2 targets are the same and distance is less than SHAKE_DISTANCE', () => { + const target = {}; + const e1: MouseEvent | DragEvent = { target: target } as MouseEvent | DragEvent; + const e2: MouseEvent | DragEvent = { target: target } as MouseEvent | DragEvent; + + // Assuming SHAKE_DISTANCE is 100 + e1.clientY = 50; + e2.clientY = 50; + + e1.clientX = 60; + e2.clientX = 60; + + expect(isShaken(e1, e2)).toBe(false); + }); + + it('should return true if e1 and e2 targets are the same and distance is greater than SHAKE_DISTANCE', () => { + const e1: MouseEvent | DragEvent = { target: {} } as MouseEvent | DragEvent; + const e2: MouseEvent | DragEvent = { target: {} } as MouseEvent | DragEvent; + + // Assuming SHAKE_DISTANCE is 100 + e1.clientY = 50; + e1.clientX = 50; + e2.clientY = 200; + e2.clientX = 200; + + expect(isShaken(e1, e2)).toBe(true); + }); +}); diff --git a/packages/utils/test/src/misc.test.ts b/packages/utils/test/src/misc.test.ts index 8873dc4c80..2514661508 100644 --- a/packages/utils/test/src/misc.test.ts +++ b/packages/utils/test/src/misc.test.ts @@ -1,4 +1,321 @@ -import { shouldUseVariableSetter } from '../../src/misc'; +import { + isVariable, + isUseI18NSetter, + convertToI18NObject, + isString, + waitForThing, + arrShallowEquals, + isFromVC, + executePendingFn, + compatStage, + invariant, + isRegExp, + shouldUseVariableSetter, +} from '../../src/misc'; +import { IPublicModelComponentMeta } from '@alilc/lowcode-types'; + +describe('isVariable', () => { + it('should return true for a variable object', () => { + const variable = { type: 'variable', variable: 'foo', value: 'bar' }; + const result = isVariable(variable); + expect(result).toBe(true); + }); + + it('should return false for non-variable objects', () => { + const obj = { type: 'object' }; + const result = isVariable(obj); + expect(result).toBe(false); + }); +}); + +describe('isUseI18NSetter', () => { + it('should return true for a property with I18nSetter', () => { + const prototype = { options: { configure: [{ name: 'propName', setter: { type: { displayName: 'I18nSetter' } } }] } }; + const propName = 'propName'; + const result = isUseI18NSetter(prototype, propName); + expect(result).toBe(true); + }); + + it('should return false for a property without I18nSetter', () => { + const prototype = { options: { configure: [{ name: 'propName', setter: { type: { displayName: 'OtherSetter' } } }] } }; + const propName = 'propName'; + const result = isUseI18NSetter(prototype, propName); + expect(result).toBe(false); + }); +}); + +describe('convertToI18NObject', () => { + it('should return the input if it is already an I18N object', () => { + const i18nObject = { type: 'i18n', use: 'en', en: 'Hello' }; + const result = convertToI18NObject(i18nObject); + expect(result).toEqual(i18nObject); + }); + + it('should convert a string to an I18N object', () => { + const inputString = 'Hello'; + const result = convertToI18NObject(inputString); + const expectedOutput = { type: 'i18n', use: 'zh-CN', 'zh-CN': inputString }; + expect(result).toEqual(expectedOutput); + }); +}); + +describe('isString', () => { + it('should return true for a string', () => { + const stringValue = 'Hello, world!'; + const result = isString(stringValue); + expect(result).toBe(true); + }); + + it('should return true for an empty string', () => { + const emptyString = ''; + const result = isString(emptyString); + expect(result).toBe(true); + }); + + it('should return false for a number', () => { + const numberValue = 42; // Not a string + const result = isString(numberValue); + expect(result).toBe(false); + }); + + it('should return false for an object', () => { + const objectValue = { key: 'value' }; // Not a string + const result = isString(objectValue); + expect(result).toBe(false); + }); + + it('should return false for null', () => { + const result = isString(null); + expect(result).toBe(false); + }); + + it('should return false for undefined', () => { + const undefinedValue = undefined; + const result = isString(undefinedValue); + expect(result).toBe(false); + }); + + it('should return false for a boolean', () => { + const booleanValue = true; // Not a string + const result = isString(booleanValue); + expect(result).toBe(false); + }); +}); + +describe('waitForThing', () => { + it('should resolve immediately if the thing is available', async () => { + const obj = { prop: 'value' }; + const path = 'prop'; + const result = await waitForThing(obj, path); + expect(result).toBe('value'); + }); + + it('should resolve after a delay if the thing becomes available', async () => { + const obj = { prop: undefined }; + const path = 'prop'; + const delay = 100; // Adjust the delay as needed + setTimeout(() => { + obj.prop = 'value'; + }, delay); + + const result = await waitForThing(obj, path); + expect(result).toBe('value'); + }); +}); + +describe('arrShallowEquals', () => { + it('should return true for two empty arrays', () => { + const arr1 = []; + const arr2 = []; + const result = arrShallowEquals(arr1, arr2); + expect(result).toBe(true); + }); + + it('should return true for two arrays with the same elements in the same order', () => { + const arr1 = [1, 2, 3]; + const arr2 = [1, 2, 3]; + const result = arrShallowEquals(arr1, arr2); + expect(result).toBe(true); + }); + + it('should return true for two arrays with the same elements in a different order', () => { + const arr1 = [1, 2, 3]; + const arr2 = [3, 2, 1]; + const result = arrShallowEquals(arr1, arr2); + expect(result).toBe(true); + }); + + it('should return false for two arrays with different lengths', () => { + const arr1 = [1, 2, 3]; + const arr2 = [1, 2]; + const result = arrShallowEquals(arr1, arr2); + expect(result).toBe(false); + }); + + it('should return false for one array and a non-array', () => { + const arr1 = [1, 2, 3]; + const nonArray = 'not an array'; + const result = arrShallowEquals(arr1, nonArray); + expect(result).toBe(false); + }); + + it('should return false for two arrays with different elements', () => { + const arr1 = [1, 2, 3]; + const arr2 = [3, 4, 5]; + const result = arrShallowEquals(arr1, arr2); + expect(result).toBe(false); + }); + + it('should return true for arrays with duplicate elements', () => { + const arr1 = [1, 2, 2, 3]; + const arr2 = [2, 3, 3, 1]; + const result = arrShallowEquals(arr1, arr2); + expect(result).toBe(true); + }); +}); + +describe('isFromVC', () => { + it('should return true when advanced configuration is present', () => { + // Create a mock meta object with advanced configuration + const meta: IPublicModelComponentMeta = { + getMetadata: () => ({ configure: { advanced: true } }), + }; + + const result = isFromVC(meta); + + expect(result).toBe(true); + }); + + it('should return false when advanced configuration is not present', () => { + // Create a mock meta object without advanced configuration + const meta: IPublicModelComponentMeta = { + getMetadata: () => ({ configure: { advanced: false } }), + }; + + const result = isFromVC(meta); + + expect(result).toBe(false); + }); + + it('should return false when meta is undefined', () => { + const meta: IPublicModelComponentMeta | undefined = undefined; + + const result = isFromVC(meta); + + expect(result).toBe(false); + }); + + it('should return false when meta does not have configure information', () => { + // Create a mock meta object without configure information + const meta: IPublicModelComponentMeta = { + getMetadata: () => ({}), + }; + + const result = isFromVC(meta); + + expect(result).toBe(false); + }); + + it('should return false when configure.advanced is not present', () => { + // Create a mock meta object with incomplete configure information + const meta: IPublicModelComponentMeta = { + getMetadata: () => ({ configure: {} }), + }; + + const result = isFromVC(meta); + + expect(result).toBe(false); + }); +}); + +describe('executePendingFn', () => { + it('should execute the provided function after the specified timeout', async () => { + // Mock the function to execute + const fn = jest.fn(); + + // Call executePendingFn with the mocked function and a short timeout + executePendingFn(fn, 100); + + // Ensure the function has not been called immediately + expect(fn).not.toHaveBeenCalled(); + + // Wait for the specified timeout + await new Promise(resolve => setTimeout(resolve, 100)); + + // Ensure the function has been called after the timeout + expect(fn).toHaveBeenCalled(); + }); + + it('should execute the provided function with a default timeout if not specified', async () => { + // Mock the function to execute + const fn = jest.fn(); + + // Call executePendingFn with the mocked function without specifying a timeout + executePendingFn(fn); + + // Ensure the function has not been called immediately + expect(fn).not.toHaveBeenCalled(); + + // Wait for the default timeout (2000 milliseconds) + await new Promise(resolve => setTimeout(resolve, 2000)); + + // Ensure the function has been called after the default timeout + expect(fn).toHaveBeenCalled(); + }); +}); + +describe('compatStage', () => { + it('should convert a number to an enum stage', () => { + const result = compatStage(3); + expect(result).toBe('save'); + }); + + it('should warn about the deprecated usage', () => { + const warnSpy = jest.spyOn(console, 'warn'); + const result = compatStage(2); + expect(result).toBe('serilize'); + expect(warnSpy).toHaveBeenCalledWith( + 'stage 直接指定为数字的使用方式已经过时,将在下一版本移除,请直接使用 IPublicEnumTransformStage.Render|Serilize|Save|Clone|Init|Upgrade' + ); + warnSpy.mockRestore(); + }); + + it('should return the enum stage if it is already an enum', () => { + const result = compatStage('render'); + expect(result).toBe('render'); + }); +}); + +describe('invariant', () => { + it('should not throw an error if the check is true', () => { + expect(() => invariant(true, 'Test invariant', 'thing')).not.toThrow(); + }); + + it('should throw an error if the check is false', () => { + expect(() => invariant(false, 'Test invariant', 'thing')).toThrowError( + "Invariant failed: Test invariant in 'thing'" + ); + }); +}); + +describe('isRegExp', () => { + it('should return true for a valid RegExp', () => { + const regex = /test/; + const result = isRegExp(regex); + expect(result).toBe(true); + }); + + it('should return false for a non-RegExp object', () => { + const nonRegExp = { test: /test/ }; + const result = isRegExp(nonRegExp); + expect(result).toBe(false); + }); + + it('should return false for null', () => { + const result = isRegExp(null); + expect(result).toBe(false); + }); +}); it('shouldUseVariableSetter', () => { expect(shouldUseVariableSetter(false, true)).toBeFalsy(); diff --git a/packages/utils/test/src/navtive-selection.test.ts b/packages/utils/test/src/navtive-selection.test.ts new file mode 100644 index 0000000000..f45d0e1b2a --- /dev/null +++ b/packages/utils/test/src/navtive-selection.test.ts @@ -0,0 +1,18 @@ +import { setNativeSelection, nativeSelectionEnabled } from '../../src/navtive-selection'; + +describe('setNativeSelection', () => { + beforeEach(() => { + // 在每个测试运行之前重置nativeSelectionEnabled的值 + setNativeSelection(true); + }); + + test('should enable native selection', () => { + setNativeSelection(true); + expect(nativeSelectionEnabled).toBe(true); + }); + + test('should disable native selection', () => { + setNativeSelection(false); + expect(nativeSelectionEnabled).toBe(false); + }); +}); diff --git a/packages/utils/test/src/schema.test.ts b/packages/utils/test/src/schema.test.ts index 138dd7a82e..8d03f58118 100644 --- a/packages/utils/test/src/schema.test.ts +++ b/packages/utils/test/src/schema.test.ts @@ -1,4 +1,132 @@ -import { compatibleLegaoSchema } from '../../src/schema'; +import { + compatibleLegaoSchema, + getNodeSchemaById, + applyActivities, +} from '../../src/schema'; +import { ActivityType } from '@alilc/lowcode-types'; + +describe('compatibleLegaoSchema', () => { + it('should handle null input', () => { + const result = compatibleLegaoSchema(null); + expect(result).toBeNull(); + }); + + it('should convert Legao schema to JSExpression', () => { + // Create your test input + const legaoSchema = { + type: 'LegaoType', + source: 'LegaoSource', + compiled: 'LegaoCompiled', + }; + const result = compatibleLegaoSchema(legaoSchema); + + // Define the expected output + const expectedOutput = { + type: 'JSExpression', + value: 'LegaoCompiled', + extType: 'function', + }; + + // Assert that the result matches the expected output + expect(result).toEqual(expectedOutput); + }); + + // Add more test cases for other scenarios +}); + +describe('getNodeSchemaById', () => { + it('should find a node in the schema', () => { + // Create your test schema and node ID + const testSchema = { + id: 'root', + children: [ + { + id: 'child1', + children: [ + { + id: 'child1.1', + }, + ], + }, + ], + }; + const nodeId = 'child1.1'; + + const result = getNodeSchemaById(testSchema, nodeId); + + // Define the expected output + const expectedOutput = { + id: 'child1.1', + }; + + // Assert that the result matches the expected output + expect(result).toEqual(expectedOutput); + }); + + // Add more test cases for other scenarios +}); + +describe('applyActivities', () => { + it('should apply ADD activity', () => { + // Create your test schema and activities + const testSchema = { + id: 'root', + children: [ + { + id: 'child1', + children: [ + { + id: 'child1.1', + }, + ], + }, + ], + }; + const activities = [ + { + type: ActivityType.ADDED, + payload: { + location: { + parent: { + nodeId: 'child1', + index: 0, + }, + }, + schema: { + id: 'newChild', + }, + }, + }, + ]; + + const result = applyActivities(testSchema, activities); + + // Define the expected output + const expectedOutput = { + id: 'root', + children: [ + { + id: 'child1', + children: [ + { + id: 'newChild', + }, + { + id: 'child1.1', + }, + ], + }, + ], + }; + + // Assert that the result matches the expected output + expect(result).toEqual(expectedOutput); + }); + + // Add more test cases for other activity types and scenarios +}); + + describe('Schema Ut', () => { it('props', () => { const schema = { diff --git a/packages/utils/test/src/script.test.ts b/packages/utils/test/src/script.test.ts new file mode 100644 index 0000000000..d3d4ffd59a --- /dev/null +++ b/packages/utils/test/src/script.test.ts @@ -0,0 +1,47 @@ +import { + evaluate, + evaluateExpression, + newFunction, +} from '../../src/script'; + +describe('evaluate', () => { + test('should evaluate the given script', () => { + const script = 'console.log("Hello, world!");'; + global.console = { log: jest.fn() }; + + evaluate(script); + + expect(global.console.log).toHaveBeenCalledWith('Hello, world!'); + }); +}); + +describe('evaluateExpression', () => { + test('should evaluate the given expression', () => { + const expr = 'return 1 + 2'; + + const result = evaluateExpression(expr); + + expect(result).toBe(3); + }); +}); + +describe('newFunction', () => { + test('should create a new function with the given arguments and code', () => { + const args = 'a, b'; + const code = 'return a + b'; + + const result = newFunction(args, code); + + expect(result).toBeInstanceOf(Function); + expect(result(1, 2)).toBe(3); + }); + + test('should return null if an error occurs', () => { + const args = 'a, b'; + const code = 'return a +;'; // Invalid code + + const result = newFunction(args, code); + + expect(result).toBeNull(); + }); +}); diff --git a/packages/utils/test/src/svg-icon.test.tsx b/packages/utils/test/src/svg-icon.test.tsx new file mode 100644 index 0000000000..bbb6e18b7c --- /dev/null +++ b/packages/utils/test/src/svg-icon.test.tsx @@ -0,0 +1,35 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { SVGIcon, IconProps } from '../../src/svg-icon'; + +describe('SVGIcon', () => { + it('should render SVG element with correct size', () => { + const iconProps: IconProps = { + size: 'small', + viewBox: '0 0 24 24', + }; + + const { container } = render(<SVGIcon {...iconProps} />); + + const svgElement = container.querySelector('svg'); + + expect(svgElement).toHaveAttribute('width', '12'); + expect(svgElement).toHaveAttribute('height', '12'); + }); + + it('should render SVG element with custom size', () => { + const iconProps: IconProps = { + size: 24, + viewBox: '0 0 24 24', + }; + + const { container } = render(<SVGIcon {...iconProps} />); + + const svgElement = container.querySelector('svg'); + + expect(svgElement).toHaveAttribute('width', '24'); + expect(svgElement).toHaveAttribute('height', '24'); + }); + + // Add more tests for other scenarios if needed +}); diff --git a/packages/utils/test/src/transaction-manager.test.ts b/packages/utils/test/src/transaction-manager.test.ts new file mode 100644 index 0000000000..42c7fa8bf0 --- /dev/null +++ b/packages/utils/test/src/transaction-manager.test.ts @@ -0,0 +1,58 @@ +import { transactionManager } from '../../src/transaction-manager'; +import { IPublicEnumTransitionType } from '@alilc/lowcode-types'; + +const type = IPublicEnumTransitionType.REPAINT; + +describe('TransactionManager', () => { + let fn1: jest.Mock; + let fn2: jest.Mock; + + beforeEach(() => { + fn1 = jest.fn(); + fn2 = jest.fn(); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + test('executeTransaction should emit startTransaction and endTransaction events', () => { + const startTransactionSpy = jest.spyOn(transactionManager.emitter, 'emit'); + const endTransactionSpy = jest.spyOn(transactionManager.emitter, 'emit'); + + transactionManager.executeTransaction(() => { + // Perform some action within the transaction + }); + + expect(startTransactionSpy).toHaveBeenCalledWith(`[${type}]startTransaction`); + expect(endTransactionSpy).toHaveBeenCalledWith(`[${type}]endTransaction`); + }); + + test('onStartTransaction should register the provided function for startTransaction event', () => { + const offSpy = jest.spyOn(transactionManager.emitter, 'off'); + + const offFunction = transactionManager.onStartTransaction(fn1); + + expect(transactionManager.emitter.listenerCount(`[${type}]startTransaction`)).toBe(1); + expect(offSpy).not.toHaveBeenCalled(); + + offFunction(); + + expect(transactionManager.emitter.listenerCount(`[${type}]startTransaction`)).toBe(0); + expect(offSpy).toHaveBeenCalledWith(`[${type}]startTransaction`, fn1); + }); + + test('onEndTransaction should register the provided function for endTransaction event', () => { + const offSpy = jest.spyOn(transactionManager.emitter, 'off'); + + const offFunction = transactionManager.onEndTransaction(fn2); + + expect(transactionManager.emitter.listenerCount(`[${type}]endTransaction`)).toBe(1); + expect(offSpy).not.toHaveBeenCalled(); + + offFunction(); + + expect(transactionManager.emitter.listenerCount(`[${type}]endTransaction`)).toBe(0); + expect(offSpy).toHaveBeenCalledWith(`[${type}]endTransaction`, fn2); + }); +}); diff --git a/packages/utils/test/src/unique-id.test.ts b/packages/utils/test/src/unique-id.test.ts new file mode 100644 index 0000000000..2b4b6e9e04 --- /dev/null +++ b/packages/utils/test/src/unique-id.test.ts @@ -0,0 +1,11 @@ +import { uniqueId } from '../../src/unique-id'; + +test('uniqueId should return a unique id with prefix', () => { + const id = uniqueId('test'); + expect(id.startsWith('test')).toBeTruthy(); +}); + +test('uniqueId should return a unique id without prefix', () => { + const id = uniqueId(); + expect(id).not.toBeFalsy(); +}); From 151748dbab0989555c1161721044ad4a2d29a2ff Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 13 Nov 2023 13:36:07 +0800 Subject: [PATCH 058/219] docs: add before start doc --- docs/docs/guide/quickStart/demo.md | 2 +- docs/docs/guide/quickStart/intro.md | 17 ++++++++++++++++- docs/docs/guide/quickStart/start.md | 2 +- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/docs/docs/guide/quickStart/demo.md b/docs/docs/guide/quickStart/demo.md index a05a42486d..ee76d5aa1b 100644 --- a/docs/docs/guide/quickStart/demo.md +++ b/docs/docs/guide/quickStart/demo.md @@ -1,6 +1,6 @@ --- title: 试用低代码引擎 Demo -sidebar_position: 1 +sidebar_position: 2 --- ## 访问地址 diff --git a/docs/docs/guide/quickStart/intro.md b/docs/docs/guide/quickStart/intro.md index 661f5912f7..b65baac269 100644 --- a/docs/docs/guide/quickStart/intro.md +++ b/docs/docs/guide/quickStart/intro.md @@ -1,6 +1,6 @@ --- title: 简介 -sidebar_position: 0 +sidebar_position: 1 --- # 阿里低代码引擎简介 @@ -46,3 +46,18 @@ sidebar_position: 0 **低代码设计器研发框架** 低代码引擎的核心是设计器,通过扩展、周边生态等可以产出各式各样的设计器。它不是一套可以适合所有人的低代码平台,而是帮助低代码平台的开发者,快速生产低代码平台的工具。 + +## 寻找适合您的低代码解决方案 + +帮助用户根据个人或企业需求选择合适的低代码产品。 + +| 特性/产品 | 低代码引擎 | Lab平台 | UIPaaS | +|-----------------|-----------------------------------------|-----------------------------------------|--------------------------------------------| +| **适用用户** | 前端开发者 | 需要快速搭建应用/页面的用户 | 企业用户,需要大规模部署低代码解决方案的组织 | +| **产品特点** | 设计器研发框架,适合定制开发 | 低代码平台, 可视化操作界面,易于上手 | 低代码平台孵化器,企业级功能 | +| **使用场景** | 定制和开发低代码平台的设计器部分 | 通过可视化, 快速开发应用或页面 | 帮助具有一定规模软件研发团队的的企业低成本定制低代码平台 | +| **产品关系** | 开源产品 | 基于UIPaaS技术实现, 展示了UIPaaS的部分能力 | 提供完整的低代码平台解决方案,商业产品 | +| **收费情况** | 免费 | 可免费使用(有额度限制),不提供私有化部署售卖 | 仅提供私有化部署售卖 | +| **官方网站** | [低代码引擎官网](https://lowcode-engine.cn/) | [Lab平台官网](https://lab.lowcode-engine.cn/) | [UIPaaS官网](https://uipaas.net/) | + +*注:请根据您的具体需求和条件选择合适的产品。如需更详细的信息,请访问各产品的官方网站。* diff --git a/docs/docs/guide/quickStart/start.md b/docs/docs/guide/quickStart/start.md index b2b728b9fe..356f501769 100644 --- a/docs/docs/guide/quickStart/start.md +++ b/docs/docs/guide/quickStart/start.md @@ -1,5 +1,5 @@ --- -sidebar_position: 2 +sidebar_position: 3 title: 快速开始 --- From ef6a203a45ae7d8d0d4708bac28d36d10d7d4b07 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Mon, 13 Nov 2023 14:09:58 +0800 Subject: [PATCH 059/219] chore(docs): publish docs 1.1.16 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 27d1a17d04..c206cdf16a 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.1.15", + "version": "1.1.16", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 9108e8cfabdb442064f43be0533538ebbaff7f4a Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 13 Nov 2023 18:46:17 +0800 Subject: [PATCH 060/219] feat(types): add IPublicTypeInstanceOf to prop-types --- packages/types/src/shell/type/prop-types.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/types/src/shell/type/prop-types.ts b/packages/types/src/shell/type/prop-types.ts index a3344b0591..22d84c86fc 100644 --- a/packages/types/src/shell/type/prop-types.ts +++ b/packages/types/src/shell/type/prop-types.ts @@ -3,7 +3,7 @@ import { IPublicTypePropConfig } from './'; export type IPublicTypePropType = IPublicTypeBasicType | IPublicTypeRequiredType | IPublicTypeComplexType; export type IPublicTypeBasicType = 'array' | 'bool' | 'func' | 'number' | 'object' | 'string' | 'node' | 'element' | 'any'; -export type IPublicTypeComplexType = IPublicTypeOneOf | IPublicTypeOneOfType | IPublicTypeArrayOf | IPublicTypeObjectOf | IPublicTypeShape | IPublicTypeExact; +export type IPublicTypeComplexType = IPublicTypeOneOf | IPublicTypeOneOfType | IPublicTypeArrayOf | IPublicTypeObjectOf | IPublicTypeShape | IPublicTypeExact | IPublicTypeInstanceOf; export interface IPublicTypeRequiredType { type: IPublicTypeBasicType; @@ -40,3 +40,9 @@ export interface IPublicTypeExact { value: IPublicTypePropConfig[]; isRequired?: boolean; } + +export interface IPublicTypeInstanceOf { + type: 'instanceOf'; + value: IPublicTypePropConfig; + isRequired?: boolean; +} From 1020f98756c6a4886f8dd755c5fca3ff6f374876 Mon Sep 17 00:00:00 2001 From: beautiful-boyyy <66351806+beautiful-boyyy@users.noreply.github.com> Date: Tue, 14 Nov 2023 09:48:36 +0800 Subject: [PATCH 061/219] chore: remove useless code (#2643) --- .../editor-skeleton/src/components/widget-views/index.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/editor-skeleton/src/components/widget-views/index.tsx b/packages/editor-skeleton/src/components/widget-views/index.tsx index 513fc1bdd6..ba49b3d1ab 100644 --- a/packages/editor-skeleton/src/components/widget-views/index.tsx +++ b/packages/editor-skeleton/src/components/widget-views/index.tsx @@ -232,12 +232,8 @@ export class PanelView extends Component<{ this.lastVisible = currentVisible; if (this.lastVisible) { panel.skeleton.postEvent(SkeletonEvents.PANEL_SHOW, panel.name, panel); - // FIXME! remove this line - panel.skeleton.postEvent('leftPanel.show' as any, panel.name, panel); } else { panel.skeleton.postEvent(SkeletonEvents.PANEL_HIDE, panel.name, panel); - // FIXME! remove this line - panel.skeleton.postEvent('leftPanel.hide' as any, panel.name, panel); } } } From b697ea9ad4399a90cf2560b45beb4ae669700fbc Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 14 Nov 2023 09:55:58 +0800 Subject: [PATCH 062/219] feat(render-core): update logger to console --- .../designer/src/builtin-simulator/index.ts | 1 + .../builtin-simulator/utils/parse-metadata.ts | 6 ++- packages/renderer-core/babel.config.js | 1 + packages/renderer-core/src/hoc/leaf.tsx | 3 +- packages/renderer-core/src/renderer/addon.tsx | 3 +- packages/renderer-core/src/renderer/base.tsx | 14 +++---- packages/renderer-core/src/renderer/temp.tsx | 3 +- packages/renderer-core/src/utils/common.ts | 6 +-- .../renderer-core/src/utils/data-helper.ts | 10 ++--- .../renderer-core/tests/utils/common.test.ts | 40 ++++++++++++++++++- .../tests/utils/data-helper.test.ts | 10 ----- 11 files changed, 66 insertions(+), 31 deletions(-) create mode 100644 packages/renderer-core/babel.config.js diff --git a/packages/designer/src/builtin-simulator/index.ts b/packages/designer/src/builtin-simulator/index.ts index 6bcee7eb76..6977fd66c6 100644 --- a/packages/designer/src/builtin-simulator/index.ts +++ b/packages/designer/src/builtin-simulator/index.ts @@ -2,3 +2,4 @@ export * from './host'; export * from './host-view'; export * from './renderer'; export * from './live-editing/live-editing'; +export { LowcodeTypes } from './utils/parse-metadata'; diff --git a/packages/designer/src/builtin-simulator/utils/parse-metadata.ts b/packages/designer/src/builtin-simulator/utils/parse-metadata.ts index b84e4e6985..5c81340a14 100644 --- a/packages/designer/src/builtin-simulator/utils/parse-metadata.ts +++ b/packages/designer/src/builtin-simulator/utils/parse-metadata.ts @@ -46,13 +46,15 @@ function define(propType: any = PropTypes.any, lowcodeType: string | object = {} return lowcodeCheckType; } -const LowcodeTypes: any = { +export const LowcodeTypes: any = { ...PropTypes, define, }; (window as any).PropTypes = LowcodeTypes; -(window as any).React.PropTypes = LowcodeTypes; +if ((window as any).React) { + (window as any).React.PropTypes = LowcodeTypes; +} // override primitive type checkers primitiveTypes.forEach((type) => { diff --git a/packages/renderer-core/babel.config.js b/packages/renderer-core/babel.config.js new file mode 100644 index 0000000000..c5986f2bc0 --- /dev/null +++ b/packages/renderer-core/babel.config.js @@ -0,0 +1 @@ +module.exports = require('../../babel.config'); \ No newline at end of file diff --git a/packages/renderer-core/src/hoc/leaf.tsx b/packages/renderer-core/src/hoc/leaf.tsx index 1ff91cb147..2bb3c0b368 100644 --- a/packages/renderer-core/src/hoc/leaf.tsx +++ b/packages/renderer-core/src/hoc/leaf.tsx @@ -4,6 +4,7 @@ import { isReactComponent, cloneEnumerableProperty } from '@alilc/lowcode-utils' import { debounce } from '../utils/common'; import adapter from '../adapter'; import * as types from '../types/index'; +import logger from '../utils/logger'; export interface IComponentHocInfo { schema: any; @@ -183,7 +184,7 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, { } if (!isReactComponent(Comp)) { - console.error(`${schema.componentName} component may be has errors: `, Comp); + logger.error(`${schema.componentName} component may be has errors: `, Comp); } initRerenderEvent({ diff --git a/packages/renderer-core/src/renderer/addon.tsx b/packages/renderer-core/src/renderer/addon.tsx index 9cb114bee4..211ec182f2 100644 --- a/packages/renderer-core/src/renderer/addon.tsx +++ b/packages/renderer-core/src/renderer/addon.tsx @@ -2,6 +2,7 @@ import PropTypes from 'prop-types'; import baseRendererFactory from './base'; import { isEmpty } from '../utils'; import { IRendererAppHelper, IBaseRendererProps, IBaseRenderComponent } from '../types'; +import logger from '../utils/logger'; export default function addonRendererFactory(): IBaseRenderComponent { const BaseRenderer = baseRendererFactory(); @@ -32,7 +33,7 @@ export default function addonRendererFactory(): IBaseRenderComponent { const schema = props.__schema || {}; this.state = this.__parseData(schema.state || {}); if (isEmpty(props.config) || !props.config?.addonKey) { - console.warn('lce addon has wrong config'); + logger.warn('lce addon has wrong config'); this.setState({ __hasError: true, }); diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index 1980734e43..6c2a04aa78 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -56,14 +56,14 @@ export function executeLifeCycleMethod(context: any, schema: IPublicTypeNodeSche } if (typeof fn !== 'function') { - console.error(`生命周期${method}类型不符`, fn); + logger.error(`生命周期${method}类型不符`, fn); return; } try { return fn.apply(context, args); } catch (e) { - console.error(`[${schema.componentName}]生命周期${method}出错`, e); + logger.error(`[${schema.componentName}]生命周期${method}出错`, e); } } @@ -208,7 +208,7 @@ export default function baseRendererFactory(): IBaseRenderComponent { async componentDidCatch(...args: any[]) { this.__executeLifeCycleMethod('componentDidCatch', args); - console.warn(args); + logger.warn(args); } reloadDataSource = () => new Promise((resolve, reject) => { @@ -278,7 +278,7 @@ export default function baseRendererFactory(): IBaseRenderComponent { value = this.__parseExpression(value, this); } if (typeof value !== 'function') { - console.error(`custom method ${key} can not be parsed to a valid function`, value); + logger.error(`custom method ${key} can not be parsed to a valid function`, value); return; } this[key] = value.bind(this); @@ -369,7 +369,7 @@ export default function baseRendererFactory(): IBaseRenderComponent { this.setLocale = (loc: string) => { const setLocaleFn = this.appHelper?.utils?.i18n?.setLocale; if (!setLocaleFn || typeof setLocaleFn !== 'function') { - console.warn('initI18nAPIs Failed, i18n only works when appHelper.utils.i18n.setLocale() exists'); + logger.warn('initI18nAPIs Failed, i18n only works when appHelper.utils.i18n.setLocale() exists'); return undefined; } return setLocaleFn(loc); @@ -527,7 +527,7 @@ export default function baseRendererFactory(): IBaseRenderComponent { : {}; if (!Comp) { - console.error(`${schema.componentName} component is not found in components list! component list is:`, components || this.props.__container?.components); + logger.error(`${schema.componentName} component is not found in components list! component list is:`, components || this.props.__container?.components); return engine.createElement( engine.getNotFoundComponent(), { @@ -749,7 +749,7 @@ export default function baseRendererFactory(): IBaseRenderComponent { __createLoopVirtualDom = (schema: IPublicTypeNodeSchema, scope: any, parentInfo: INodeInfo, idx: number | string) => { if (isFileSchema(schema)) { - console.warn('file type not support Loop'); + logger.warn('file type not support Loop'); return null; } if (!Array.isArray(schema.loop)) { diff --git a/packages/renderer-core/src/renderer/temp.tsx b/packages/renderer-core/src/renderer/temp.tsx index 83adef7e30..1432da5fd2 100644 --- a/packages/renderer-core/src/renderer/temp.tsx +++ b/packages/renderer-core/src/renderer/temp.tsx @@ -1,4 +1,5 @@ import { IBaseRenderComponent } from '../types'; +import logger from '../utils/logger'; import baseRendererFactory from './base'; export default function tempRendererFactory(): IBaseRenderComponent { @@ -41,7 +42,7 @@ export default function tempRendererFactory(): IBaseRenderComponent { } async componentDidCatch(e: any) { - console.warn(e); + logger.warn(e); this.__debug(`componentDidCatch - ${this.props.__schema.fileName}`); } diff --git a/packages/renderer-core/src/utils/common.ts b/packages/renderer-core/src/utils/common.ts index 29381b5473..495744acd9 100644 --- a/packages/renderer-core/src/utils/common.ts +++ b/packages/renderer-core/src/utils/common.ts @@ -183,13 +183,13 @@ export function transformArrayToMap(arr: any[], key: string, overwrite = true) { return res; } -export function checkPropTypes(value: any, name: string, rule: any, componentName: string) { +export function checkPropTypes(value: any, name: string, rule: any, componentName: string): boolean { let ruleFunction = rule; if (typeof rule === 'string') { ruleFunction = new Function(`"use strict"; const PropTypes = arguments[0]; return ${rule}`)(PropTypes2); } if (!ruleFunction || typeof ruleFunction !== 'function') { - console.warn('checkPropTypes should have a function type rule argument'); + logger.warn('checkPropTypes should have a function type rule argument'); return true; } const err = ruleFunction( @@ -203,7 +203,7 @@ export function checkPropTypes(value: any, name: string, rule: any, componentNam ReactPropTypesSecret, ); if (err) { - console.warn(err); + logger.warn(err); } return !err; } diff --git a/packages/renderer-core/src/utils/data-helper.ts b/packages/renderer-core/src/utils/data-helper.ts index d884c13c97..41bcb9bfa0 100644 --- a/packages/renderer-core/src/utils/data-helper.ts +++ b/packages/renderer-core/src/utils/data-helper.ts @@ -186,7 +186,7 @@ export class DataHelper { } const { headers, ...otherProps } = otherOptionsObj || {}; if (!req) { - console.warn(`getDataSource API named ${id} not exist`); + logger.warn(`getDataSource API named ${id} not exist`); return; } @@ -215,7 +215,7 @@ export class DataHelper { try { callbackFn && callbackFn(res && res[id]); } catch (e) { - console.error('load请求回调函数报错', e); + logger.error('load请求回调函数报错', e); } return res && res[id]; }) @@ -223,7 +223,7 @@ export class DataHelper { try { callbackFn && callbackFn(null, err); } catch (e) { - console.error('load请求回调函数报错', e); + logger.error('load请求回调函数报错', e); } return err; }); @@ -300,9 +300,9 @@ export class DataHelper { return dataHandlerFun.call(this.host, data, error); } catch (e) { if (id) { - console.error(`[${id}]单个请求数据处理函数运行出错`, e); + logger.error(`[${id}]单个请求数据处理函数运行出错`, e); } else { - console.error('请求数据处理函数运行出错', e); + logger.error('请求数据处理函数运行出错', e); } } } diff --git a/packages/renderer-core/tests/utils/common.test.ts b/packages/renderer-core/tests/utils/common.test.ts index 995e55642e..2ee3ed4dcc 100644 --- a/packages/renderer-core/tests/utils/common.test.ts +++ b/packages/renderer-core/tests/utils/common.test.ts @@ -1,4 +1,4 @@ -// @ts-nocheck +import factoryWithTypeCheckers from 'prop-types/factoryWithTypeCheckers'; import { isSchema, isFileSchema, @@ -18,9 +18,14 @@ import { parseThisRequiredExpression, parseI18n, parseData, + checkPropTypes, } from '../../src/utils/common'; import logger from '../../src/utils/logger'; +var ReactIs = require('react-is'); + +const PropTypes = factoryWithTypeCheckers(ReactIs.isElement, true); + describe('test isSchema', () => { it('should be false when empty value is passed', () => { expect(isSchema(null)).toBeFalsy(); @@ -461,4 +466,37 @@ describe('test parseData ', () => { expect(result.__privateKey).toBeUndefined(); }); +}); + +describe('checkPropTypes', () => { + it('should validate correctly with valid prop type', () => { + expect(checkPropTypes(123, 'age', PropTypes.number, 'TestComponent')).toBe(true); + expect(checkPropTypes('123', 'age', PropTypes.string, 'TestComponent')).toBe(true); + }); + + it('should log a warning and return false with invalid prop type', () => { + expect(checkPropTypes(123, 'age', PropTypes.string, 'TestComponent')).toBe(false); + expect(checkPropTypes('123', 'age', PropTypes.number, 'TestComponent')).toBe(false); + }); + + it('should handle custom rule functions correctly', () => { + const customRule = (props, propName) => { + if (props[propName] !== 123) { + return new Error('Invalid value'); + } + }; + const result = checkPropTypes(123, 'customProp', customRule, 'TestComponent'); + expect(result).toBe(true); + }); + + + it('should interpret and validate a rule given as a string', () => { + const result = checkPropTypes(123, 'age', 'PropTypes.number', 'TestComponent'); + expect(result).toBe(true); + }); + + it('should log a warning for invalid rule type', () => { + const result = checkPropTypes(123, 'age', 123, 'TestComponent'); + expect(result).toBe(true); + }); }); \ No newline at end of file diff --git a/packages/renderer-core/tests/utils/data-helper.test.ts b/packages/renderer-core/tests/utils/data-helper.test.ts index cd4508ea87..f4b388ce92 100644 --- a/packages/renderer-core/tests/utils/data-helper.test.ts +++ b/packages/renderer-core/tests/utils/data-helper.test.ts @@ -346,11 +346,6 @@ describe('test DataHelper ', () => { result = dataHelper.handleData('fullConfigGet', mockDataHandler, { data: 'mockDataValue' }, null); expect(result).toStrictEqual({ data: 'mockDataValue' }); - // test exception - const mockError = jest.fn(); - const orginalConsole = global.console; - global.console = { error: mockError }; - // exception with id mockDataHandler = { type: 'JSFunction', @@ -358,7 +353,6 @@ describe('test DataHelper ', () => { }; result = dataHelper.handleData('fullConfigGet', mockDataHandler, { data: 'mockDataValue' }, null); expect(result).toBeUndefined(); - expect(mockError).toBeCalledWith('[fullConfigGet]单个请求数据处理函数运行出错', expect.anything()); // exception without id mockDataHandler = { @@ -367,12 +361,8 @@ describe('test DataHelper ', () => { }; result = dataHelper.handleData(null, mockDataHandler, { data: 'mockDataValue' }, null); expect(result).toBeUndefined(); - expect(mockError).toBeCalledWith('请求数据处理函数运行出错', expect.anything()); - - global.console = orginalConsole; }); - it('updateConfig should work', () => { const mockHost = { stateA: 'aValue'}; const mockDataSourceConfig = { From 944012ab3ff56bb9ec5781b1c9ecb0d14a165581 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 14 Nov 2023 11:46:13 +0800 Subject: [PATCH 063/219] test(designer): add test ut to sequencify --- packages/designer/jest.config.js | 1 + packages/designer/src/plugin/sequencify.ts | 58 ++++++-- .../designer/tests/plugin/sequencify.test.ts | 128 ++++++++++++++++++ 3 files changed, 177 insertions(+), 10 deletions(-) create mode 100644 packages/designer/tests/plugin/sequencify.test.ts diff --git a/packages/designer/jest.config.js b/packages/designer/jest.config.js index 1ecebd9388..f0ad2e861e 100644 --- a/packages/designer/jest.config.js +++ b/packages/designer/jest.config.js @@ -20,6 +20,7 @@ const jestConfig = { // testMatch: ['**/node.test.ts'], // testMatch: ['**/builtin-hotkey.test.ts'], // testMatch: ['**/selection.test.ts'], + // testMatch: ['**/plugin/sequencify.test.ts'], transformIgnorePatterns: [ `/node_modules/(?!${esModules})/`, ], diff --git a/packages/designer/src/plugin/sequencify.ts b/packages/designer/src/plugin/sequencify.ts index a312df2075..9084b0a0e6 100644 --- a/packages/designer/src/plugin/sequencify.ts +++ b/packages/designer/src/plugin/sequencify.ts @@ -1,19 +1,50 @@ -function sequence(tasks, names, results, missing, recursive, nest) { +interface ITaks { + [key: string]: { + name: string; + dep: string[]; + }; +} + +export function sequence({ + tasks, + names, + results, + missing, + recursive, + nest, + parentName, +}: { + tasks: ITaks; + names: string[]; + results: string[]; + missing: string[]; + recursive: string[][]; + nest: string[]; + parentName: string; +}) { names.forEach((name) => { if (results.indexOf(name) !== -1) { return; // de-dup results } const node = tasks[name]; if (!node) { - missing.push(name); + missing.push([parentName, name].filter((d => !!d)).join('.')); } else if (nest.indexOf(name) > -1) { nest.push(name); recursive.push(nest.slice(0)); - nest.pop(name); + nest.pop(); } else if (node.dep.length) { nest.push(name); - sequence(tasks, node.dep, results, missing, recursive, nest); // recurse - nest.pop(name); + sequence({ + tasks, + parentName: name, + names: node.dep, + results, + missing, + recursive, + nest, + }); // recurse + nest.pop(); } results.push(name); }); @@ -21,12 +52,19 @@ function sequence(tasks, names, results, missing, recursive, nest) { // tasks: object with keys as task names // names: array of task names -export default function (tasks, names) { - let results = []; // the final sequence - const missing = []; // missing tasks - const recursive = []; // recursive task dependencies +export default function (tasks: ITaks, names: string[]) { + let results: string[] = []; // the final sequence + const missing: string[] = []; // missing tasks + const recursive: string[][] = []; // recursive task dependencies - sequence(tasks, names, results, missing, recursive, []); + sequence({ + tasks, + names, + results, + missing, + recursive, + nest: [], + }); if (missing.length || recursive.length) { results = []; // results are incomplete at best, completely wrong at worst, remove them to avoid confusion diff --git a/packages/designer/tests/plugin/sequencify.test.ts b/packages/designer/tests/plugin/sequencify.test.ts new file mode 100644 index 0000000000..89140e2794 --- /dev/null +++ b/packages/designer/tests/plugin/sequencify.test.ts @@ -0,0 +1,128 @@ +import sequencify, { sequence } from '../../src/plugin/sequencify'; + +describe('sequence', () => { + it('handles tasks with no dependencies', () => { + const tasks = { + task1: { name: 'Task 1', dep: [] }, + task2: { name: 'Task 2', dep: [] } + }; + const results = []; + const missing = []; + const recursive = []; + sequence({ tasks, names: ['task1', 'task2'], results, missing, recursive, nest: [] }); + + expect(results).toEqual(['task1', 'task2']); + expect(missing).toEqual([]); + expect(recursive).toEqual([]); + }); + + it('correctly orders tasks based on dependencies', () => { + const tasks = { + task1: { name: 'Task 1', dep: [] }, + task2: { name: 'Task 2', dep: ['task1'] } + }; + const results = []; + const missing = []; + const recursive = []; + sequence({ tasks, names: ['task2', 'task1'], results, missing, recursive, nest: [] }); + + expect(results).toEqual(['task1', 'task2']); + expect(missing).toEqual([]); + expect(recursive).toEqual([]); + }); + + it('identifies missing tasks', () => { + const tasks = { + task1: { name: 'Task 1', dep: [] } + }; + const results = []; + const missing = []; + const recursive = []; + const nest = [] + sequence({ tasks, names: ['task2'], results, missing, recursive, nest }); + + expect(results).toEqual(['task2']); + expect(missing).toEqual(['task2']); + expect(recursive).toEqual([]); + expect(nest).toEqual([]); + }); + + it('detects recursive dependencies', () => { + const tasks = { + task1: { name: 'Task 1', dep: ['task2'] }, + task2: { name: 'Task 2', dep: ['task1'] } + }; + const results = []; + const missing = []; + const recursive = []; + const nest = [] + sequence({ tasks, names: ['task1', 'task2'], results, missing, recursive, nest }); + + expect(results).toEqual(['task1', 'task2', 'task1']); + expect(missing).toEqual([]); + expect(recursive).toEqual([['task1', 'task2', 'task1']]); + expect(nest).toEqual([]); + }); +}); + +describe('sequence', () => { + + it('should return tasks in sequence without dependencies', () => { + const tasks = { + task1: { name: 'Task 1', dep: [] }, + task2: { name: 'Task 2', dep: [] }, + task3: { name: 'Task 3', dep: [] } + }; + const names = ['task1', 'task2', 'task3']; + const expected = { + sequence: ['task1', 'task2', 'task3'], + missingTasks: [], + recursiveDependencies: [] + }; + expect(sequencify(tasks, names)).toEqual(expected); + }); + + it('should handle tasks with dependencies', () => { + const tasks = { + task1: { name: 'Task 1', dep: [] }, + task2: { name: 'Task 2', dep: ['task1'] }, + task3: { name: 'Task 3', dep: ['task2'] } + }; + const names = ['task3', 'task2', 'task1']; + const expected = { + sequence: ['task1', 'task2', 'task3'], + missingTasks: [], + recursiveDependencies: [] + }; + expect(sequencify(tasks, names)).toEqual(expected); + }); + + it('should identify missing tasks', () => { + const tasks = { + task1: { name: 'Task 1', dep: [] }, + task2: { name: 'Task 2', dep: ['task3'] } // task3 is missing + }; + const names = ['task1', 'task2']; + const expected = { + sequence: [], + missingTasks: ['task2.task3'], + recursiveDependencies: [] + }; + expect(sequencify(tasks, names)).toEqual(expected); + }); + + it('should detect recursive dependencies', () => { + const tasks = { + task1: { name: 'Task 1', dep: ['task2'] }, + task2: { name: 'Task 2', dep: ['task1'] } // Recursive dependency + }; + const names = ['task1', 'task2']; + const expected = { + sequence: [], + missingTasks: [], + recursiveDependencies: [['task1', 'task2', 'task1']] + }; + expect(sequencify(tasks, names)).toEqual(expected); + }); + +}); \ No newline at end of file From 736cb0e96552c557aa3f2c6d290cc3c915fb8adb Mon Sep 17 00:00:00 2001 From: beautiful-boyyy <beautiful_boyyy@outlook.com> Date: Wed, 15 Nov 2023 12:09:55 +0800 Subject: [PATCH 064/219] docs: update prepare.md --- docs/docs/participate/prepare.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/docs/participate/prepare.md b/docs/docs/participate/prepare.md index c0e1d5880e..acb0947f22 100644 --- a/docs/docs/participate/prepare.md +++ b/docs/docs/participate/prepare.md @@ -33,27 +33,27 @@ npm install && npm start "proxy": [ [ "https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/engine-core.js", - "http://localhost:5555/js/engine-core.js" + "http://localhost:5555/js/AliLowCodeEngine.js" ], [ "https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/engine-core.css", - "http://localhost:5555/css/engine-core.css" + "http://localhost:5555/css/AliLowCodeEngine.css" ], [ "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/react-simulator-renderer.js", - "http://localhost:5555/js/react-simulator-renderer.js" + "http://localhost:5555/js/ReactSimulatorRenderer.js" ], [ "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/react-simulator-renderer.css", - "http://localhost:5555/css/react-simulator-renderer.css" + "http://localhost:5555/css/ReactSimulatorRenderer.css" ], [ "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/rax-simulator-renderer.js", - "http://localhost:5555/js/rax-simulator-renderer.js" + "http://localhost:5555/js/RaxSimulatorRenderer.js" ], [ "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/rax-simulator-renderer.css", - "http://localhost:5555/css/rax-simulator-renderer.css" + "http://localhost:5555/css/RaxSimulatorRenderer.css" ], ] } From 6cba4bcc206c148ec87aa2aed5ffd382ae3fe438 Mon Sep 17 00:00:00 2001 From: beautiful-boyyy <beautiful_boyyy@outlook.com> Date: Wed, 15 Nov 2023 12:09:55 +0800 Subject: [PATCH 065/219] docs: update prepare.md --- docs/docs/participate/prepare.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/docs/participate/prepare.md b/docs/docs/participate/prepare.md index c0e1d5880e..acb0947f22 100644 --- a/docs/docs/participate/prepare.md +++ b/docs/docs/participate/prepare.md @@ -33,27 +33,27 @@ npm install && npm start "proxy": [ [ "https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/engine-core.js", - "http://localhost:5555/js/engine-core.js" + "http://localhost:5555/js/AliLowCodeEngine.js" ], [ "https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/engine-core.css", - "http://localhost:5555/css/engine-core.css" + "http://localhost:5555/css/AliLowCodeEngine.css" ], [ "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/react-simulator-renderer.js", - "http://localhost:5555/js/react-simulator-renderer.js" + "http://localhost:5555/js/ReactSimulatorRenderer.js" ], [ "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/react-simulator-renderer.css", - "http://localhost:5555/css/react-simulator-renderer.css" + "http://localhost:5555/css/ReactSimulatorRenderer.css" ], [ "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/rax-simulator-renderer.js", - "http://localhost:5555/js/rax-simulator-renderer.js" + "http://localhost:5555/js/RaxSimulatorRenderer.js" ], [ "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/rax-simulator-renderer.css", - "http://localhost:5555/css/rax-simulator-renderer.css" + "http://localhost:5555/css/RaxSimulatorRenderer.css" ], ] } From e7884fdb5a9b448aa92ca3e897def4c05bc8caa6 Mon Sep 17 00:00:00 2001 From: Super-Rz <41566502+Super-Rz@users.noreply.github.com> Date: Wed, 15 Nov 2023 14:23:07 +0800 Subject: [PATCH 066/219] fix: createIcon props (#2629) * fix: createIcon props * fix: createIcon props --- .../src/builtin-simulator/bem-tools/border-selecting.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx b/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx index 0e9d734b60..4f452727d2 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx +++ b/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx @@ -143,7 +143,7 @@ function createAction(content: ReactNode | ComponentType<any> | IPublicTypeActio }); }} > - {icon && createIcon(icon)} + {icon && createIcon(icon, { key, node: node.internalToShellNode() })} <Tip>{title}</Tip> </div> ); From 058e184b21b15bcf512d796aea825b69756db537 Mon Sep 17 00:00:00 2001 From: beautiful-boyyy <beautiful_boyyy@outlook.com> Date: Wed, 15 Nov 2023 15:18:18 +0800 Subject: [PATCH 067/219] fix: fixed string trim issue --- packages/renderer-core/src/renderer/base.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index 6c2a04aa78..ac4b1de125 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -901,9 +901,6 @@ export default function baseRendererFactory(): IBaseRenderComponent { }); return checkProps(res); } - if (typeof props === 'string') { - return checkProps(props.trim()); - } return checkProps(props); }; From 8898f1c4a7bb9766a0ce78632501b98942070ab4 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 15 Nov 2023 15:23:03 +0800 Subject: [PATCH 068/219] fix: fix engine-core classes is undefined --- packages/engine/src/engine-core.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/engine/src/engine-core.ts b/packages/engine/src/engine-core.ts index 204b9b30ab..2b59ba1b6d 100644 --- a/packages/engine/src/engine-core.ts +++ b/packages/engine/src/engine-core.ts @@ -54,7 +54,7 @@ import { } from '@alilc/lowcode-shell'; import { isPlainObject } from '@alilc/lowcode-utils'; import './modules/live-editing'; -import classes from './modules/classes'; +import * as classes from './modules/classes'; import symbols from './modules/symbols'; import { componentMetaParser } from './inner-plugins/component-meta-parser'; import { setterRegistry } from './inner-plugins/setter-registry'; From 0f8bc8228236439775a0429c488308ba32ab7a4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= <liujup@foxmail.com> Date: Mon, 20 Nov 2023 16:04:26 +0800 Subject: [PATCH 069/219] Update index.md --- docs/docs/article/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/docs/article/index.md b/docs/docs/article/index.md index e62f8f9d87..2de0b059ee 100644 --- a/docs/docs/article/index.md +++ b/docs/docs/article/index.md @@ -6,6 +6,7 @@ - [2022/12/21 低代码多分支协同开发的建设与实践](https://mp.weixin.qq.com/s/DmwxL67htHfTUP1U966N-Q) - [2022/11/24 低代码引擎半岁啦,来跟大家唠唠嗑...](https://segmentfault.com/a/1190000042884409) - [2022/10/27 低代码技术在研发团队的应用模式探讨](https://mp.weixin.qq.com/s/Ynk_wjJbmNw7fEG6UtGZbQ) +- [基于 LowCodeEngine 的调试能力建设与实践](https://mp.weixin.qq.com/s/H8KvEOylmzLPgIuuBO0S9w) - [2022/06/23 低代码渲染那些事](https://mp.weixin.qq.com/s/yqYey76qLGYPfDtpGkVFfA) - [2022/06/16 关于 LowCode&ProCode 混合研发的思考](https://mp.weixin.qq.com/s/TY3VXjkSmsQoT47xma3wig) - [2022/04/07 磁贴布局在钉钉宜搭报表设计引擎中的实现](https://mp.weixin.qq.com/s/PSTut5ahAB8nlJ9kBpBaxw) From 8208dd3a324081eeed3718d0924a397142c0c950 Mon Sep 17 00:00:00 2001 From: AprChell <smile_zchi@163.com> Date: Mon, 20 Nov 2023 16:24:27 +0800 Subject: [PATCH 070/219] fix(exportschema): exportSchema(IPublicEnumTransformStage.Save) type conver (#2661) * fix(exportschema): exportSchema(IPublicEnumTransformStage.Save) type conver * test(prop): nullProp equals null, not --- .../designer/src/document/node/props/prop.ts | 4 ---- .../tests/document/node/props/prop.test.ts | 2 +- packages/designer/tests/fixtures/schema/form.ts | 16 ++++++++-------- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/packages/designer/src/document/node/props/prop.ts b/packages/designer/src/document/node/props/prop.ts index 01b2dc26b9..e2d9f12e8e 100644 --- a/packages/designer/src/document/node/props/prop.ts +++ b/packages/designer/src/document/node/props/prop.ts @@ -290,10 +290,6 @@ export class Prop implements IProp, IPropParent { } if (type === 'literal' || type === 'expression') { - // TODO 后端改造之后删除此逻辑 - if (this._value === null && stage === IPublicEnumTransformStage.Save) { - return ''; - } return this._value; } diff --git a/packages/designer/tests/document/node/props/prop.test.ts b/packages/designer/tests/document/node/props/prop.test.ts index 58c24a4ea4..4424eb6010 100644 --- a/packages/designer/tests/document/node/props/prop.test.ts +++ b/packages/designer/tests/document/node/props/prop.test.ts @@ -136,7 +136,7 @@ describe('Prop 类测试', () => { expect(boolProp.export(IPublicEnumTransformStage.Save)).toBe(true); expect(strProp.export(IPublicEnumTransformStage.Save)).toBe('haha'); expect(numProp.export(IPublicEnumTransformStage.Save)).toBe(1); - expect(nullProp.export(IPublicEnumTransformStage.Save)).toBe(''); + expect(nullProp.export(IPublicEnumTransformStage.Save)).toBe(null); expect(nullProp.export(IPublicEnumTransformStage.Serilize)).toBe(null); expect(expProp.export(IPublicEnumTransformStage.Save)).toEqual({ type: 'JSExpression', diff --git a/packages/designer/tests/fixtures/schema/form.ts b/packages/designer/tests/fixtures/schema/form.ts index 8da6faf9e1..e8479629f8 100644 --- a/packages/designer/tests/fixtures/schema/form.ts +++ b/packages/designer/tests/fixtures/schema/form.ts @@ -267,7 +267,7 @@ export default { labelTipsText: { type: 'i18n', use: 'zh-CN', - 'en-US': null, + 'en-US': '', 'zh-CN': '', }, }, @@ -337,7 +337,7 @@ export default { labelTipsText: { type: 'i18n', use: 'zh-CN', - 'en-US': null, + 'en-US': '', 'zh-CN': '', }, }, @@ -407,7 +407,7 @@ export default { labelTipsText: { type: 'i18n', use: 'zh-CN', - 'en-US': null, + 'en-US': '', 'zh-CN': '', }, }, @@ -489,7 +489,7 @@ export default { labelTipsText: { type: 'i18n', use: 'zh-CN', - 'en-US': null, + 'en-US': '', 'zh-CN': '', }, }, @@ -578,7 +578,7 @@ export default { labelTipsText: { type: 'i18n', use: 'zh-CN', - 'en-US': null, + 'en-US': '', 'zh-CN': '', }, searchDelay: 300, @@ -697,7 +697,7 @@ export default { labelTipsText: { type: 'i18n', use: 'zh-CN', - 'en-US': null, + 'en-US': '', 'zh-CN': '', }, }, @@ -789,7 +789,7 @@ export default { labelTipsText: { type: 'i18n', use: 'zh-CN', - 'en-US': null, + 'en-US': '', 'zh-CN': '', }, }, @@ -871,7 +871,7 @@ export default { labelTipsText: { type: 'i18n', use: 'zh-CN', - 'en-US': null, + 'en-US': '', 'zh-CN': '', }, }, From 3c4bd1d2d0321453b3a1fa5253b0340c3dde8afc Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Mon, 20 Nov 2023 16:45:11 +0800 Subject: [PATCH 071/219] chore(docs): publish docs 1.1.17 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index c206cdf16a..81703741ac 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.1.16", + "version": "1.1.17", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 396e99aa11d442f1ace9ff138b2d4698ef57d9f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= <liujup@foxmail.com> Date: Mon, 20 Nov 2023 17:00:36 +0800 Subject: [PATCH 072/219] docs: update index.md --- docs/docs/article/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/article/index.md b/docs/docs/article/index.md index 2de0b059ee..c223137b25 100644 --- a/docs/docs/article/index.md +++ b/docs/docs/article/index.md @@ -6,7 +6,7 @@ - [2022/12/21 低代码多分支协同开发的建设与实践](https://mp.weixin.qq.com/s/DmwxL67htHfTUP1U966N-Q) - [2022/11/24 低代码引擎半岁啦,来跟大家唠唠嗑...](https://segmentfault.com/a/1190000042884409) - [2022/10/27 低代码技术在研发团队的应用模式探讨](https://mp.weixin.qq.com/s/Ynk_wjJbmNw7fEG6UtGZbQ) -- [基于 LowCodeEngine 的调试能力建设与实践](https://mp.weixin.qq.com/s/H8KvEOylmzLPgIuuBO0S9w) +- [2022/08/23 基于 LowCodeEngine 的调试能力建设与实践](https://mp.weixin.qq.com/s/H8KvEOylmzLPgIuuBO0S9w) - [2022/06/23 低代码渲染那些事](https://mp.weixin.qq.com/s/yqYey76qLGYPfDtpGkVFfA) - [2022/06/16 关于 LowCode&ProCode 混合研发的思考](https://mp.weixin.qq.com/s/TY3VXjkSmsQoT47xma3wig) - [2022/04/07 磁贴布局在钉钉宜搭报表设计引擎中的实现](https://mp.weixin.qq.com/s/PSTut5ahAB8nlJ9kBpBaxw) From bf50071cc8ca2c06b70f03c16347fc85533bd8e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= <liujup@foxmail.com> Date: Mon, 20 Nov 2023 17:03:11 +0800 Subject: [PATCH 073/219] docs: update index.md --- docs/docs/video/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/docs/video/index.md b/docs/docs/video/index.md index 9f348e4e65..2f8a5f49ce 100644 --- a/docs/docs/video/index.md +++ b/docs/docs/video/index.md @@ -1,4 +1,5 @@ # 官方视频 +- [2023/11/17 云栖大会|阿里开源低代码引擎及商业解决方案](https://www.bilibili.com/video/BV1Qw411H7DH) - [2023/08/03 初识低代码引擎](https://www.bilibili.com/video/BV1gu411p7TC) # 社区视频 From d47df9dc441cfc5f0a3490e2243e90473e3469e1 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 20 Nov 2023 17:33:53 +0800 Subject: [PATCH 074/219] style: add --workspace-left-area-width --- docs/docs/guide/expand/editor/theme.md | 1 + packages/editor-skeleton/src/layouts/workbench.less | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/docs/guide/expand/editor/theme.md b/docs/docs/guide/expand/editor/theme.md index b62fb4f28c..94e434580d 100644 --- a/docs/docs/guide/expand/editor/theme.md +++ b/docs/docs/guide/expand/editor/theme.md @@ -72,6 +72,7 @@ sidebar_position: 9 - `--workspace-sub-top-area-height`: 应用级二级 topArea 高度 - `--workspace-sub-top-area-margin`: 应用级二级 topArea margin - `--workspace-sub-top-area-padding`: 应用级二级 topArea padding +- `--workspace-left-area-width`: 应用级 leftArea width ### 生态使用主题色变量 diff --git a/packages/editor-skeleton/src/layouts/workbench.less b/packages/editor-skeleton/src/layouts/workbench.less index 6d0604a1f1..eb86bfe04c 100644 --- a/packages/editor-skeleton/src/layouts/workbench.less +++ b/packages/editor-skeleton/src/layouts/workbench.less @@ -13,6 +13,7 @@ --popup-border-radius: @popup-border-radius; --left-area-width: 48px; + --workspace-left-area-width: 48px; --right-area-width: 300px; --top-area-height: 48px; --toolbar-height: 36px; @@ -273,7 +274,7 @@ body { } .lc-left-area, .lc-workspace-left-area { height: 100%; - width: var(--left-area-width); + width: var(--workspace-left-area-width, --left-area-width); display: none; flex-shrink: 0; flex-direction: column; From 322313ceada4bf3d2011a0032f0be598c73ebeab Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 20 Nov 2023 18:14:15 +0800 Subject: [PATCH 075/219] docs: update faq list --- docs/docs/faq/index.md | 43 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/docs/docs/faq/index.md b/docs/docs/faq/index.md index ed31bad28e..5e5eee8ac4 100644 --- a/docs/docs/faq/index.md +++ b/docs/docs/faq/index.md @@ -1,7 +1,46 @@ --- title: FAQ 概述 -sidebar_position: 1 +sidebar_position: -1 tags: [FAQ] --- -不定期将社区常见问题及答案维护到此处 \ No newline at end of file +不定期将社区常见问题及答案维护到此处 + +## Demo 使用 +- [渲染唯一标识(key)](/site/docs/faq/faq002) +- [点击事件如何添加参数](/site/docs/faq/faq003) +- [如何通过 API 手动调用数据源请求](/site/docs/faq/faq006) + +## 设计器定制 +- [如何通过 this.utils 使用第三方工具扩展](/site/docs/faq/faq005) +- [设置面板中的高级 tab 如何配置](/site/docs/faq/faq007) +- [插件面板如何调整位置](/site/docs/faq/faq010) + +## 源码和依赖 +- [某某 npm 包对应的源码在哪里?](/site/docs/faq/faq008) + +## 错误和报错 +- [物料出现 Component Not Found 相关报错](/site/docs/faq/faq009) +- [VERSION_PLACEHOLDER is not defined](/site/docs/faq/faq014) +- [Cannot read property 'Icon' of Undefined](/site/docs/faq/faq016) +- [windows 下运行低代码引擎源码出现报错](/site/docs/faq/faq019) +- [Can't import the named export from non ECMAScript module](/site/docs/faq/faq020) +- [Slot组件渲染报错问题](/site/docs/faq/faq023) + +## 物料相关问题 +- [如何获取物料当前处于编辑态还是渲染态](/site/docs/faq/faq011) +- [Procode 物料如何调用数据源方法](/site/docs/faq/faq012) +- [已有组件如何快速接入引擎](/site/docs/faq/faq015) +- [Modal 类组件 hidden 属性被强制设置 true](/site/docs/faq/faq013) +- [最小渲染单元配置](/site/docs/faq/faq004) +- [节点无法拖拽到 Page 下](/site/docs/faq/faq022) + +## 其他说明 +- [vue 画布支持说明](/site/docs/faq/faq017) +- [是否可以生成 Vue 页面代码?](/site/docs/faq/faq018) + +## 参与贡献 +- [提交 PR 时,明明签署过 CLA,仍被提示需要签署](/site/docs/faq/faq021) + +## 相关依赖文档 +- [build-scripts 的使用文档](/site/docs/faq/faq001) From e35c672a50dc877f5768c1092e330bfb0424cfe2 Mon Sep 17 00:00:00 2001 From: "chenkeyao.chenkeya" <chenkeyao.chenkeya@alibaba-inc.com> Date: Mon, 20 Nov 2023 21:02:05 +0800 Subject: [PATCH 076/219] feat: add new video --- docs/docs/video/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/video/index.md b/docs/docs/video/index.md index 2f8a5f49ce..8ae21620bc 100644 --- a/docs/docs/video/index.md +++ b/docs/docs/video/index.md @@ -1,5 +1,5 @@ # 官方视频 -- [2023/11/17 云栖大会|阿里开源低代码引擎及商业解决方案](https://www.bilibili.com/video/BV1Qw411H7DH) +- [2023/11/20 云栖大会|阿里开源低代码引擎及商业解决方案](https://www.bilibili.com/video/BV1Ku4y1w7Zr) - [2023/08/03 初识低代码引擎](https://www.bilibili.com/video/BV1gu411p7TC) # 社区视频 From 7c72261fef0324cb57fd3e42331ede0f5b680573 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Tue, 21 Nov 2023 10:28:27 +0800 Subject: [PATCH 077/219] chore(docs): publish docs 1.2.0 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 81703741ac..cb3cb946dc 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.1.17", + "version": "1.2.0", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 394b56d0cef70101709802fb6ab1fda8f0ec2e3a Mon Sep 17 00:00:00 2001 From: 1ncounter <1ncounter.100@gmail.com> Date: Wed, 22 Nov 2023 19:50:22 +0800 Subject: [PATCH 078/219] fix: recover component lifecycle and avoid execute from scope __proto__ --- packages/renderer-core/src/renderer/base.tsx | 5 +++++ .../renderer-core/src/renderer/component.tsx | 21 ------------------- 2 files changed, 5 insertions(+), 21 deletions(-) diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index ac4b1de125..dddc55e838 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -50,6 +50,11 @@ export function executeLifeCycleMethod(context: any, schema: IPublicTypeNodeSche return; } + // avoid execute lifeCycle method from __proto__'s method (it is React class Component Class lifeCycle) + if (!Object.prototype.hasOwnProperty.call(context, method) && method !== 'constructor') { + return; + } + // TODO: cache if (isJSExpression(fn) || isJSFunction(fn)) { fn = thisRequiredInJSE ? parseThisRequiredExpression(fn, context) : parseExpression(fn, context); diff --git a/packages/renderer-core/src/renderer/component.tsx b/packages/renderer-core/src/renderer/component.tsx index f9f6e8f96e..3dfc1df33f 100644 --- a/packages/renderer-core/src/renderer/component.tsx +++ b/packages/renderer-core/src/renderer/component.tsx @@ -46,26 +46,5 @@ export default function componentRendererFactory(): IBaseRenderComponent { return this.__renderComp(Component, this.__renderContextProvider({ compContext: this })); } - - getComponentName() { - return this.props?.componentName; - } - - /** 需要重载下面几个方法,如果在低代码组件中绑定了对应的生命周期时会出现死循环 */ - componentDidMount() { - this.__debug(`componentDidMount - ${this.getComponentName()}`); - } - getSnapshotBeforeUpdate() { - this.__debug(`getSnapshotBeforeUpdate - ${this.getComponentName()}`); - } - componentDidUpdate() { - this.__debug(`componentDidUpdate - ${this.getComponentName()}`); - } - componentWillUnmount() { - this.__debug(`componentWillUnmount - ${this.getComponentName()}`); - } - componentDidCatch() { - this.__debug(`componentDidCatch - ${this.getComponentName()}`); - } }; } From 27e914cecee34a886680db3f2bc0c69f2b62c726 Mon Sep 17 00:00:00 2001 From: andylili21 <101868030+andylili21@users.noreply.github.com> Date: Thu, 23 Nov 2023 16:05:07 +0800 Subject: [PATCH 079/219] fix: Improve code and simplify logic (#2651) * fix: Improve code and simplify logic --- packages/designer/src/document/node/node.ts | 14 ++--- .../designer/tests/document/node/node.test.ts | 61 +++++++++++++++++-- 2 files changed, 64 insertions(+), 11 deletions(-) diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts index 9effc341dd..145a5a85ec 100644 --- a/packages/designer/src/document/node/node.ts +++ b/packages/designer/src/document/node/node.ts @@ -440,23 +440,23 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema> } private initialChildren(children: IPublicTypeNodeData | IPublicTypeNodeData[] | undefined): IPublicTypeNodeData[] { - // FIXME! this is dirty code + const { initialChildren } = this.componentMeta.advanced; + if (children == null) { - const { initialChildren } = this.componentMeta.advanced; if (initialChildren) { if (typeof initialChildren === 'function') { return initialChildren(this.internalToShellNode()!) || []; } return initialChildren; } + return []; } + if (Array.isArray(children)) { return children; - } else if (children) { - return [children]; - } else { - return []; } + + return [children]; } isContainer(): boolean { @@ -1094,7 +1094,7 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema> } /** - * 是否可执行某action + * 是否可执行某 action */ canPerformAction(actionName: string): boolean { const availableActions = diff --git a/packages/designer/tests/document/node/node.test.ts b/packages/designer/tests/document/node/node.test.ts index c4717b3a02..2695d6c838 100644 --- a/packages/designer/tests/document/node/node.test.ts +++ b/packages/designer/tests/document/node/node.test.ts @@ -54,7 +54,60 @@ describe('Node 方法测试', () => { project = null; }); - it('condition group', () => {}); + // Case 1: When children is null + test('initialChildren returns result of initialChildren function when children is null ', () => { + const node = new Node(doc, { componentName: 'Button', props: { a: 1 } }); + const result = node.initialChildren(null); + // 预期结果是一个空数组 + expect(result).toEqual([]); + }); + + // Case 2: When children is undefined + test('initialChildren returns result of initialChildren function when children is null ', () => { + const node = new Node(doc, { componentName: 'Button', props: { a: 1 } }); + const result = node.initialChildren(undefined); + // 预期结果是一个空数组 + expect(result).toEqual([]); + }); + + // Case 3: When children is array + test('initialChildren returns result of initialChildren function when children is null ', () => { + const node = new Node(doc, { componentName: 'Button', props: { a: 1 } }); + const childrenArray = [{ id: 1, name: 'Child 1' }, { id: 2, name: 'Child 2' }]; + const result = node.initialChildren(childrenArray); + // 预期结果是一个数组 + expect(result).toEqual(childrenArray); + }); + + // Case 4: When children is not null and not an array + test('initialChildren returns result of initialChildren function when children is null ', () => { + const node = new Node(doc, { componentName: 'Button', props: { a: 1 } }); + const childObject = { id: 1, name: 'Child 1' }; + const result = node.initialChildren(childObject); + // 预期结果是一个数组 + expect(result).toEqual([childObject]); + }); + + // Case 5: When children 0 + test('initialChildren returns result of initialChildren function when children is null ', () => { + const node = new Node(doc, { componentName: 'Button', props: { a: 1 } }); + const childObject = 0; + const result = node.initialChildren(childObject); + // 预期结果是一个数组 + expect(result).toEqual([0]); + }); + + // Case 6: When children false + test('initialChildren returns result of initialChildren function when children is null ', () => { + const node = new Node(doc, { componentName: 'Button', props: { a: 1 } }); + const childObject = false; + const result = node.initialChildren(childObject); + // 预期结果是一个数组 + expect(result).toEqual([false]); + }); + + + it('condition group', () => { }); it('getExtraProp / setExtraProp', () => { const firstBtn = doc.getNode('node_k1ow3cbn')!; @@ -367,7 +420,7 @@ describe('Node 方法测试', () => { expect(mockFn).not.toHaveBeenCalled(); }); - it('addSlot / unlinkSlot / removeSlot', () => {}); + it('addSlot / unlinkSlot / removeSlot', () => { }); it('setProps', () => { const firstBtn = doc.getNode('node_k1ow3cbn')!; @@ -407,7 +460,7 @@ describe('Node 方法测试', () => { designer.createComponentMeta(btnMetadata); const btn = doc.getNode('node_k1ow3cbn'); // 从 componentMeta 中获取到 title 值 - expect(btn.title).toEqual({ type: 'i18n', 'zh-CN': '按钮', 'en-US': 'Button' } ); + expect(btn.title).toEqual({ type: 'i18n', 'zh-CN': '按钮', 'en-US': 'Button' }); // 从 extraProp 中获取值 btn.setExtraProp('title', 'hello button'); expect(btn.title).toBe('hello button'); @@ -546,7 +599,7 @@ describe('Node 方法测试', () => { expect(comparePosition(firstBtn, firstCard)).toBe(PositionNO.BeforeOrAfter); }); - it('getZLevelTop', () => {}); + it('getZLevelTop', () => { }); it('propsData', () => { expect(new Node(doc, { componentName: 'Leaf' }).propsData).toBeNull(); expect(new Node(doc, { componentName: 'Fragment' }).propsData).toBeNull(); From ad044f49ed9064fe1afa5195f68759a76bda5f5e Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 23 Nov 2023 11:01:50 +0800 Subject: [PATCH 080/219] feat(utils): add workspace utils --- packages/designer/src/plugin/plugin-types.ts | 1 + packages/engine/src/engine-core.ts | 1 + .../types/src/shell/model/plugin-context.ts | 2 + packages/utils/src/index.ts | 1 + packages/utils/src/workspace.tsx | 54 +++++++++++++++++++ .../workspace/src/context/base-context.ts | 1 + 6 files changed, 60 insertions(+) create mode 100644 packages/utils/src/workspace.tsx diff --git a/packages/designer/src/plugin/plugin-types.ts b/packages/designer/src/plugin/plugin-types.ts index ac08d7d0ca..6091170f02 100644 --- a/packages/designer/src/plugin/plugin-types.ts +++ b/packages/designer/src/plugin/plugin-types.ts @@ -60,6 +60,7 @@ export interface ILowCodePluginContextPrivate { set workspace(workspace: IPublicApiWorkspace); set editorWindow(window: IPublicModelWindow); set registerLevel(level: IPublicEnumPluginRegisterLevel); + set isPluginRegisteredInWorkspace(flag: boolean); } export interface ILowCodePluginContextApiAssembler { assembleApis( diff --git a/packages/engine/src/engine-core.ts b/packages/engine/src/engine-core.ts index 2b59ba1b6d..3ac4c32a75 100644 --- a/packages/engine/src/engine-core.ts +++ b/packages/engine/src/engine-core.ts @@ -139,6 +139,7 @@ const pluginContextApiAssembler: ILowCodePluginContextApiAssembler = { context.logger = new Logger({ level: 'warn', bizName: `plugin:${pluginName}` }); context.workspace = workspace; context.registerLevel = IPublicEnumPluginRegisterLevel.Default; + context.isPluginRegisteredInWorkspace = false; }, }; diff --git a/packages/types/src/shell/model/plugin-context.ts b/packages/types/src/shell/model/plugin-context.ts index 1f3d3b5e85..35e7e38af3 100644 --- a/packages/types/src/shell/model/plugin-context.ts +++ b/packages/types/src/shell/model/plugin-context.ts @@ -108,6 +108,8 @@ export interface IPublicModelPluginContext { */ get registerLevel(): IPublicEnumPluginRegisterLevel; + get isPluginRegisteredInWorkspace(): boolean; + get editorWindow(): IPublicModelWindow; } diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index e3f70ff80a..3e37f46ba6 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -30,3 +30,4 @@ export * from './is-plugin-event-name'; export * as css from './css-helper'; export { transactionManager } from './transaction-manager'; export * from './check-types'; +export * from './workspace'; diff --git a/packages/utils/src/workspace.tsx b/packages/utils/src/workspace.tsx new file mode 100644 index 0000000000..446530ce8e --- /dev/null +++ b/packages/utils/src/workspace.tsx @@ -0,0 +1,54 @@ +import React, { useEffect, useState, useCallback } from 'react'; +import { IPublicModelPluginContext, IPublicEnumPluginRegisterLevel, IPublicModelWindow, IPublicModelEditorView } from '@alilc/lowcode-types'; + +/** + * 高阶组件(HOC):为组件提供 view 插件上下文。 + * + * @param {React.ComponentType} Component - 需要被封装的组件。 + * @param {string|string[]} viewName - 视图名称或视图名称数组,用于过滤特定的视图插件上下文。 + * @returns {React.ComponentType} 返回封装后的组件。 + * + * @example + * // 用法示例(函数组件): + * const EnhancedComponent = ProvideViewPluginContext(MyComponent, "viewName"); + */ +export const ProvideViewPluginContext = (Component: any, viewName?: string | string[]) => { + // 创建一个新的函数组件,以便在其中使用 Hooks + return function WithPluginContext(props: { + [key: string]: any; + + pluginContext?: IPublicModelPluginContext; + }) { + const getPluginContextFun = useCallback((editorWindow?: IPublicModelWindow | null) => { + if (!editorWindow?.currentEditorView) { + return null; + } + if (viewName) { + const items = editorWindow?.editorViews.filter(d => (d as any).viewName === viewName || (Array.isArray(viewName) && viewName.includes((d as any).viewName))); + return items[0]; + } else { + return editorWindow.currentEditorView; + } + }, []); + + const { workspace } = props.pluginContext || {}; + const [pluginContext, setPluginContext] = useState<IPublicModelEditorView | null>(getPluginContextFun(workspace?.window)); + + useEffect(() => { + if (workspace?.window) { + const ctx = getPluginContextFun(workspace.window); + ctx && setPluginContext(ctx); + } + return workspace?.onChangeActiveEditorView(() => { + const ctx = getPluginContextFun(workspace.window); + ctx && setPluginContext(ctx); + }); + }, [workspace, getPluginContextFun]); + + if (props.pluginContext?.registerLevel !== IPublicEnumPluginRegisterLevel.Workspace || !props.pluginContext) { + return <Component {...props} />; + } + + return <Component {...props} pluginContext={pluginContext} />; + }; +}; diff --git a/packages/workspace/src/context/base-context.ts b/packages/workspace/src/context/base-context.ts index b359a6139f..78f32079ff 100644 --- a/packages/workspace/src/context/base-context.ts +++ b/packages/workspace/src/context/base-context.ts @@ -170,6 +170,7 @@ export class BasicContext implements IBasicContext { context.editorWindow = new Window(editorWindow); } context.registerLevel = registerLevel; + context.isPluginRegisteredInWorkspace = registerLevel === IPublicEnumPluginRegisterLevel.Workspace; }, }; From 029fd1ce67739e85dd669c61ebfedf52199c2d11 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 23 Nov 2023 11:23:34 +0800 Subject: [PATCH 081/219] feat(outline-pane): suport registry in workspace level --- .../src/controllers/tree-master.ts | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/packages/plugin-outline-pane/src/controllers/tree-master.ts b/packages/plugin-outline-pane/src/controllers/tree-master.ts index 40162d808f..ede5f0f5f3 100644 --- a/packages/plugin-outline-pane/src/controllers/tree-master.ts +++ b/packages/plugin-outline-pane/src/controllers/tree-master.ts @@ -41,22 +41,19 @@ export class TreeMaster { this.initEvent(); if (pluginContext.registerLevel === IPublicEnumPluginRegisterLevel.Workspace) { this.setPluginContext(workspace.window?.currentEditorView); - workspace.onWindowRendererReady(() => { - this.setPluginContext(workspace.window?.currentEditorView); - let dispose: IPublicTypeDisposable | undefined; - const windowViewTypeChangeEvent = () => { - dispose = workspace.window?.onChangeViewType(() => { - this.setPluginContext(workspace.window?.currentEditorView); - }); - }; - - windowViewTypeChangeEvent(); - - workspace.onChangeActiveWindow(() => { - windowViewTypeChangeEvent(); + let dispose: IPublicTypeDisposable | undefined; + const windowViewTypeChangeEvent = () => { + dispose = workspace.window?.onChangeViewType(() => { this.setPluginContext(workspace.window?.currentEditorView); - dispose && dispose(); }); + }; + + windowViewTypeChangeEvent(); + + workspace.onChangeActiveWindow(() => { + windowViewTypeChangeEvent(); + this.setPluginContext(workspace.window?.currentEditorView); + dispose && dispose(); }); } } From a3fef9c13d39ac1b35b200cf0f711cf7c7c233d8 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 23 Nov 2023 15:32:54 +0800 Subject: [PATCH 082/219] feat(skeleton): add registerConfigTransducer API --- docs/docs/api/skeleton.md | 62 +++++++++++++++++++ packages/editor-skeleton/src/skeleton.ts | 31 +++++++++- packages/shell/src/api/skeleton.ts | 6 +- packages/types/src/shell/api/skeleton.ts | 19 +++++- .../types/src/shell/type/config-transducer.ts | 9 +++ packages/types/src/shell/type/index.ts | 1 + 6 files changed, 124 insertions(+), 4 deletions(-) create mode 100644 packages/types/src/shell/type/config-transducer.ts diff --git a/docs/docs/api/skeleton.md b/docs/docs/api/skeleton.md index c378792de0..90cf1a2c17 100644 --- a/docs/docs/api/skeleton.md +++ b/docs/docs/api/skeleton.md @@ -295,6 +295,68 @@ showArea(areaName: string): void; */ hideArea(areaName: string): void; ``` + +### registerConfigTransducer +注册一个面板的配置转换器(transducer)。 + +```typescript +/** + * 注册一个面板的配置转换器(transducer)。 + * Registers a configuration transducer for a panel. + * @param {IPublicTypeConfigTransducer} transducer + * - 要注册的转换器函数。该函数接受一个配置对象(类型为 IPublicTypeSkeletonConfig)作为输入,并返回修改后的配置对象。 + * - The transducer function to be registered. This function takes a configuration object + * + * @param {number} level + * - 转换器的优先级。优先级较高的转换器会先执行。 + * - The priority level of the transducer. Transducers with higher priority levels are executed first. + * + * @param {string} [id] + * - (可选)转换器的唯一标识符。用于在需要时引用或操作特定的转换器。 + * - (Optional) A unique identifier for the transducer. Used for referencing or manipulating a specific transducer when needed. + */ +registerConfigTransducer(transducer: IPublicTypeConfigTransducer, level: number, id?: string): void; +``` + +使用示例 + +```typescript +import { IPublicModelPluginContext, IPublicTypeSkeletonConfig } from '@alilc/lowcode-types'; + +function updatePanelWidth(config: IPublicTypeSkeletonConfig) { + if (config.type === 'PanelDock') { + return { + ...config, + panelProps: { + ...(config.panelProps || {}), + width: 240, + }, + } + } + + return config; +} + +const controlPanelWidthPlugin = (ctx: IPublicModelPluginContext) => { + const { skeleton } = ctx; + (skeleton as any).registerConfigTransducer?.(updatePanelWidth, 1, 'update-panel-width'); + + return { + init() {}, + }; +}; + +controlPanelWidthPlugin.pluginName = 'controlPanelWidthPlugin'; +controlPanelWidthPlugin.meta = { + dependencies: [], + engines: { + lowcodeEngine: '^1.2.3', // 插件需要配合 ^1.0.0 的引擎才可运行 + }, +}; + +export default controlPanelWidthPlugin; +``` + ## 事件 ### onShowPanel diff --git a/packages/editor-skeleton/src/skeleton.ts b/packages/editor-skeleton/src/skeleton.ts index 89bffc4cfe..13967e94d6 100644 --- a/packages/editor-skeleton/src/skeleton.ts +++ b/packages/editor-skeleton/src/skeleton.ts @@ -28,6 +28,7 @@ import { IPublicTypeWidgetConfigArea, IPublicTypeSkeletonConfig, IPublicApiSkeleton, + IPublicTypeConfigTransducer, } from '@alilc/lowcode-types'; const logger = new Logger({ level: 'warn', bizName: 'skeleton' }); @@ -111,6 +112,8 @@ export interface ISkeleton extends Omit<IPublicApiSkeleton, export class Skeleton implements ISkeleton { private panels = new Map<string, Panel>(); + private configTransducers: IPublicTypeConfigTransducer[] = []; + private containers = new Map<string, WidgetContainer<any>>(); readonly leftArea: Area<DockConfig | PanelDockConfig | DialogDockConfig>; @@ -448,11 +451,35 @@ export class Skeleton implements ISkeleton { return restConfig; } + registerConfigTransducer( + transducer: IPublicTypeConfigTransducer, + level = 100, + id?: string, + ) { + transducer.level = level; + transducer.id = id; + const i = this.configTransducers.findIndex((item) => item.level != null && item.level > level); + if (i < 0) { + this.configTransducers.push(transducer); + } else { + this.configTransducers.splice(i, 0, transducer); + } + } + + getRegisteredConfigTransducers(): IPublicTypeConfigTransducer[] { + return this.configTransducers; + } + add(config: IPublicTypeSkeletonConfig, extraConfig?: Record<string, any>): IWidget | Widget | Panel | Stage | Dock | PanelDock | undefined { - const parsedConfig = { + const registeredTransducers = this.getRegisteredConfigTransducers(); + + const parsedConfig = registeredTransducers.reduce((prevConfig, current) => { + return current(prevConfig); + }, { ...this.parseConfig(config), ...extraConfig, - }; + }); + let { area } = parsedConfig; if (!area) { if (parsedConfig.type === 'Panel') { diff --git a/packages/shell/src/api/skeleton.ts b/packages/shell/src/api/skeleton.ts index 0d17075257..07a1727dd3 100644 --- a/packages/shell/src/api/skeleton.ts +++ b/packages/shell/src/api/skeleton.ts @@ -4,7 +4,7 @@ import { SkeletonEvents, } from '@alilc/lowcode-editor-skeleton'; import { skeletonSymbol } from '../symbols'; -import { IPublicApiSkeleton, IPublicModelSkeletonItem, IPublicTypeDisposable, IPublicTypeSkeletonConfig, IPublicTypeWidgetConfigArea } from '@alilc/lowcode-types'; +import { IPublicApiSkeleton, IPublicModelSkeletonItem, IPublicTypeConfigTransducer, IPublicTypeDisposable, IPublicTypeSkeletonConfig, IPublicTypeWidgetConfigArea } from '@alilc/lowcode-types'; import { getLogger } from '@alilc/lowcode-utils'; import { SkeletonItem } from '../model/skeleton-item'; @@ -208,6 +208,10 @@ export class Skeleton implements IPublicApiSkeleton { }); return () => editor.eventBus.off(SkeletonEvents.WIDGET_HIDE, listener); } + + registerConfigTransducer(fn: IPublicTypeConfigTransducer, level: number, id?: string) { + this[skeletonSymbol].registerConfigTransducer(fn, level, id); + } } function normalizeArea(area: IPublicTypeWidgetConfigArea | undefined): 'leftArea' | 'rightArea' | 'topArea' | 'toolbar' | 'mainArea' | 'bottomArea' | 'leftFixedArea' | 'leftFloatArea' | 'stages' | 'subTopArea' { diff --git a/packages/types/src/shell/api/skeleton.ts b/packages/types/src/shell/api/skeleton.ts index 2ad561518b..9a36aa4690 100644 --- a/packages/types/src/shell/api/skeleton.ts +++ b/packages/types/src/shell/api/skeleton.ts @@ -1,5 +1,5 @@ import { IPublicModelSkeletonItem } from '../model'; -import { IPublicTypeDisposable, IPublicTypeSkeletonConfig } from '../type'; +import { IPublicTypeConfigTransducer, IPublicTypeDisposable, IPublicTypeSkeletonConfig } from '../type'; export interface IPublicApiSkeleton { @@ -114,4 +114,21 @@ export interface IPublicApiSkeleton { * @returns */ onHideWidget(listener: (...args: any[]) => void): IPublicTypeDisposable; + + /** + * 注册一个面板的配置转换器(transducer)。 + * Registers a configuration transducer for a panel. + * @param {IPublicTypeConfigTransducer} transducer + * - 要注册的转换器函数。该函数接受一个配置对象(类型为 IPublicTypeSkeletonConfig)作为输入,并返回修改后的配置对象。 + * - The transducer function to be registered. This function takes a configuration object (of type IPublicTypeSkeletonConfig) as input and returns a modified configuration object. + * + * @param {number} level + * - 转换器的优先级。优先级较高的转换器会先执行。 + * - The priority level of the transducer. Transducers with higher priority levels are executed first. + * + * @param {string} [id] + * - (可选)转换器的唯一标识符。用于在需要时引用或操作特定的转换器。 + * - (Optional) A unique identifier for the transducer. Used for referencing or manipulating a specific transducer when needed. + */ + registerConfigTransducer(transducer: IPublicTypeConfigTransducer, level: number, id?: string): void; } diff --git a/packages/types/src/shell/type/config-transducer.ts b/packages/types/src/shell/type/config-transducer.ts new file mode 100644 index 0000000000..64c33a5c4e --- /dev/null +++ b/packages/types/src/shell/type/config-transducer.ts @@ -0,0 +1,9 @@ +import { IPublicTypeSkeletonConfig } from '.'; + +export interface IPublicTypeConfigTransducer { + (prev: IPublicTypeSkeletonConfig): IPublicTypeSkeletonConfig; + + level?: number; + + id?: string; +} diff --git a/packages/types/src/shell/type/index.ts b/packages/types/src/shell/type/index.ts index 7232ffbbdc..b2fd3313f9 100644 --- a/packages/types/src/shell/type/index.ts +++ b/packages/types/src/shell/type/index.ts @@ -91,3 +91,4 @@ export * from './hotkey-callback-config'; export * from './hotkey-callbacks'; export * from './scrollable'; export * from './simulator-renderer'; +export * from './config-transducer'; \ No newline at end of file From 7e80d1f863f934720915df35db3b27415a11ebb7 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 23 Nov 2023 16:33:45 +0800 Subject: [PATCH 083/219] chore(docs): publish docs 1.2.1 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index cb3cb946dc..14d0c99e55 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.0", + "version": "1.2.1", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From dc1e0f5a49a81b3fb8c47b4a1495d06e16798fde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=94=90=E6=BE=9C?= <1ncounter.100@gmail.com> Date: Thu, 23 Nov 2023 18:58:24 +0800 Subject: [PATCH 084/219] Fix/component lifecycle not execute (#2690) * fix: recover component lifecycle and avoid execute from scope __proto__ From 6c7a52652131b0a18a03bf6f90b8730544b8be34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=94=90=E6=BE=9C?= <1ncounter.100@gmail.com> Date: Thu, 23 Nov 2023 19:28:41 +0800 Subject: [PATCH 085/219] Fix/component lifecycle not execute (#2692) * fix: recover component lifecycle and avoid execute from scope __proto__ From c643c0fc4f4c9eb90b8d273447fef04d28cfe13d Mon Sep 17 00:00:00 2001 From: 1ncounter <1ncounter.100@gmail.com> Date: Thu, 23 Nov 2023 19:35:37 +0800 Subject: [PATCH 086/219] fix(renderer-core): remove compatibility with uipaas --- packages/renderer-core/src/renderer/base.tsx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index dddc55e838..ac4b1de125 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -50,11 +50,6 @@ export function executeLifeCycleMethod(context: any, schema: IPublicTypeNodeSche return; } - // avoid execute lifeCycle method from __proto__'s method (it is React class Component Class lifeCycle) - if (!Object.prototype.hasOwnProperty.call(context, method) && method !== 'constructor') { - return; - } - // TODO: cache if (isJSExpression(fn) || isJSFunction(fn)) { fn = thisRequiredInJSE ? parseThisRequiredExpression(fn, context) : parseExpression(fn, context); From 1c2f195e8bce05284419eb7bbbba33bb97acf30e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= <liujup@foxmail.com> Date: Mon, 27 Nov 2023 16:22:29 +0800 Subject: [PATCH 087/219] docs: update skeleton.md --- docs/docs/api/skeleton.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/docs/api/skeleton.md b/docs/docs/api/skeleton.md index 90cf1a2c17..5bfa239724 100644 --- a/docs/docs/api/skeleton.md +++ b/docs/docs/api/skeleton.md @@ -69,6 +69,7 @@ skeleton.add({ props: { align: "left", icon: "wenjian", + title: '标题', // 图标下方展示的标题 description: "JS 面板", }, panelProps: { From 20bf62aed3c67753c265c38dffaa5e5a31c2b4ee Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Mon, 27 Nov 2023 17:50:48 +0800 Subject: [PATCH 088/219] chore(docs): publish docs 1.2.2 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 14d0c99e55..e9d5b87b43 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.1", + "version": "1.2.2", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From d41f2c13d24a0270616ae4d2d2484e347ca02573 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= <liujup@foxmail.com> Date: Mon, 27 Nov 2023 21:40:25 +0800 Subject: [PATCH 089/219] docs: update material.md --- docs/docs/api/material.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/docs/docs/api/material.md b/docs/docs/api/material.md index 8b1214476b..51ed4e3054 100644 --- a/docs/docs/api/material.md +++ b/docs/docs/api/material.md @@ -116,6 +116,21 @@ material.setAssets(assets1); material.loadIncrementalAssets(assets2); ``` +更新特定物料的描述文件 + +```typescript +import { material } from '@alilc/lowcode-engine'; +material.loadIncrementalAssets({ + version: '', + components: [ + { + "componentName": 'Button', + "props": [{ name: 'new', title: 'new', propType: 'string' }] + } + ], +}) +``` + ### 设计器辅助层 #### addBuiltinComponentAction 在设计器辅助层增加一个扩展 action From f75b9ae61cdc46618038b3fe43e6744aa8d56f5c Mon Sep 17 00:00:00 2001 From: owenchen1004 <yoga981004@gmail.com> Date: Tue, 28 Nov 2023 10:50:38 +0800 Subject: [PATCH 090/219] fix: executeLifeCycleMethod return bug in renderer --- packages/renderer-core/src/renderer/base.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index 1980734e43..640763538a 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -182,7 +182,7 @@ export default function baseRendererFactory(): IBaseRenderComponent { __afterInit(_props: IBaseRendererProps) { } static getDerivedStateFromProps(props: IBaseRendererProps, state: any) { - return executeLifeCycleMethod(this, props?.__schema, 'getDerivedStateFromProps', [props, state], props.thisRequiredInJSE); + return executeLifeCycleMethod(this, props?.__schema, 'getDerivedStateFromProps', [props, state], props.thisRequiredInJSE) || null; } async getSnapshotBeforeUpdate(...args: any[]) { From b786c8fcaad1376d1d4d1316f75e283418f93913 Mon Sep 17 00:00:00 2001 From: owenchen1004 <yoga981004@gmail.com> Date: Tue, 28 Nov 2023 11:04:37 +0800 Subject: [PATCH 091/219] fix: coding style update --- packages/renderer-core/src/renderer/base.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index 640763538a..ebaa8eadc8 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -182,7 +182,8 @@ export default function baseRendererFactory(): IBaseRenderComponent { __afterInit(_props: IBaseRendererProps) { } static getDerivedStateFromProps(props: IBaseRendererProps, state: any) { - return executeLifeCycleMethod(this, props?.__schema, 'getDerivedStateFromProps', [props, state], props.thisRequiredInJSE) || null; + const result = executeLifeCycleMethod(this, props?.__schema, 'getDerivedStateFromProps', [props, state], props.thisRequiredInJSE); + return result === undefined ? null : result; } async getSnapshotBeforeUpdate(...args: any[]) { From d199b44eca0b1fe47d1744421a275188f69533e1 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 28 Nov 2023 16:11:04 +0800 Subject: [PATCH 092/219] style: add --color-toolbar-background --- docs/docs/guide/expand/editor/theme.md | 73 +++++++++++++++---- .../src/layouts/workbench.less | 2 +- 2 files changed, 59 insertions(+), 16 deletions(-) diff --git a/docs/docs/guide/expand/editor/theme.md b/docs/docs/guide/expand/editor/theme.md index 94e434580d..16bcf04b09 100644 --- a/docs/docs/guide/expand/editor/theme.md +++ b/docs/docs/guide/expand/editor/theme.md @@ -3,23 +3,46 @@ title: 主题色扩展 sidebar_position: 9 --- -## 主题色扩展简述 +## 简介 -通过主题色扩展,可以定制多种设计器主题。 +主题色扩展允许用户定制多样的设计器主题,增加界面的个性化和品牌识别度。 -## 主题色扩展说明 +## 设计器主题色定制 + +在 CSS 的根级别定义主题色变量可以确保这些变量在整个应用中都可用。例如: + +```css +:root { + --color-brand: rgba(0, 108, 255, 1); /* 主品牌色 */ + --color-brand-light: rgba(25, 122, 255, 1); /* 浅色品牌色 */ + --color-brand-dark: rgba(0, 96, 229, 1); /* 深色品牌色 */ +} + +``` + +将样式文件引入到你的设计器中,定义的 CSS 变量就可以改变设计器的主题色了。 ### 主题色变量 -- `--color-brand`: 品牌色 -- `--color-brand-light`: 品牌色(light) -- `--color-brand-dark`: 品牌色(dark) -- `--color-icon-normal`: 正常 icon 颜色 -- `--color-icon-hover`: icon hover 态颜色 -- `--color-icon-active`: icon active 态颜色 -- `--color-icon-reverse`: icon 反色 -- `--color-icon-disabled`: icon 禁用态颜色 -- `--color-icon-pane`: icon 面板颜色 +以下是低代码引擎设计器支持的主题色变量列表,以及它们的用途说明: + +#### 品牌相关颜色 + +- `--color-brand`: 主品牌色 +- `--color-brand-light`: 浅色品牌色 +- `--color-brand-dark`: 深色品牌色 + +#### Icon 相关颜色 + +- `--color-icon-normal`: 默认状态 +- `--color-icon-hover`: 鼠标悬停状态 +- `--color-icon-active`: 激活状态 +- `--color-icon-reverse`: 反色状态 +- `--color-icon-disabled`: 禁用状态 +- `--color-icon-pane`: 面板颜色 + +#### 线条和文本颜色 + - `--color-line-normal`: 线条颜色 - `--color-line-darken`: 线条颜色(darken) - `--color-title`: 标题颜色 @@ -29,6 +52,9 @@ sidebar_position: 9 - `--color-text-reverse`: 反色情况下,文字颜色 - `--color-text-regular`: 文字颜色(regular) - `--color-text-disabled`: 禁用态文字颜色 + +#### 字段和边框颜色 + - `--color-field-label`: field 标签颜色 - `--color-field-text`: field 文本颜色 - `--color-field-placeholder`: field placeholder 颜色 @@ -36,6 +62,9 @@ sidebar_position: 9 - `--color-field-border-hover`: hover 态下,field 边框颜色 - `--color-field-border-active`: active 态下,field 边框颜色 - `--color-field-background`: field 背景色 + +#### 状态颜色 + - `--color-success`: success 颜色 - `--colo-success-dark`: success 颜色(dark) - `--color-success-light`: success 颜色(light) @@ -50,7 +79,9 @@ sidebar_position: 9 - `--color-error-light`: error 颜色(light) - `--color-purple`: purple 颜色 - `--color-brown`: brown 颜色 -- `--color-pane-background`: 面板背景色 + +#### 区块背景色 + - `--color-block-background-normal`: 区块背景色 - `--color-block-background-light`: 区块背景色(light), 作用于画布组件 hover 时遮罩背景色。 - `--color-block-background-shallow`: 区块背景色 shallow @@ -61,20 +92,30 @@ sidebar_position: 9 - `--color-block-background-error`: 区块背景色(error) - `--color-block-background-success`: 区块背景色(success) - `--color-block-background-deep-dark`: 区块背景色(deep-dark),作用于多个组件同时拖拽的背景色。 + +#### 其他区域背景色 + - `--color-layer-mask-background`: 拖拽元素时,元素原来位置的遮罩背景色 - `--color-layer-tooltip-background`: tooltip 背景色 +- `--color-pane-background`: 面板背景色 - `--color-background`: 设计器主要背景色 - `--color-top-area-background`: topArea 背景色,优先级大于 `--color-pane-background` - `--color-left-area-background`: leftArea 背景色,优先级大于 `--color-pane-background` +- `--color-toolbar-background`: toolbar 背景色,优先级大于 `--color-pane-background` - `--color-workspace-left-area-background`: 应用级 leftArea 背景色,优先级大于 `--color-pane-background` - `--color-workspace-top-area-background`: 应用级 topArea 背景色,优先级大于 `--color-pane-background` - `--color-workspace-sub-top-area-background`: 应用级二级 topArea 背景色,优先级大于 `--color-pane-background` + +#### 其他变量 + - `--workspace-sub-top-area-height`: 应用级二级 topArea 高度 - `--workspace-sub-top-area-margin`: 应用级二级 topArea margin - `--workspace-sub-top-area-padding`: 应用级二级 topArea padding - `--workspace-left-area-width`: 应用级 leftArea width -### 生态使用主题色变量 + + +### 低代码引擎生态主题色定制 插件、物料、设置器等生态为了支持主题色需要对样式进行改造,需要对生态中的样式升级为 css 变量。例如: @@ -87,6 +128,8 @@ background: var(--color-brand, #006cff); ``` +这里 `var(--color-brand, #默认色)` 表示使用 `--color-brand` 变量,如果该变量未定义,则使用默认颜色(#默认色)。 + ### fusion 物料进行主题色扩展 -如果使用了 fusion 组件,可以通过 https://fusion.alibaba-inc.com/ 平台进行主题色定制。 \ No newline at end of file +如果使用了 fusion 组件时,可以通过 [fusion 平台](https://fusion.design/) 进行主题色定制。在平台上,您可以选择不同的主题颜色,并直接应用于您的 fusion 组件,这样可以无缝地集成到您的应用设计中。 \ No newline at end of file diff --git a/packages/editor-skeleton/src/layouts/workbench.less b/packages/editor-skeleton/src/layouts/workbench.less index eb86bfe04c..1f0eae8ec8 100644 --- a/packages/editor-skeleton/src/layouts/workbench.less +++ b/packages/editor-skeleton/src/layouts/workbench.less @@ -366,7 +366,7 @@ body { .lc-toolbar { display: flex; height: var(--toolbar-height); - background-color: var(--color-pane-background); + background-color: var(--color-toolbar-background, var(--color-pane-background)); padding: 8px 16px; .lc-toolbar-center { display: flex; From d703e64ac958de5e91d34f4741b49b94a6b467ea Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Wed, 29 Nov 2023 11:10:29 +0800 Subject: [PATCH 093/219] chore(docs): publish docs 1.2.3 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index e9d5b87b43..00887a7588 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.2", + "version": "1.2.3", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 19bf6ad28456feab9b58de3a00023898c72d8fde Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 29 Nov 2023 11:29:33 +0800 Subject: [PATCH 094/219] style: add --color-toolbar-background --- packages/editor-skeleton/src/layouts/workbench.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/editor-skeleton/src/layouts/workbench.less b/packages/editor-skeleton/src/layouts/workbench.less index 1f0eae8ec8..2cddb25372 100644 --- a/packages/editor-skeleton/src/layouts/workbench.less +++ b/packages/editor-skeleton/src/layouts/workbench.less @@ -452,7 +452,7 @@ body { .lc-toolbar { display: flex; height: var(--toolbar-height); - background-color: var(--color-pane-background); + background-color: var(--color-toolbar-background, var(--color-pane-background)); padding: 8px 16px; .lc-toolbar-center { display: flex; From 1a328bd1f63a27074ba4b07c9b866ef85038e6e2 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 30 Nov 2023 17:36:55 +0800 Subject: [PATCH 095/219] style: fix --workspace-left-area-width style bug --- docs/docs/guide/expand/editor/theme.md | 1 + packages/editor-skeleton/src/layouts/workbench.less | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/docs/docs/guide/expand/editor/theme.md b/docs/docs/guide/expand/editor/theme.md index 16bcf04b09..35a77f2ac6 100644 --- a/docs/docs/guide/expand/editor/theme.md +++ b/docs/docs/guide/expand/editor/theme.md @@ -112,6 +112,7 @@ sidebar_position: 9 - `--workspace-sub-top-area-margin`: 应用级二级 topArea margin - `--workspace-sub-top-area-padding`: 应用级二级 topArea padding - `--workspace-left-area-width`: 应用级 leftArea width +- `--left-area-width`: leftArea width diff --git a/packages/editor-skeleton/src/layouts/workbench.less b/packages/editor-skeleton/src/layouts/workbench.less index 2cddb25372..565b6f07d7 100644 --- a/packages/editor-skeleton/src/layouts/workbench.less +++ b/packages/editor-skeleton/src/layouts/workbench.less @@ -443,6 +443,10 @@ body { min-height: 0; position: relative; + > .lc-left-float-pane { + left: calc(var(--workspace-left-area-width, var(--left-area-width)) + 1px); + } + .lc-workspace-workbench-center { flex: 1; display: flex; From 8f5ba69813bf4cf1a3b084c2a1eb24f2dbc8be35 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 1 Dec 2023 14:23:29 +0800 Subject: [PATCH 096/219] docs: add meet docs --- docs/docs/participate/meet.md | 55 +++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 docs/docs/participate/meet.md diff --git a/docs/docs/participate/meet.md b/docs/docs/participate/meet.md new file mode 100644 index 0000000000..23226bf1cd --- /dev/null +++ b/docs/docs/participate/meet.md @@ -0,0 +1,55 @@ +--- +title: 开源社区例会 +sidebar_position: 0 +--- + +## **简介** + +低代码引擎开源社区致力于共同推动低代码技术的发展和创新。本社区汇集了低代码技术领域的开发者、技术专家和行业观察者,通过定期的例会来交流思想、分享经验、讨论新技术,并探索低代码技术的未来发展方向。 + +## 参与要求 + +为了确保例会的质量和效果,我们建议以下人员参加: + +- **已参与低代码引擎贡献的成员**:那些对低代码引擎有实际贡献的社区成员。 +- **参考贡献指南**:可查阅[贡献指南](https://lowcode-engine.cn/site/docs/participate/)获取更多信息。 +- **提供过优秀建议的成员**:那些在过去为低代码引擎提供过有价值建议的成员。 + +## **时间周期** + +- **周期性**:月例会 + +### **特别说明** + +- 例会周期可根据成员反馈进行调整。如果讨论的议题较多,可增加例会频率;若议题较少,单次例会可能取消。若多次取消,可能会暂停例会。 + +## **例会流程** + +### **准备阶段** + +- **定期确定议题**:会前一周确定下一次会议的议题。 +- **分发会议通知**:提前发送会议时间、议程和参与方式。 + +### **会议阶段** + +- **开场和介绍**:简短开场和自我介绍,特别是新成员加入时。 +- **议题讨论**:按照议程进行议题讨论,每个议题分配一定时间,并留足够时间供讨论和提问。 +- **记录要点和决定**:记录讨论要点、决策和任何行动事项。 + +### **后续阶段** + +- **分享会议纪要**:会后将会议纪要和行动计划分发给所有成员。 +- **执行和跟进**:根据会议中的讨论和决策执行相关任务,并在下次会议中进行跟进汇报。 + +## **开源例会议题** + +开源例会议题包括但不限于: + +- **共建低代码行业发展**:探讨通过开源社区合作加速低代码行业发展。 +- **改进建议和反馈收集**:讨论社区成员对低代码引擎的使用体验和改进建议。 +- **前端技术与低代码的结合**:针对前端开发者,讨论将前端技术与低代码引擎结合的方式。 +- **低代码业务场景和经验分享**:邀请社区成员分享低代码引擎的实际应用经验。 +- **低代码技术原理介绍**:深入理解低代码引擎的技术原理和实现方式。 +- **低代码引擎的最新进展**:分享低代码引擎的最新进展,包括新版本发布和新功能实现等。 +- **低代码技术的未来展望**:讨论低代码技术的未来发展方向。 +- **最新低代码平台功能和趋势分析**:分享和讨论当前低代码平台的新功能、趋势和发展方向。 \ No newline at end of file From ebdcc4146135ae3d41c8cf79024e9247238a8c63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=94=90=E6=BE=9C?= <1ncounter.100@gmail.com> Date: Fri, 1 Dec 2023 15:27:30 +0800 Subject: [PATCH 097/219] fix: scope props merge defaultProps (#2716) --- packages/renderer-core/src/renderer/base.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index f6930e86d5..9d9e88ab59 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -429,7 +429,14 @@ export default function baseRendererFactory(): IBaseRenderComponent { __createDom = () => { const { __schema, __ctx, __components = {} } = this.props; - const scope: any = {}; + // merge defaultProps + const scopeProps = { + ...__schema.defaultProps, + ...this.props, + }; + const scope: any = { + props: scopeProps, + }; scope.__proto__ = __ctx || this; const _children = getSchemaChildren(__schema); From 4d03610fd3b6d056fa7ce35f127cf7a90f99dd6c Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 30 Nov 2023 20:38:12 +0800 Subject: [PATCH 098/219] feat: update types define --- packages/types/src/shell/type/plugin-config.ts | 4 ++-- packages/types/src/shell/type/resource-type-config.ts | 3 ++- packages/types/src/shell/type/resource-type.ts | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/types/src/shell/type/plugin-config.ts b/packages/types/src/shell/type/plugin-config.ts index e9e65192e0..2d841dd804 100644 --- a/packages/types/src/shell/type/plugin-config.ts +++ b/packages/types/src/shell/type/plugin-config.ts @@ -1,5 +1,5 @@ export interface IPublicTypePluginConfig { - init(): Promise<void>; - destroy?(): Promise<void>; + init(): Promise<void> | void; + destroy?(): Promise<void> | void; exports?(): any; } diff --git a/packages/types/src/shell/type/resource-type-config.ts b/packages/types/src/shell/type/resource-type-config.ts index 474987b529..01b49aa2bd 100644 --- a/packages/types/src/shell/type/resource-type-config.ts +++ b/packages/types/src/shell/type/resource-type-config.ts @@ -1,3 +1,4 @@ +import React from 'react'; import { IPublicTypeEditorView } from './editor-view'; export interface IPublicResourceTypeConfig { @@ -6,7 +7,7 @@ export interface IPublicResourceTypeConfig { description?: string; /** 资源 icon 标识 */ - icon?: React.ReactElement; + icon?: React.ReactElement | React.FunctionComponent | React.ComponentClass; /** * 默认视图类型 diff --git a/packages/types/src/shell/type/resource-type.ts b/packages/types/src/shell/type/resource-type.ts index 7cfb125aaf..7d64a4463d 100644 --- a/packages/types/src/shell/type/resource-type.ts +++ b/packages/types/src/shell/type/resource-type.ts @@ -4,7 +4,7 @@ import { IPublicResourceTypeConfig } from './resource-type-config'; export interface IPublicTypeResourceType { resourceName: string; - resourceType: 'editor' | 'webview'; + resourceType: 'editor' | 'webview' | string; (ctx: IPublicModelPluginContext, options: Object): IPublicResourceTypeConfig; } \ No newline at end of file From 70845a1eca349c5786101119537ff9664fbe9056 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Tue, 5 Dec 2023 09:32:21 +0800 Subject: [PATCH 099/219] chore(docs): publish docs 1.2.4 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 00887a7588..d5d42cf96d 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.3", + "version": "1.2.4", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 0a50cf5a0d351fd3f140f4893140193f6aa5231c Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 5 Dec 2023 13:05:08 +0800 Subject: [PATCH 100/219] docs: update participate docs --- docs/docs/participate/config.md | 88 -------------------- docs/docs/participate/doc.md | 25 ------ docs/docs/participate/index.md | 133 ++++++++++++++++++++++++++----- docs/docs/participate/prepare.md | 64 --------------- 4 files changed, 114 insertions(+), 196 deletions(-) delete mode 100644 docs/docs/participate/config.md delete mode 100644 docs/docs/participate/doc.md delete mode 100644 docs/docs/participate/prepare.md diff --git a/docs/docs/participate/config.md b/docs/docs/participate/config.md deleted file mode 100644 index 1d70a7a89e..0000000000 --- a/docs/docs/participate/config.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -title: 工程化配置 -sidebar_position: 3 ---- -目前引擎体系共包含 2 个 js 文件 (配套 2 个 css),即: - - -```html -<!-- 低代码引擎的页面框架样式 --> -<link rel="stylesheet" href="https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/1.0.18/dist/css/engine-core.css" /> -<!-- 低代码引擎官方扩展的样式 --> -<link rel="stylesheet" href="https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine-ext/1.0.5/dist/css/engine-ext.css" /> - -<!-- 低代码引擎的主包 --> -<script crossorigin="anonymous" src="https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/1.0.18/dist/js/engine-core.js"></script> -<!-- 低代码引擎官方扩展的主包 --> -<script crossorigin="anonymous" src="https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine-ext/1.0.5/dist/js/engine-ext.js"></script> -``` - -> 注,这里的版本号是示例,请尽量选用最新版 - -工程化配置我们进行了统一,具体如下: -```shell -{ - "entry": { - ... - }, - "library": "...", - "libraryTarget": "umd", - "externals": { - "react": "var window.React", - "react-dom": "var window.ReactDOM", - "prop-types": "var window.PropTypes", - "@alilc/lowcode-engine": "var window.AliLowCodeEngine", - "@alilc/lowcode-engine-ext": "var window.AliLowCodeEngineExt", - "moment": "var moment", - "lodash": "var _", - "@alifd/next": "var Next" - }, - "polyfill": false, - "outputDir": "dist", - "vendor": false, - "ignoreHtmlTemplate": true, - "sourceMap": true, - "plugins": [ - "build-plugin-react-app", - ["build-plugin-fusion", { - }], - ["build-plugin-moment-locales", { - "locales": ["zh-CN"] - }], - "./build.plugin.js" - ] -} - -``` -总结一下,有 2 点: - -1. **都不包含 polyfill,**需要应用级别单独引入 polyfill,推荐动态 polyfill -2. **都不包含 lodash / moment / next** - - -#### 前置依赖资源: -```html -<link rel="stylesheet" href="//alifd.alicdn.com/npm/@alifd/next/1.20.25/next.min.css"> - -<script src="//polyfill.alicdn.com/s/polyfill.min.js?features=default,es2017,es6,fetch,RegeneratorRuntime"></script> -<script src="//alifd.alicdn.com/npm/@alifd/next/1.20.25/next.min.js"></script> -<script src="//g.alicdn.com/platform/c/lodash/4.6.1/lodash.min.js"></script> -<script src="//g.alicdn.com/mylib/moment/2.24.0/min/moment.min.js"></script> -``` - - -#### 所有资源: -```html -<link rel="stylesheet" href="//alifd.alicdn.com/npm/@alifd/next/1.20.25/next.min.css"> -<link rel="stylesheet" href="//uipaas-assets.com/prod/npm/@alilc/lowcode-engine/1.0.18/dist/css/engine-core.css"/> -<link rel="stylesheet" href="//uipaas-assets.com/prod/npm/@alilc/lowcode-engine/1.0.5/dist/css/engine-ext.css"/> - -<script src="//polyfill.alicdn.com/s/polyfill.min.js?features=default,es2017,es6,fetch,RegeneratorRuntime"></script> -<script src="//alifd.alicdn.com/npm/@alifd/next/1.20.25/next.min.js"></script> -<script src="//g.alicdn.com/platform/c/lodash/4.6.1/lodash.min.js"></script> -<script src="//g.alicdn.com/mylib/moment/2.24.0/min/moment.min.js"></script> -<!-- engine-core 引擎的 core,负责引擎的基础模块 --> -<script crossorigin="anonymous" src="//uipaas-assets.com/prod/npm/@alilc/lowcode-engine/1.0.18/dist/js/engine-core.js"></script> -<!-- engine-ext 引擎的扩展包,负责收拢内置 setters / plugins,方便迭代 --> -<script crossorigin="anonymous" src="//uipaas-assets.com/prod/npm/@alilc/lowcode-engine/1.0.5/dist/js/engine-ext.js"></script> -``` diff --git a/docs/docs/participate/doc.md b/docs/docs/participate/doc.md deleted file mode 100644 index 1e19918db5..0000000000 --- a/docs/docs/participate/doc.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: 参与文档贡献 -sidebar_position: 3 ---- - -## 基本原则 - -### 维护方式 - -- 官方文档通过 github 管理文档源,官网文档与[主仓库 develop 分支](https://github.com/alibaba/lowcode-engine/tree/develop/docs)保持同步。 -- 点击每篇文档下发的 `编辑此页` 可直接定位到 github 中位置。 -- 欢迎 PR,文档 PR 也会作为贡献者贡献,会用于贡献度统计。 -- **文档同步到官方网站由官方人员进行操作**,如有需要可以通过 issue 或 贡献者群与相关人员沟通。 -- 为了提供更好的阅读和使用体验,文档中的图片文件会定期转换成可信的 CDN 地址。 - -### PR 提交注意事项 - -- 指向 develop 分支。 -- 涉及到图片的,需附在文档同级的 img 目录下,通过相对地址引用。 - -### 文档格式 - -本项目文档参考[文档编写指南](https://github.com/sparanoid/chinese-copywriting-guidelines)。 - -使用 vscode 进行编辑的朋友可以安装 vscode 插件 [huacnlee.autocorrect](https://github.com/huacnlee/autocorrect) 辅助文档 lint。 diff --git a/docs/docs/participate/index.md b/docs/docs/participate/index.md index ea87651ffd..4540fa640d 100644 --- a/docs/docs/participate/index.md +++ b/docs/docs/participate/index.md @@ -1,31 +1,126 @@ --- -title: 贡献者指南 +title: 参与贡献 sidebar_position: 0 --- -### 首个 Pull Request -在写第一个 Pull Request?你可以从这一系列视频中学习怎么做: -[How to Contribute to an Open Source Project on GitHub](https://egghead.io/courses/how-to-contribute-to-an-open-source-project-on-github) -为了使你能够快速上手和熟悉贡献流程,我们这里有个列表 [good first issues](https://github.com/alibaba/lowcode-engine/issues?q=is:open+is:issue+label:%22good+first+issue%22),里面有相对没那么笼统的漏洞,从这开始是个不错的选择。 +### 环境准备 + +开发 LowcodeEngine 需要 Node.js 16+。 + +推荐使用 nvm 管理 Node.js,避免权限问题的同时,还能够随时切换当前使用的 Node.js 的版本。 + +### 贡献低代码引擎 + +#### clone 项目 + +``` +git clone git@github.com:alibaba/lowcode-engine.git +cd lowcode-engine +``` + +#### 安装依赖并构建 + +``` +npm install && npm run setup +``` + +#### 调试环境配置 + +本质上是将 demo 页面引入的几个 js/css 代理到 engine 项目,可以使用趁手的代理工具,这里推荐 [XSwitch](https://chrome.google.com/webstore/detail/xswitch/idkjhjggpffolpidfkikidcokdkdaogg?hl=en-US)。 + +本地开发代理规则如下: +```json +{ + "proxy": [ + [ + "https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/engine-core.js", + "http://localhost:5555/js/AliLowCodeEngine.js" + ], + [ + "https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/engine-core.css", + "http://localhost:5555/css/AliLowCodeEngine.css" + ], + [ + "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/react-simulator-renderer.js", + "http://localhost:5555/js/ReactSimulatorRenderer.js" + ], + [ + "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/react-simulator-renderer.css", + "http://localhost:5555/css/ReactSimulatorRenderer.css" + ], + [ + "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/rax-simulator-renderer.js", + "http://localhost:5555/js/RaxSimulatorRenderer.js" + ], + [ + "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/rax-simulator-renderer.css", + "http://localhost:5555/css/RaxSimulatorRenderer.css" + ], + ] +} +``` + +#### 开发 + +``` +npm start +``` + +选择一个环境进行调试,例如[低代码引擎在线 DEMO](https://lowcode-engine.cn/demo/demo-general/index.html) + +开启代理之后,就可以进行开发调试了。 -如果你想解决一个 issue,请确定检查了该 issue 下的评论以防有人正在处理它。如果目前没人在处理该 issue,那么请留下评论去表明你想处理该 issue 以便其他人不会意外重复你的工作。 -如果有人留言表明要处理该 issue 但是超过两周没有跟进,你可以接手工作,不过也应该留言说明。 +### 贡献低代码引擎文档 -### 提交 Pull Request -核心团队时刻关注 pull requests,我们会先评审你的 pull request,之后可能会合并,可能会要求再次更改,也可能会关闭该 pull request 并对此作出解释。我们会尽力全程更新和反馈。 +#### 开发文档 -**提交 pull request 前**,请确保完成以下步骤: +在 lowcode-engine 目录下执行下面命令 +``` +cd docs -1. Fork [此仓库](https://github.com/alibaba/lowcode-engine),从 main 创建分支。 -2. 在仓库根目录下执行 yarn。 -3. 如果你修复了 bug 或者添加了代码,而这些内容需要测试,请添加测试! -4. 确保通过测试套件(yarn test)。 -5. 请签订贡献者许可证协议(Contributor License Agreement)。 - > 如已签署 CLA 仍被提示需要签署,[解决办法](/site/docs/faq/faq021) +npm start +``` -### 核心贡献者交流 -如果你想长期参与到项目维护中,我们提供了一个核心贡献者交流群。 +#### 维护方式 +- 官方文档通过 github 管理文档源,官网文档与[主仓库 develop 分支](https://github.com/alibaba/lowcode-engine/tree/develop/docs)保持同步。 +- 点击每篇文档下发的 `编辑此页` 可直接定位到 github 中位置。 +- 欢迎 PR,文档 PR 也会作为贡献者贡献,会用于贡献度统计。 +- **文档同步到官方网站由官方人员进行操作**,如有需要可以通过 issue 或 贡献者群与相关人员沟通。 +- 为了提供更好的阅读和使用体验,文档中的图片文件会定期转换成可信的 CDN 地址。 + +#### 文档格式 + +本项目文档参考[文档编写指南](https://github.com/sparanoid/chinese-copywriting-guidelines)。 + +使用 vscode 进行编辑的朋友可以安装 vscode 插件 [huacnlee.autocorrect](https://github.com/huacnlee/autocorrect) 辅助文档 lint。 + + +### 贡献低代码引擎生态 + +相关源码详见[NPM 包对应源码位置汇总](/site/docs/guide/appendix/npms) + +开发调试方式详见[低代码生态脚手架 & 调试机制](/site/docs/guide/expand/editor/cli) + +### 发布 + +PR 被合并之后,我们会尽快发布相关的正式版本或者 beta 版本。 + +### 加入 Contributor 群 +提交过 Bugfix 或 Feature 类 PR 的同学,如果有兴趣一起参与维护 LowcodeEngine,我们提供了一个核心贡献者交流群。 1. 可以通过[填写问卷](https://survey.taobao.com/apps/zhiliao/4YEtu9gHF)的方式,参与到其中。 -2. 填写问卷后加微信号 `wxidvlalalalal` 说明一下。 +2. 填写问卷后加微信号 `wxidvlalalalal` (注明 github id)我们会拉你到群里。 + +如果你不知道可以贡献什么,可以到源码里搜 TODO 或 FIXME 找找。 + +为了使你能够快速上手和熟悉贡献流程,我们这里有个列表 [good first issues](https://github.com/alibaba/lowcode-engine/issues?q=is:open+is:issue+label:%22good+first+issue%22),里面有相对没那么笼统的漏洞,从这开始是个不错的选择。 + +### PR 提交注意事项 + +- lowcode-engine 仓库建议从 develop 创建分支,PR 指向 develop 分支。 +- 其他仓库从 main 分支创建分支,PR 指向 main 分支 +- 如果你修复了 bug 或者添加了代码,而这些内容需要测试,请添加测试! +- 确保通过测试套件(yarn test)。 +- 请签订贡献者许可证协议(Contributor License Agreement)。 + > 如已签署 CLA 仍被提示需要签署,[解决办法](/site/docs/faq/faq021) \ No newline at end of file diff --git a/docs/docs/participate/prepare.md b/docs/docs/participate/prepare.md deleted file mode 100644 index acb0947f22..0000000000 --- a/docs/docs/participate/prepare.md +++ /dev/null @@ -1,64 +0,0 @@ ---- -title: 调试环境配置 -sidebar_position: 1 ---- -低代码引擎的核心仓库是不包含任何物料、插件、setter 的,它本身用于生成低代码引擎的主包。 - -如果您需要对低代码的主包进行开发和调试,需要用到本文里介绍的知识。 - -如果您需要对低代码编辑器进行定制,您可能只需要 clone [lowcode-demo 项目](https://github.com/alibaba/lowcode-demo)并进行修改,参考“[配置低代码扩展点](/site/docs/guide/expand/editor/summary)”章节。 - -> 前置条件: -> node 推荐使用 16.18.0(14.x 也可以) - -### 1. 拉取代码,启动项目 -```bash -git clone git@github.com:alibaba/lowcode-engine.git -cd lowcode-engine -npm install && npm run setup -npm start - - -git clone git@github.com:alibaba/lowcode-demo.git -cd lowcode-demo -npm install && npm start -``` - -### 2. 配置资源代理 -本质上是将 demo 页面引入的几个 js/css 代理到 engine 项目,可以使用趁手的代理工具,这里推荐 [XSwitch](https://chrome.google.com/webstore/detail/xswitch/idkjhjggpffolpidfkikidcokdkdaogg?hl=en-US)。 - -本地开发代理规则如下: -```json -{ - "proxy": [ - [ - "https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/engine-core.js", - "http://localhost:5555/js/AliLowCodeEngine.js" - ], - [ - "https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/engine-core.css", - "http://localhost:5555/css/AliLowCodeEngine.css" - ], - [ - "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/react-simulator-renderer.js", - "http://localhost:5555/js/ReactSimulatorRenderer.js" - ], - [ - "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/react-simulator-renderer.css", - "http://localhost:5555/css/ReactSimulatorRenderer.css" - ], - [ - "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/rax-simulator-renderer.js", - "http://localhost:5555/js/RaxSimulatorRenderer.js" - ], - [ - "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/rax-simulator-renderer.css", - "http://localhost:5555/css/RaxSimulatorRenderer.css" - ], - ] -} -``` - -### 3. 本地调试物料/插件/设置器 - -详见[低代码生态脚手架 & 调试机制](/site/docs/guide/expand/editor/cli) From 28fdf9a37d04fc4c5d942aca4f87511bb0f901fe Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Tue, 5 Dec 2023 13:29:16 +0800 Subject: [PATCH 101/219] chore(docs): publish docs 1.2.5 --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index d5d42cf96d..75704e688c 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.4", + "version": "1.2.5", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From a87dcaada18eb28d0b67fa99e4ab82ca1d552d7d Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 5 Dec 2023 15:25:28 +0800 Subject: [PATCH 102/219] chore: create publish docs.yml --- .github/workflows/publish docs.yml | 51 ++++++++++++++++++++++++++++++ docs/package.json | 2 +- 2 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/publish docs.yml diff --git a/.github/workflows/publish docs.yml b/.github/workflows/publish docs.yml new file mode 100644 index 0000000000..dcbeec3844 --- /dev/null +++ b/.github/workflows/publish docs.yml @@ -0,0 +1,51 @@ +name: Update and Publish Docs + +on: + push: + branches: + - develop + paths: + - 'docs/**' + +jobs: + publish-docs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js + uses: actions/setup-node@v2 + with: + node-version: '14' + registry-url: 'https://registry.npmjs.org' + - run: cd docs && npm install + - run: | + cd docs + npm version patch + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + git add package.json + git commit -m "Update package version" + git push + - run: cd docs && npm publish + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + - name: Get version + id: get_version + run: echo "::set-output name=version::$(node -p "require('./docs/package.json').version")" + + comment-pr: + needs: publish-docs + runs-on: ubuntu-latest + steps: + - name: Comment on PR + if: github.event_name == 'pull_request' && github.event.action == 'closed' && github.event.pull_request.merged == true + uses: actions/github-script@v4 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + github.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: '🚀 New version has been released: ' + '${{ needs.publish-docs.outputs.version }}' + }) \ No newline at end of file diff --git a/docs/package.json b/docs/package.json index 75704e688c..8af810d33e 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.5", + "version": "1.2.6", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 77aea1bfbafe4315e8488417d862d820e81dd573 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Tue, 5 Dec 2023 07:29:34 +0000 Subject: [PATCH 103/219] Update package version --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 8af810d33e..634f73bee1 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.6", + "version": "1.2.7", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 398f06974571a05af5b03b3d7c651c3f604f5967 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 5 Dec 2023 14:42:28 +0800 Subject: [PATCH 104/219] style: add css themes vars --- docs/docs/guide/expand/editor/theme.md | 11 ++++++++++- .../designer/src/builtin-simulator/host.less | 8 ++++---- packages/editor-skeleton/src/layouts/theme.less | 2 +- .../editor-skeleton/src/layouts/workbench.less | 16 ++++++++-------- .../types/src/shell/type/widget-base-config.ts | 5 +++++ 5 files changed, 28 insertions(+), 14 deletions(-) diff --git a/docs/docs/guide/expand/editor/theme.md b/docs/docs/guide/expand/editor/theme.md index 35a77f2ac6..36500cb458 100644 --- a/docs/docs/guide/expand/editor/theme.md +++ b/docs/docs/guide/expand/editor/theme.md @@ -50,7 +50,6 @@ sidebar_position: 9 - `--color-text-dark`: 文字颜色(dark) - `--color-text-light`: 文字颜色(light) - `--color-text-reverse`: 反色情况下,文字颜色 -- `--color-text-regular`: 文字颜色(regular) - `--color-text-disabled`: 禁用态文字颜色 #### 字段和边框颜色 @@ -109,10 +108,20 @@ sidebar_position: 9 #### 其他变量 - `--workspace-sub-top-area-height`: 应用级二级 topArea 高度 +- `--top-area-height`: 顶部区域的高度 - `--workspace-sub-top-area-margin`: 应用级二级 topArea margin - `--workspace-sub-top-area-padding`: 应用级二级 topArea padding - `--workspace-left-area-width`: 应用级 leftArea width - `--left-area-width`: leftArea width +- `--simulator-top-distance`: simulator 距离容器顶部的距离 +- `--simulator-bottom-distance`: simulator 距离容器底部的距离 +- `--simulator-left-distance`: simulator 距离容器左边的距离 +- `--simulator-right-distance`: simulator 距离容器右边的距离 +- `--toolbar-padding`: toolbar 的 padding +- `--toolbar-height`: toolbar 的高度 +- `--pane-title-height`: 面板标题高度 +- `--pane-title-font-size`: 面板标题字体大小 +- `--pane-title-padding`: 面板标题边距 diff --git a/packages/designer/src/builtin-simulator/host.less b/packages/designer/src/builtin-simulator/host.less index 7130c42972..9a00963f24 100644 --- a/packages/designer/src/builtin-simulator/host.less +++ b/packages/designer/src/builtin-simulator/host.less @@ -73,10 +73,10 @@ } &-device-default { - top: 16px; - right: 16px; - bottom: 16px; - left: 16px; + top: var(--simulator-top-distance, 16px); + right: var(--simulator-right-distance, 16px); + bottom: var(--simulator-bottom-distance, 16px); + left: var(--simulator-left-distance, 16px); width: auto; box-shadow: 0 1px 4px 0 var(--color-block-background-shallow, rgba(31, 50, 88, 0.125)); } diff --git a/packages/editor-skeleton/src/layouts/theme.less b/packages/editor-skeleton/src/layouts/theme.less index 716ab3a99e..78c6fa5fd6 100644 --- a/packages/editor-skeleton/src/layouts/theme.less +++ b/packages/editor-skeleton/src/layouts/theme.less @@ -27,7 +27,6 @@ --color-text-dark: darken(@dark-alpha-3, 10%); --color-text-light: lighten(@dark-alpha-3, 10%); --color-text-reverse: @white-alpha-2; - --color-text-regular: @normal-alpha-2; --color-text-disabled: @gray-light; --color-field-label: @dark-alpha-4; @@ -87,4 +86,5 @@ --color-function-error-light: lighten(@brand-danger, 10%); --color-function-purple: rgb(144, 94, 190); --color-function-brown: #7b605b; + --color-text-regular: @normal-alpha-2; } diff --git a/packages/editor-skeleton/src/layouts/workbench.less b/packages/editor-skeleton/src/layouts/workbench.less index 565b6f07d7..596ea69f60 100644 --- a/packages/editor-skeleton/src/layouts/workbench.less +++ b/packages/editor-skeleton/src/layouts/workbench.less @@ -66,16 +66,16 @@ body { } } > .lc-panel-title { - height: 48px; - font-size: 16px; - padding: 0 15px; + height: var(--pane-title-height, 48px); + font-size: var(--pane-title-font-size, 16px); + padding: var(--pane-title-padding, 0 15px); color: var(--color-title, #0f1726); font-weight: bold; } .lc-panel-body { position: absolute; - top: 48px; + top: var(--pane-title-height, 48px); bottom: 0; left: 0; right: 0; @@ -234,7 +234,7 @@ body { .lc-pane-icon-close { position: absolute; right: 16px; - top: 14px; + top: calc(var(--pane-title-height, 48px) / 2 - 10px); height: auto; z-index: 2; .next-icon { @@ -247,7 +247,7 @@ body { .lc-pane-icon-float { position: absolute; right: 38px; - top: 14px; + top: calc(var(--pane-title-height, 48px) / 2 - 10px); height: auto; z-index: 2; svg { @@ -367,7 +367,7 @@ body { display: flex; height: var(--toolbar-height); background-color: var(--color-toolbar-background, var(--color-pane-background)); - padding: 8px 16px; + padding: var(--toolbar-padding, 8px 16px); .lc-toolbar-center { display: flex; justify-content: center; @@ -457,7 +457,7 @@ body { display: flex; height: var(--toolbar-height); background-color: var(--color-toolbar-background, var(--color-pane-background)); - padding: 8px 16px; + padding: var(--toolbar-padding, 8px 16px); .lc-toolbar-center { display: flex; justify-content: center; diff --git a/packages/types/src/shell/type/widget-base-config.ts b/packages/types/src/shell/type/widget-base-config.ts index edddf2d68f..b23ba0f137 100644 --- a/packages/types/src/shell/type/widget-base-config.ts +++ b/packages/types/src/shell/type/widget-base-config.ts @@ -15,6 +15,11 @@ export interface IPublicTypeWidgetBaseConfig { props?: Record<string, any>; content?: any; contentProps?: Record<string, any>; + + /** + * 优先级,值越小,优先级越高,优先级高的会排在前面 + */ + index?: number; } export interface IPublicTypePanelDockConfig extends IPublicTypeWidgetBaseConfig { From 3786b3a7ff09c4223f0b84fc15da58356c123694 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Tue, 5 Dec 2023 07:38:51 +0000 Subject: [PATCH 105/219] Update package version --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 634f73bee1..f175552e54 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.7", + "version": "1.2.8", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 1f214918bb5ce4d03132b78081eb63c815b0c347 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 7 Dec 2023 11:03:07 +0800 Subject: [PATCH 106/219] style: add css themes vars --- docs/docs/guide/expand/editor/theme.md | 8 +++++++- .../designer/src/builtin-simulator/bem-tools/borders.less | 2 +- packages/editor-skeleton/src/layouts/theme.less | 8 ++++++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/docs/docs/guide/expand/editor/theme.md b/docs/docs/guide/expand/editor/theme.md index 36500cb458..ef0e04d28d 100644 --- a/docs/docs/guide/expand/editor/theme.md +++ b/docs/docs/guide/expand/editor/theme.md @@ -35,6 +35,7 @@ sidebar_position: 9 #### Icon 相关颜色 - `--color-icon-normal`: 默认状态 +- `--color-icon-light`: icon light 状态 - `--color-icon-hover`: 鼠标悬停状态 - `--color-icon-active`: 激活状态 - `--color-icon-reverse`: 反色状态 @@ -82,16 +83,21 @@ sidebar_position: 9 #### 区块背景色 - `--color-block-background-normal`: 区块背景色 -- `--color-block-background-light`: 区块背景色(light), 作用于画布组件 hover 时遮罩背景色。 +- `--color-block-background-light`: 区块背景色(light)。 - `--color-block-background-shallow`: 区块背景色 shallow - `--color-block-background-dark`: 区块背景色(dark) - `--color-block-background-disabled`: 区块背景色(disabled) - `--color-block-background-active`: 区块背景色(active) +- `--color-block-background-active-light`: 区块背景色(active light) - `--color-block-background-warning`: 区块背景色(warning) - `--color-block-background-error`: 区块背景色(error) - `--color-block-background-success`: 区块背景色(success) - `--color-block-background-deep-dark`: 区块背景色(deep-dark),作用于多个组件同时拖拽的背景色。 +#### 引擎相关颜色 + +- `--color-canvas-detecting-background`: 画布组件 hover 时遮罩背景色。 + #### 其他区域背景色 - `--color-layer-mask-background`: 拖拽元素时,元素原来位置的遮罩背景色 diff --git a/packages/designer/src/builtin-simulator/bem-tools/borders.less b/packages/designer/src/builtin-simulator/bem-tools/borders.less index 43fba6a2b8..cb83d36f38 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/borders.less +++ b/packages/designer/src/builtin-simulator/bem-tools/borders.less @@ -100,7 +100,7 @@ &&-detecting { z-index: 1; border-style: dashed; - background: var(--color-block-background-light, rgba(0,121,242,.04)); + background: var(--color-canvas-detecting-background, rgba(0,121,242,.04)); } &&-selecting { diff --git a/packages/editor-skeleton/src/layouts/theme.less b/packages/editor-skeleton/src/layouts/theme.less index 78c6fa5fd6..01542c7584 100644 --- a/packages/editor-skeleton/src/layouts/theme.less +++ b/packages/editor-skeleton/src/layouts/theme.less @@ -14,6 +14,7 @@ --color-icon-normal: @normal-alpha-4; --color-icon-hover: @normal-alpha-3; + --color-icon-light: @normal-alpha-5; --color-icon-active: @brand-color-1; --color-icon-reverse: @white-alpha-1; --color-icon-disabled: @normal-alpha-6; @@ -55,10 +56,11 @@ --color-pane-background: @white-alpha-1; --color-block-background-normal: @white-alpha-1; --color-block-background-light: @normal-alpha-9; - --color-block-background-shallow: @normal-alpha-8; --color-block-background-dark: @normal-alpha-7; + --color-block-background-shallow: @normal-alpha-8; --color-block-background-disabled: @normal-alpha-6; - --color-block-background-active: @brand-color-1-7; + --color-block-background-active: @brand-color-1; + --color-block-background-active-light: @brand-color-1-7; --color-block-background-warning: @brand-warning-alpha-7; --color-block-background-error: @brand-danger-alpha-7; --color-block-background-success: @brand-success-alpha-7; @@ -67,6 +69,8 @@ --color-layer-tooltip-background: rgba(44,47,51,0.8); --color-background: #edeff3; + --color-canvas-detecting-background: rgba(0,121,242,.04); + --pane-title-bg-color: rgba(31,56,88,.04); } From 6932c3bdc7def44a7db971672469c18e5fbc2e63 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Thu, 7 Dec 2023 05:49:17 +0000 Subject: [PATCH 107/219] Update package version --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index f175552e54..a1b6d646f5 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.8", + "version": "1.2.9", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 014834a31f1ebbcfb21c8993534046d753540b99 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 13 Dec 2023 12:16:28 +0800 Subject: [PATCH 108/219] style(outline): update outline-filter-icon style --- packages/plugin-outline-pane/src/views/style.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugin-outline-pane/src/views/style.less b/packages/plugin-outline-pane/src/views/style.less index 15f115ea6b..8521883b49 100644 --- a/packages/plugin-outline-pane/src/views/style.less +++ b/packages/plugin-outline-pane/src/views/style.less @@ -28,7 +28,7 @@ } .lc-outline-filter-icon { - background: var(--color-block-background-shallow, #ebecf0); + background: var(--color-block-background-light, #ebecf0); border: 1px solid var(--color-field-border, #c4c6cf); display: flex; align-items: center; From a0975428c4c7301b9d678cf0c19e6e49c241ee79 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 13 Dec 2023 14:21:59 +0800 Subject: [PATCH 109/219] docs: add faq024 --- docs/docs/faq/faq024.md | 133 ++++++++++++++++++++++++++++++++++++++++ docs/docs/faq/index.md | 1 + 2 files changed, 134 insertions(+) create mode 100644 docs/docs/faq/faq024.md diff --git a/docs/docs/faq/faq024.md b/docs/docs/faq/faq024.md new file mode 100644 index 0000000000..ab1b68f5d7 --- /dev/null +++ b/docs/docs/faq/faq024.md @@ -0,0 +1,133 @@ +--- +title: workspace 模式常见问题 +sidebar_position: 23 +tags: [FAQ] +--- + +#### 如何判断是否开启了IDE模式? + +- **通过官方API判断**:您可以通过访问 [workspace.isActive](/site/docs/api/workspace#isactive) 来判断当前是否处于IDE模式。这是阿里低代码引擎提供的一个官方API,专门用于确认是否处于集成开发环境。 + + + +#### 如何使用插件的ctx来做判断在哪个模式下? + +- **插件是否为应用级别**:可以通过 **ctx.isPluginRegisteredInWorkspace** 方法来判断一个插件是否是应用级别的插件。这有助于理解插件在阿里低代码引擎中的作用域和潜在的使用场景。 +- **插件的注册级别**:您可以使用 **ctx.registerLevel** 属性来判断插件处于哪个级别。插件级别的值包括: + - **Default**:默认级别。非 IDE 模式下的值 + - **Workspace**:应用级别。 + - **Resource**:资源级别。 + - **EditorView**:编辑视图级别。 这些级别代表了插件可能的作用域和使用场景,有助于在开发和管理低代码应用时对插件进行更精确的控制和配置。 + + + +#### 如何在IDE模式下设置资源列表? + +- **设置资源列表API**:在IDE模式下,可以通过访问 [workspace.setResourceList](/site/docs/api/workspace#setresourcelist) 来设置或更新IDE中的资源列表。这确保您在编辑器窗口中打开的资源是最新且可访问的。 + + + +#### 如何打开视图窗口? + +- **使用推荐的方法**:使用 `openEditorWindow(resource: Resource, sleep?: boolean): Promise<void>;` 来打开视图窗口。这里的 **resource** 参数指的是您要打开的特定资源,可通过 [workspace.resourceList](/site/docs/api/workspace#resourcelist) 获取。 +- **不推荐使用的过时方法**:有一个过时的方法 `openEditorWindow(resourceName: string, id: string, extra: Object, viewName?: string, sleep?: boolean): Promise<void>;` 也用于打开视图窗口。虽然仍然可用,但官方不推荐使用此方法,并计划在后续版本中废弃,因为它在维护和可扩展性方面存在限制。 + + + +#### 如何在全局插件中获取视图的上下文? + +- 在阿里低代码引擎的全局插件中获取视图的上下文,可以通过使用 **ProvideViewPluginContext** 函数实现。这个函数来自 **@alilc/lowcode-utils** 库,它使得您的 React 组件能够接收 **pluginContext** 作为 props,进而访问和操作当前视图的状态和属性。 + +**步骤** + +**引入依赖**:首先,确保您的插件文件中已经引入了 **ProvideViewPluginContext** 以及其他必要的依赖。 + +``` +import { ProvideViewPluginContext } from '@alilc/lowcode-utils'; +``` + +**定义 React 组件**:创建一个 React 组件,它将使用来自 **ProvideViewPluginContext** 的 **pluginContext**。 + +```typescript +const MyComponent = (props) => { + const { pluginContext } = props; + // 组件逻辑 + return <div>/* 组件内容 */</div>; +}; +``` + +**定义全局插件**:定义一个函数,这个函数会在插件被注册时调用。这个函数通常接受一个上下文对象 **ctx**,它提供了对引擎功能的访问。 + +```javascript +const globalPlugin = (ctx) => { + const { skeleton } = ctx; + + skeleton.add({ + type: 'PanelDock', + name: 'datapool', + content: ProvideViewPluginContext((props) => { + // 组件内容 + return ( + <MyComponent {...props} /> + ) + }), + // 其他配置 + contentProps: { + // 需要提供 pluginContext 作为参数 + pluginContext: ctx, + } + }); +}; +``` + +通过这些步骤,您的全局插件中的 React 组件就能够获取并使用视图的上下文了。这为您在插件中实现更复杂的功能和交互提供了基础。 + + + +**注意事项** + +- **组件重渲染**:正常情况下,**pluginsContext** 是视图的上下文。当视图切换时,组件会重新渲染。如果需要在组件中处理视图切换导致的重新渲染,可以利用 React 的 **key** 属性。 + +**示例代码** + +```typescript +ProvideViewPluginContext(props => { + return ( + <DataPoolPane + {...props} + key={props.pluginContext?.editorWindow?.id} + ); +}); +``` + +通过这种方式,当视图切换时,组件会根据视图的不同进行重新渲染,确保组件状态与当前视图的上下文保持一致。这对于在低代码平台上开发复杂插件和交互功能是非常有用的。 + + + +#### 如何判断插件是否在 Workspace 模式下注册? + +**使用** **ctx.isPluginRegisteredInWorkspace()** **方法**: + +通过 **ctx.isPluginRegisteredInWorkspace()** 方法,可以判断一个插件是否在 Workspace 级别注册。以下是一个示例代码片段: + +```javascript +if (ctx.isPluginRegisteredInWorkspace('pluginName')) { + console.log('插件已在 Workspace 模式下注册。'); +} else { + console.log('插件未在 Workspace 模式下注册。'); +} +``` + +注意:此方法目前在 beta 版本中,可能会有 TypeScript 提示显示已移除。 + +**检查** **ctx.registerLevel** **的值**: + +可以通过比较 **ctx.registerLevel** 的值来判断插件的注册级别。示例代码如下: + +```javascript +if (ctx.registerLevel !== IPublicEnumPluginRegisterLevel.Workspace) { + console.log('插件未在 Workspace 模式下注册。'); +} else { + console.log('插件已在 Workspace 模式下注册。'); +} +``` diff --git a/docs/docs/faq/index.md b/docs/docs/faq/index.md index 5e5eee8ac4..ef8d7b3b15 100644 --- a/docs/docs/faq/index.md +++ b/docs/docs/faq/index.md @@ -15,6 +15,7 @@ tags: [FAQ] - [如何通过 this.utils 使用第三方工具扩展](/site/docs/faq/faq005) - [设置面板中的高级 tab 如何配置](/site/docs/faq/faq007) - [插件面板如何调整位置](/site/docs/faq/faq010) +- [workspace 模式常见问题](/site/docs/faq/faq024) ## 源码和依赖 - [某某 npm 包对应的源码在哪里?](/site/docs/faq/faq008) From 07ee7e0355bdb251053afdb860bae3c87012b1b9 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Wed, 13 Dec 2023 06:37:30 +0000 Subject: [PATCH 110/219] Update package version --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index a1b6d646f5..eaf87ac219 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.9", + "version": "1.2.10", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 271aef4fb964f2fab74f1a70b020ab679564a10f Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 13 Dec 2023 16:12:15 +0800 Subject: [PATCH 111/219] chore: add publish engine actions --- .github/workflows/publish docs.yml | 2 +- .github/workflows/publish engine beta.yml | 30 +++++++++++++++++++ .github/workflows/publish engine.yml | 26 ++++++++++++++++ package.json | 4 +-- .../src/layouts/workbench.less | 1 + 5 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/publish engine beta.yml create mode 100644 .github/workflows/publish engine.yml diff --git a/.github/workflows/publish docs.yml b/.github/workflows/publish docs.yml index dcbeec3844..ed16bb869a 100644 --- a/.github/workflows/publish docs.yml +++ b/.github/workflows/publish docs.yml @@ -5,7 +5,7 @@ on: branches: - develop paths: - - 'docs/**' + - 'docs/docs/**' jobs: publish-docs: diff --git a/.github/workflows/publish engine beta.yml b/.github/workflows/publish engine beta.yml new file mode 100644 index 0000000000..ab498c8df6 --- /dev/null +++ b/.github/workflows/publish engine beta.yml @@ -0,0 +1,30 @@ +name: Update and Publish Docs + +on: + push: + branches: + - 'release/[0-9]+.[0-9]+.[0-9]+-beta' + paths: + - 'packages/**' + +jobs: + publish-engine: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js + uses: actions/setup-node@v2 + with: + node-version: '14' + registry-url: 'https://registry.npmjs.org' + - run: npm install && npm run setup + - run: | + npm run build + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + - run: npm run pub:prerelease + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + - name: Get version + id: get_version + run: echo "::set-output name=version::$(node -p "require('./docs/package.json').version")" diff --git a/.github/workflows/publish engine.yml b/.github/workflows/publish engine.yml new file mode 100644 index 0000000000..3710cf816c --- /dev/null +++ b/.github/workflows/publish engine.yml @@ -0,0 +1,26 @@ +name: Update and Publish Docs + +on: + workflow_dispatch: + +jobs: + publish-engine: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js + uses: actions/setup-node@v2 + with: + node-version: '14' + registry-url: 'https://registry.npmjs.org' + - run: npm install && npm run setup + - run: | + npm run build + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + - run: npm run pub + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + - name: Get version + id: get_version + run: echo "::set-output name=version::$(node -p "require('./docs/package.json').version")" diff --git a/package.json b/package.json index aded2a3015..caabbeeb13 100644 --- a/package.json +++ b/package.json @@ -20,11 +20,11 @@ "lint:fix": "f2elint fix -i ./packages/*/src", "lint:modules": "f2elint scan -q -i ./modules/*/src", "lint:modules:fix": "f2elint fix -i ./modules/*/src", - "pub": "npm run watchdog:build && lerna publish patch --force-publish --exact --no-changelog", + "pub": "npm run watchdog:build && lerna publish patch --yes --force-publish --exact --no-changelog", "pub:premajor": "npm run watchdog:build && lerna publish premajor --force-publish --exact --dist-tag beta --preid beta --no-changelog", "pub:preminor": "npm run watchdog:build && lerna publish preminor --force-publish --exact --dist-tag beta --preid beta --no-changelog", "pub:prepatch": "npm run watchdog:build && lerna publish prepatch --force-publish --exact --dist-tag beta --preid beta --no-changelog", - "pub:prerelease": "npm run watchdog:build && lerna publish prerelease --force-publish --exact --dist-tag beta --preid beta --no-changelog", + "pub:prerelease": "npm run watchdog:build && lerna publish prerelease --yes --force-publish --exact --dist-tag beta --preid beta --no-changelog", "setup": "node ./scripts/setup.js", "setup:test": "./scripts/setup-for-test.sh", "setup:skip-build": "./scripts/setup-skip-build.sh", diff --git a/packages/editor-skeleton/src/layouts/workbench.less b/packages/editor-skeleton/src/layouts/workbench.less index 596ea69f60..97a017523d 100644 --- a/packages/editor-skeleton/src/layouts/workbench.less +++ b/packages/editor-skeleton/src/layouts/workbench.less @@ -105,6 +105,7 @@ body { right: 0; bottom: 0; z-index: -1; + overflow: hidden; &.active { z-index: 999; From a25aad4975231706a9e47ba3e62e17034ce18846 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 13 Dec 2023 16:43:51 +0800 Subject: [PATCH 112/219] fix(outline): fix view change bugs in workspace mode --- .github/workflows/publish engine beta.yml | 4 ++-- .github/workflows/publish engine.yml | 4 ++-- packages/plugin-outline-pane/src/controllers/tree-master.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/publish engine beta.yml b/.github/workflows/publish engine beta.yml index ab498c8df6..32c5b4c15b 100644 --- a/.github/workflows/publish engine beta.yml +++ b/.github/workflows/publish engine beta.yml @@ -1,4 +1,4 @@ -name: Update and Publish Docs +name: Publish Engine Beta on: push: @@ -27,4 +27,4 @@ jobs: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Get version id: get_version - run: echo "::set-output name=version::$(node -p "require('./docs/package.json').version")" + run: echo "::set-output name=version::$(node -p "require('./package.json').version")" diff --git a/.github/workflows/publish engine.yml b/.github/workflows/publish engine.yml index 3710cf816c..f9206d4cb9 100644 --- a/.github/workflows/publish engine.yml +++ b/.github/workflows/publish engine.yml @@ -1,4 +1,4 @@ -name: Update and Publish Docs +name: Publish Engine on: workflow_dispatch: @@ -23,4 +23,4 @@ jobs: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Get version id: get_version - run: echo "::set-output name=version::$(node -p "require('./docs/package.json').version")" + run: echo "::set-output name=version::$(node -p "require('./package.json').version")" diff --git a/packages/plugin-outline-pane/src/controllers/tree-master.ts b/packages/plugin-outline-pane/src/controllers/tree-master.ts index ede5f0f5f3..f86ce3deca 100644 --- a/packages/plugin-outline-pane/src/controllers/tree-master.ts +++ b/packages/plugin-outline-pane/src/controllers/tree-master.ts @@ -51,9 +51,9 @@ export class TreeMaster { windowViewTypeChangeEvent(); workspace.onChangeActiveWindow(() => { - windowViewTypeChangeEvent(); this.setPluginContext(workspace.window?.currentEditorView); dispose && dispose(); + windowViewTypeChangeEvent(); }); } } From 2ec9bf7cdf203c3d4cdda8dc4048c44851019028 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= <liujup@foxmail.com> Date: Wed, 13 Dec 2023 17:05:03 +0800 Subject: [PATCH 113/219] chore: create publish engine.yml --- .github/workflows/publish engine.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .github/workflows/publish engine.yml diff --git a/.github/workflows/publish engine.yml b/.github/workflows/publish engine.yml new file mode 100644 index 0000000000..7c245a3d82 --- /dev/null +++ b/.github/workflows/publish engine.yml @@ -0,0 +1,26 @@ +name: Publish Engine + +on: + workflow_dispatch: + +jobs: + publish-engine: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js + uses: actions/setup-node@v2 + with: + node-version: '16' + registry-url: 'https://registry.npmjs.org' + - run: npm install && npm run setup + - run: | + npm run build + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + - run: npm run pub + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + - name: Get version + id: get_version + run: echo "::set-output name=version::$(node -p "require('./package.json').version")" From 3c3a305c7aa00544d1f28084367eb43f3e42b5a1 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 13 Dec 2023 17:22:40 +0800 Subject: [PATCH 114/219] chore: update publish engine.yml --- .github/workflows/publish engine.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/publish engine.yml b/.github/workflows/publish engine.yml index 7c245a3d82..6825c66fca 100644 --- a/.github/workflows/publish engine.yml +++ b/.github/workflows/publish engine.yml @@ -6,6 +6,9 @@ on: jobs: publish-engine: runs-on: ubuntu-latest + if: >- + contains(github.ref, 'refs/heads/release/') && + (github.actor == 'JackLian' || github.actor == 'liujuping') steps: - uses: actions/checkout@v2 - name: Setup Node.js From 2e604c99109b82d2dc1f447ab1de37f623e3188d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=94=90=E6=BE=9C?= <1ncounter.100@gmail.com> Date: Thu, 23 Nov 2023 18:58:24 +0800 Subject: [PATCH 115/219] Fix/component lifecycle not execute (#2690) * fix: recover component lifecycle and avoid execute from scope __proto__ From c3d0ffb62cd03d81f4fc46d01b1714eb1dd79a03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=94=90=E6=BE=9C?= <1ncounter.100@gmail.com> Date: Thu, 23 Nov 2023 19:28:41 +0800 Subject: [PATCH 116/219] Fix/component lifecycle not execute (#2692) * fix: recover component lifecycle and avoid execute from scope __proto__ From f418e5b2c18ddb5299a575f0888ad67de642bcf2 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Wed, 13 Dec 2023 09:34:24 +0000 Subject: [PATCH 117/219] chore(release): publish 1.2.3 --- lerna.json | 2 +- packages/designer/package.json | 8 ++++---- packages/editor-core/package.json | 6 +++--- packages/editor-skeleton/package.json | 10 +++++----- packages/engine/package.json | 18 +++++++++--------- packages/ignitor/package.json | 2 +- packages/plugin-designer/package.json | 8 ++++---- packages/plugin-outline-pane/package.json | 6 +++--- packages/rax-renderer/package.json | 6 +++--- packages/rax-simulator-renderer/package.json | 10 +++++----- packages/react-renderer/package.json | 4 ++-- packages/react-simulator-renderer/package.json | 10 +++++----- packages/renderer-core/package.json | 8 ++++---- packages/shell/package.json | 14 +++++++------- packages/types/package.json | 2 +- packages/utils/package.json | 4 ++-- packages/workspace/package.json | 12 ++++++------ 17 files changed, 65 insertions(+), 65 deletions(-) diff --git a/lerna.json b/lerna.json index 34be89faa8..98ef80f138 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "lerna": "4.0.0", - "version": "1.2.2", + "version": "1.2.3", "npmClient": "yarn", "useWorkspaces": true, "packages": [ diff --git a/packages/designer/package.json b/packages/designer/package.json index 69a402ed22..e961451d88 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-designer", - "version": "1.2.2", + "version": "1.2.3", "description": "Designer for Ali LowCode Engine", "main": "lib/index.js", "module": "es/index.js", @@ -15,9 +15,9 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-editor-core": "1.2.2", - "@alilc/lowcode-types": "1.2.2", - "@alilc/lowcode-utils": "1.2.2", + "@alilc/lowcode-editor-core": "1.2.3", + "@alilc/lowcode-types": "1.2.3", + "@alilc/lowcode-utils": "1.2.3", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/editor-core/package.json b/packages/editor-core/package.json index de9d30bc8b..345783c806 100644 --- a/packages/editor-core/package.json +++ b/packages/editor-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-core", - "version": "1.2.2", + "version": "1.2.3", "description": "Core Api for Ali lowCode engine", "license": "MIT", "main": "lib/index.js", @@ -14,8 +14,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.2.2", - "@alilc/lowcode-utils": "1.2.2", + "@alilc/lowcode-types": "1.2.3", + "@alilc/lowcode-utils": "1.2.3", "classnames": "^2.2.6", "debug": "^4.1.1", "intl-messageformat": "^9.3.1", diff --git a/packages/editor-skeleton/package.json b/packages/editor-skeleton/package.json index fe2d0d43ff..fa5c1e13e6 100644 --- a/packages/editor-skeleton/package.json +++ b/packages/editor-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-skeleton", - "version": "1.2.2", + "version": "1.2.3", "description": "alibaba lowcode editor skeleton", "main": "lib/index.js", "module": "es/index.js", @@ -19,10 +19,10 @@ ], "dependencies": { "@alifd/next": "^1.20.12", - "@alilc/lowcode-designer": "1.2.2", - "@alilc/lowcode-editor-core": "1.2.2", - "@alilc/lowcode-types": "1.2.2", - "@alilc/lowcode-utils": "1.2.2", + "@alilc/lowcode-designer": "1.2.3", + "@alilc/lowcode-editor-core": "1.2.3", + "@alilc/lowcode-types": "1.2.3", + "@alilc/lowcode-utils": "1.2.3", "classnames": "^2.2.6", "react": "^16.8.1", "react-dom": "^16.8.1" diff --git a/packages/engine/package.json b/packages/engine/package.json index 3ea47f79da..c9eef3534c 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine", - "version": "1.2.2", + "version": "1.2.3", "description": "An enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系", "main": "lib/engine-core.js", "module": "es/engine-core.js", @@ -19,15 +19,15 @@ "license": "MIT", "dependencies": { "@alifd/next": "^1.19.12", - "@alilc/lowcode-designer": "1.2.2", - "@alilc/lowcode-editor-core": "1.2.2", - "@alilc/lowcode-editor-skeleton": "1.2.2", + "@alilc/lowcode-designer": "1.2.3", + "@alilc/lowcode-editor-core": "1.2.3", + "@alilc/lowcode-editor-skeleton": "1.2.3", "@alilc/lowcode-engine-ext": "^1.0.0", - "@alilc/lowcode-plugin-designer": "1.2.2", - "@alilc/lowcode-plugin-outline-pane": "1.2.2", - "@alilc/lowcode-shell": "1.2.2", - "@alilc/lowcode-utils": "1.2.2", - "@alilc/lowcode-workspace": "1.2.2", + "@alilc/lowcode-plugin-designer": "1.2.3", + "@alilc/lowcode-plugin-outline-pane": "1.2.3", + "@alilc/lowcode-shell": "1.2.3", + "@alilc/lowcode-utils": "1.2.3", + "@alilc/lowcode-workspace": "1.2.3", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/ignitor/package.json b/packages/ignitor/package.json index d737a7c868..71a21484c4 100644 --- a/packages/ignitor/package.json +++ b/packages/ignitor/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-ignitor", - "version": "1.2.2", + "version": "1.2.3", "description": "点火器,bootstrap lce project", "main": "lib/index.js", "private": true, diff --git a/packages/plugin-designer/package.json b/packages/plugin-designer/package.json index fe653568bb..500c0c9611 100644 --- a/packages/plugin-designer/package.json +++ b/packages/plugin-designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-designer", - "version": "1.2.2", + "version": "1.2.3", "description": "alibaba lowcode editor designer plugin", "files": [ "es", @@ -18,9 +18,9 @@ ], "author": "xiayang.xy", "dependencies": { - "@alilc/lowcode-designer": "1.2.2", - "@alilc/lowcode-editor-core": "1.2.2", - "@alilc/lowcode-utils": "1.2.2", + "@alilc/lowcode-designer": "1.2.3", + "@alilc/lowcode-editor-core": "1.2.3", + "@alilc/lowcode-utils": "1.2.3", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/plugin-outline-pane/package.json b/packages/plugin-outline-pane/package.json index 2540ca5ad4..5a2ef38a45 100644 --- a/packages/plugin-outline-pane/package.json +++ b/packages/plugin-outline-pane/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-outline-pane", - "version": "1.2.2", + "version": "1.2.3", "description": "Outline pane for Ali lowCode engine", "files": [ "es", @@ -13,8 +13,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.2.2", - "@alilc/lowcode-utils": "1.2.2", + "@alilc/lowcode-types": "1.2.3", + "@alilc/lowcode-utils": "1.2.3", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/rax-renderer/package.json b/packages/rax-renderer/package.json index 60ea0c6981..837aebc85e 100644 --- a/packages/rax-renderer/package.json +++ b/packages/rax-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-renderer", - "version": "1.2.2", + "version": "1.2.3", "description": "Rax renderer for Ali lowCode engine", "main": "lib/index.js", "module": "es/index.js", @@ -30,8 +30,8 @@ "build": "build-scripts build" }, "dependencies": { - "@alilc/lowcode-renderer-core": "1.2.2", - "@alilc/lowcode-utils": "1.2.2", + "@alilc/lowcode-renderer-core": "1.2.3", + "@alilc/lowcode-utils": "1.2.3", "rax-find-dom-node": "^1.0.1" }, "devDependencies": { diff --git a/packages/rax-simulator-renderer/package.json b/packages/rax-simulator-renderer/package.json index 520ff32c89..dc9b7b1478 100644 --- a/packages/rax-simulator-renderer/package.json +++ b/packages/rax-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-simulator-renderer", - "version": "1.2.2", + "version": "1.2.3", "description": "rax simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -13,10 +13,10 @@ "build:umd": "build-scripts build --config build.umd.json" }, "dependencies": { - "@alilc/lowcode-designer": "1.2.2", - "@alilc/lowcode-rax-renderer": "1.2.2", - "@alilc/lowcode-types": "1.2.2", - "@alilc/lowcode-utils": "1.2.2", + "@alilc/lowcode-designer": "1.2.3", + "@alilc/lowcode-rax-renderer": "1.2.3", + "@alilc/lowcode-types": "1.2.3", + "@alilc/lowcode-utils": "1.2.3", "classnames": "^2.2.6", "driver-universal": "^3.1.3", "history": "^5.0.0", diff --git a/packages/react-renderer/package.json b/packages/react-renderer/package.json index a35039fc3c..1dceb9c2e7 100644 --- a/packages/react-renderer/package.json +++ b/packages/react-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-renderer", - "version": "1.2.2", + "version": "1.2.3", "description": "react renderer for ali lowcode engine", "main": "lib/index.js", "module": "es/index.js", @@ -22,7 +22,7 @@ ], "dependencies": { "@alifd/next": "^1.21.16", - "@alilc/lowcode-renderer-core": "1.2.2" + "@alilc/lowcode-renderer-core": "1.2.3" }, "devDependencies": { "@alib/build-scripts": "^0.1.18", diff --git a/packages/react-simulator-renderer/package.json b/packages/react-simulator-renderer/package.json index 413b1825f8..8935c92eef 100644 --- a/packages/react-simulator-renderer/package.json +++ b/packages/react-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-simulator-renderer", - "version": "1.2.2", + "version": "1.2.3", "description": "react simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -17,10 +17,10 @@ "test:cov": "build-scripts test --config build.test.json --jest-coverage" }, "dependencies": { - "@alilc/lowcode-designer": "1.2.2", - "@alilc/lowcode-react-renderer": "1.2.2", - "@alilc/lowcode-types": "1.2.2", - "@alilc/lowcode-utils": "1.2.2", + "@alilc/lowcode-designer": "1.2.3", + "@alilc/lowcode-react-renderer": "1.2.3", + "@alilc/lowcode-types": "1.2.3", + "@alilc/lowcode-utils": "1.2.3", "classnames": "^2.2.6", "mobx": "^6.3.0", "mobx-react": "^7.2.0", diff --git a/packages/renderer-core/package.json b/packages/renderer-core/package.json index 3b96ef40b3..4774ae3689 100644 --- a/packages/renderer-core/package.json +++ b/packages/renderer-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-renderer-core", - "version": "1.2.2", + "version": "1.2.3", "description": "renderer core", "license": "MIT", "main": "lib/index.js", @@ -16,8 +16,8 @@ }, "dependencies": { "@alilc/lowcode-datasource-engine": "^1.0.0", - "@alilc/lowcode-types": "1.2.2", - "@alilc/lowcode-utils": "1.2.2", + "@alilc/lowcode-types": "1.2.3", + "@alilc/lowcode-utils": "1.2.3", "classnames": "^2.2.6", "debug": "^4.1.1", "fetch-jsonp": "^1.1.3", @@ -32,7 +32,7 @@ "devDependencies": { "@alib/build-scripts": "^0.1.18", "@alifd/next": "^1.26.0", - "@alilc/lowcode-designer": "1.2.2", + "@alilc/lowcode-designer": "1.2.3", "@babel/plugin-transform-typescript": "^7.16.8", "@testing-library/react": "^11.2.2", "@types/classnames": "^2.2.11", diff --git a/packages/shell/package.json b/packages/shell/package.json index 7e20192352..2ebf14bbc2 100644 --- a/packages/shell/package.json +++ b/packages/shell/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-shell", - "version": "1.2.2", + "version": "1.2.3", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -13,12 +13,12 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.2.2", - "@alilc/lowcode-editor-core": "1.2.2", - "@alilc/lowcode-editor-skeleton": "1.2.2", - "@alilc/lowcode-types": "1.2.2", - "@alilc/lowcode-utils": "1.2.2", - "@alilc/lowcode-workspace": "1.2.2", + "@alilc/lowcode-designer": "1.2.3", + "@alilc/lowcode-editor-core": "1.2.3", + "@alilc/lowcode-editor-skeleton": "1.2.3", + "@alilc/lowcode-types": "1.2.3", + "@alilc/lowcode-utils": "1.2.3", + "@alilc/lowcode-workspace": "1.2.3", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", diff --git a/packages/types/package.json b/packages/types/package.json index c4fa290036..c0b8e203fe 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-types", - "version": "1.2.2", + "version": "1.2.3", "description": "Types for Ali lowCode engine", "files": [ "es", diff --git a/packages/utils/package.json b/packages/utils/package.json index af76e9e2f6..00efffb8d3 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-utils", - "version": "1.2.2", + "version": "1.2.3", "description": "Utils for Ali lowCode engine", "files": [ "lib", @@ -14,7 +14,7 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.2.2", + "@alilc/lowcode-types": "1.2.3", "lodash": "^4.17.21", "mobx": "^6.3.0", "react": "^16" diff --git a/packages/workspace/package.json b/packages/workspace/package.json index 4724323797..8c09a93b6c 100644 --- a/packages/workspace/package.json +++ b/packages/workspace/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-workspace", - "version": "1.2.2", + "version": "1.2.3", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -15,11 +15,11 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.2.2", - "@alilc/lowcode-editor-core": "1.2.2", - "@alilc/lowcode-editor-skeleton": "1.2.2", - "@alilc/lowcode-types": "1.2.2", - "@alilc/lowcode-utils": "1.2.2", + "@alilc/lowcode-designer": "1.2.3", + "@alilc/lowcode-editor-core": "1.2.3", + "@alilc/lowcode-editor-skeleton": "1.2.3", + "@alilc/lowcode-types": "1.2.3", + "@alilc/lowcode-utils": "1.2.3", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", From f2d8fca18840cfaaa531219b0cb430294d99f01a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=8F=8A=E8=90=8D=28=E7=B5=AE=E9=BB=8E=29?= <liujup@foxmail.com> Date: Thu, 14 Dec 2023 09:55:14 +0800 Subject: [PATCH 118/219] docs: update workspace.md --- docs/docs/api/workspace.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/api/workspace.md b/docs/docs/api/workspace.md index 9911dc93ad..6d0714ae09 100644 --- a/docs/docs/api/workspace.md +++ b/docs/docs/api/workspace.md @@ -87,7 +87,7 @@ registerResourceType(resourceTypeModel: IPublicTypeResourceType): void; setResourceList(resourceList: IPublicResourceList) {} ``` -相关类型:[IPublicResourceOptions](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/resource-options.ts) +相关类型:[IPublicResourceData](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/resource-list.ts) ### openEditorWindow From c0ddba5543d7fee9735445774806396fec82fdfc Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Thu, 14 Dec 2023 02:15:38 +0000 Subject: [PATCH 119/219] Update package version --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index eaf87ac219..3c43bff657 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.10", + "version": "1.2.11", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 27bf7babe53ac07bf165832cd4eb55f4aafcf37c Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 14 Dec 2023 10:16:30 +0800 Subject: [PATCH 120/219] chore: use tnpm as oss-syncing source --- scripts/sync-oss.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/sync-oss.js b/scripts/sync-oss.js index ba4a77be37..2108e676d2 100644 --- a/scripts/sync-oss.js +++ b/scripts/sync-oss.js @@ -19,7 +19,7 @@ const onResponse = function (res) { chunks.push(chunk); }); - res.on('end', (chunk) => { + res.on('end', () => { const body = Buffer.concat(chunks); console.table(JSON.stringify(JSON.parse(body.toString()), null, 2)); }); @@ -39,9 +39,9 @@ const postData = JSON.stringify({ }, ], // 可以发布指定源的 npm 包,默认公网 npm - useTnpm: false, + useTnpm: true, }); req.write(postData); -req.end(); \ No newline at end of file +req.end(); From 9d526ebcd8a43635a27a300f00d8223f74ecc353 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 14 Dec 2023 10:22:26 +0800 Subject: [PATCH 121/219] chore(workflows/publish-docs): update commit message --- .github/workflows/publish docs.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish docs.yml b/.github/workflows/publish docs.yml index ed16bb869a..4bddec3ba3 100644 --- a/.github/workflows/publish docs.yml +++ b/.github/workflows/publish docs.yml @@ -24,7 +24,7 @@ jobs: git config --local user.email "action@github.com" git config --local user.name "GitHub Action" git add package.json - git commit -m "Update package version" + git commit -m "chore(docs): publish documentation" git push - run: cd docs && npm publish env: @@ -48,4 +48,4 @@ jobs: owner: context.repo.owner, repo: context.repo.repo, body: '🚀 New version has been released: ' + '${{ needs.publish-docs.outputs.version }}' - }) \ No newline at end of file + }) From bb50a20ef11367fbfe52efc800194697c0c3056e Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 14 Dec 2023 10:44:34 +0800 Subject: [PATCH 122/219] chore(docs): use tnpm as oss-syncing source --- docs/scripts/sync-oss.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/scripts/sync-oss.js b/docs/scripts/sync-oss.js index 9518a8ea7f..2d052dfa12 100644 --- a/docs/scripts/sync-oss.js +++ b/docs/scripts/sync-oss.js @@ -19,7 +19,7 @@ const onResponse = function (res) { chunks.push(chunk); }); - res.on('end', (chunk) => { + res.on('end', () => { const body = Buffer.concat(chunks); console.table(JSON.stringify(JSON.parse(body.toString()), null, 2)); }); @@ -39,9 +39,9 @@ const postData = JSON.stringify({ }, ], // 可以发布指定源的 npm 包,默认公网 npm - useTnpm: false, + useTnpm: true, }); req.write(postData); -req.end(); \ No newline at end of file +req.end(); From a567f12473791f05a4282bc04299d936d4fd8a30 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 14 Dec 2023 11:08:47 +0800 Subject: [PATCH 123/219] docs: add new link to video page --- docs/docs/video/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/docs/video/index.md b/docs/docs/video/index.md index 8ae21620bc..d7d438e4f7 100644 --- a/docs/docs/video/index.md +++ b/docs/docs/video/index.md @@ -3,6 +3,7 @@ - [2023/08/03 初识低代码引擎](https://www.bilibili.com/video/BV1gu411p7TC) # 社区视频 +- [低代码从入门到实战:低代码引擎实践](https://www.bilibili.com/video/BV1aP4y1Q7Xa/?vd_source=cb026325b1d587f9669d09fb586bc020) - [阿里低代码引擎项目实战 (1)-引擎 demo 部署到 faas 服务](https://www.bilibili.com/video/BV1B44y1P7GM/) - [【有翻车】阿里低代码引擎项目实战 (2)-保存页面到远端存储](https://www.bilibili.com/video/BV1AS4y1K7DP/) - [阿里巴巴低代码引擎项目实战 (3)-自定义组件接入](https://www.bilibili.com/video/BV1dZ4y1m76S/) From ef573d3ad9e3c3c8304957c4198f4217a394400a Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Thu, 14 Dec 2023 03:09:41 +0000 Subject: [PATCH 124/219] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 3c43bff657..75d7f1f28f 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.11", + "version": "1.2.12", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From ec843543f04a9e10c221b1d99368d3b45986747a Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 14 Dec 2023 11:31:05 +0800 Subject: [PATCH 125/219] chore: update docs publish action --- .github/workflows/publish docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish docs.yml b/.github/workflows/publish docs.yml index 4bddec3ba3..7218976e42 100644 --- a/.github/workflows/publish docs.yml +++ b/.github/workflows/publish docs.yml @@ -26,7 +26,7 @@ jobs: git add package.json git commit -m "chore(docs): publish documentation" git push - - run: cd docs && npm publish + - run: cd docs && npm build && npm publish env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Get version From 08401c76f93ccb9200c43d3fec2455ea6dd89cf6 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 14 Dec 2023 13:57:29 +0800 Subject: [PATCH 126/219] chore(workflows/publish-docs): add workflow_dispatch trigger --- .github/workflows/publish docs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/publish docs.yml b/.github/workflows/publish docs.yml index 7218976e42..3b42398310 100644 --- a/.github/workflows/publish docs.yml +++ b/.github/workflows/publish docs.yml @@ -6,6 +6,7 @@ on: - develop paths: - 'docs/docs/**' + workflow_dispatch: jobs: publish-docs: From 613142b2d836f73e98ad22f443f96e99e706ef4f Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 14 Dec 2023 14:00:52 +0800 Subject: [PATCH 127/219] chore(workflows/publish-docs): add workflow_dispatch trigger --- .github/workflows/publish docs.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/publish docs.yml b/.github/workflows/publish docs.yml index ed16bb869a..3b42398310 100644 --- a/.github/workflows/publish docs.yml +++ b/.github/workflows/publish docs.yml @@ -6,6 +6,7 @@ on: - develop paths: - 'docs/docs/**' + workflow_dispatch: jobs: publish-docs: @@ -24,9 +25,9 @@ jobs: git config --local user.email "action@github.com" git config --local user.name "GitHub Action" git add package.json - git commit -m "Update package version" + git commit -m "chore(docs): publish documentation" git push - - run: cd docs && npm publish + - run: cd docs && npm build && npm publish env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Get version @@ -48,4 +49,4 @@ jobs: owner: context.repo.owner, repo: context.repo.repo, body: '🚀 New version has been released: ' + '${{ needs.publish-docs.outputs.version }}' - }) \ No newline at end of file + }) From cdcc8c8a90e9e7075d9ca8ade90fe84adccde7e3 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Thu, 14 Dec 2023 06:04:49 +0000 Subject: [PATCH 128/219] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 75d7f1f28f..0d4964cd9a 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.12", + "version": "1.2.13", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From b56a2a92742e170b95766e2907a3bde099d8a833 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 14 Dec 2023 14:13:58 +0800 Subject: [PATCH 129/219] chore(workflows/publish-docs): update config --- .github/workflows/publish docs.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish docs.yml b/.github/workflows/publish docs.yml index 3b42398310..e85d08f2a9 100644 --- a/.github/workflows/publish docs.yml +++ b/.github/workflows/publish docs.yml @@ -16,7 +16,8 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v2 with: - node-version: '14' + ref: 'develop' + node-version: '16' registry-url: 'https://registry.npmjs.org' - run: cd docs && npm install - run: | @@ -27,7 +28,7 @@ jobs: git add package.json git commit -m "chore(docs): publish documentation" git push - - run: cd docs && npm build && npm publish + - run: cd docs && npm run build && npm publish env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Get version From 729b123e462b17123b691ba1925dab2b8af07ee6 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Thu, 14 Dec 2023 06:16:05 +0000 Subject: [PATCH 130/219] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 0d4964cd9a..c1d9fe53fb 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.13", + "version": "1.2.14", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 729083aa01844d2b40ca39a45e69cfd82028279e Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 14 Dec 2023 14:18:57 +0800 Subject: [PATCH 131/219] chore(workflows/publish-docs): update config --- .github/workflows/publish docs.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish docs.yml b/.github/workflows/publish docs.yml index 3b42398310..e85d08f2a9 100644 --- a/.github/workflows/publish docs.yml +++ b/.github/workflows/publish docs.yml @@ -16,7 +16,8 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v2 with: - node-version: '14' + ref: 'develop' + node-version: '16' registry-url: 'https://registry.npmjs.org' - run: cd docs && npm install - run: | @@ -27,7 +28,7 @@ jobs: git add package.json git commit -m "chore(docs): publish documentation" git push - - run: cd docs && npm build && npm publish + - run: cd docs && npm run build && npm publish env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Get version From 5d08b6858d73f24cae33b07c22474c83f3868d27 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 14 Dec 2023 14:45:01 +0800 Subject: [PATCH 132/219] chore(workflows/publish-docs): update config --- .github/workflows/publish docs.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/publish docs.yml b/.github/workflows/publish docs.yml index e85d08f2a9..7553fa50f8 100644 --- a/.github/workflows/publish docs.yml +++ b/.github/workflows/publish docs.yml @@ -7,6 +7,14 @@ on: paths: - 'docs/docs/**' workflow_dispatch: + inputs: + branch: + description: 'doc is designed be published from develop' + required: true + default: 'develop' + type: choice + options: + - 'develop' jobs: publish-docs: From 53078ba5f0c973ccf137def297cdd3dc0ba23a0c Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 14 Dec 2023 14:46:17 +0800 Subject: [PATCH 133/219] chore(workflows/publish-docs): update config --- .github/workflows/publish docs.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/publish docs.yml b/.github/workflows/publish docs.yml index e85d08f2a9..7553fa50f8 100644 --- a/.github/workflows/publish docs.yml +++ b/.github/workflows/publish docs.yml @@ -7,6 +7,14 @@ on: paths: - 'docs/docs/**' workflow_dispatch: + inputs: + branch: + description: 'doc is designed be published from develop' + required: true + default: 'develop' + type: choice + options: + - 'develop' jobs: publish-docs: From 9394aecc7c612ab6818d3d5751d69d2a19eb2b16 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 14 Dec 2023 14:49:25 +0800 Subject: [PATCH 134/219] chore(workflows/publish-docs): update config --- .github/workflows/publish docs.yml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.github/workflows/publish docs.yml b/.github/workflows/publish docs.yml index 7553fa50f8..e85d08f2a9 100644 --- a/.github/workflows/publish docs.yml +++ b/.github/workflows/publish docs.yml @@ -7,14 +7,6 @@ on: paths: - 'docs/docs/**' workflow_dispatch: - inputs: - branch: - description: 'doc is designed be published from develop' - required: true - default: 'develop' - type: choice - options: - - 'develop' jobs: publish-docs: From 39d030bfc3a1546b6ca13208734be28c30561e2d Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 14 Dec 2023 14:49:25 +0800 Subject: [PATCH 135/219] chore(workflows/publish-docs): update config --- .github/workflows/publish docs.yml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.github/workflows/publish docs.yml b/.github/workflows/publish docs.yml index 7553fa50f8..e85d08f2a9 100644 --- a/.github/workflows/publish docs.yml +++ b/.github/workflows/publish docs.yml @@ -7,14 +7,6 @@ on: paths: - 'docs/docs/**' workflow_dispatch: - inputs: - branch: - description: 'doc is designed be published from develop' - required: true - default: 'develop' - type: choice - options: - - 'develop' jobs: publish-docs: From 230e63ce5527078b2d223f873cd0c2f3796cf871 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Thu, 14 Dec 2023 17:27:07 +0800 Subject: [PATCH 136/219] docs: add new link to video page --- docs/docs/video/index.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/docs/video/index.md b/docs/docs/video/index.md index d7d438e4f7..38a0e8a5ce 100644 --- a/docs/docs/video/index.md +++ b/docs/docs/video/index.md @@ -3,7 +3,8 @@ - [2023/08/03 初识低代码引擎](https://www.bilibili.com/video/BV1gu411p7TC) # 社区视频 -- [低代码从入门到实战:低代码引擎实践](https://www.bilibili.com/video/BV1aP4y1Q7Xa/?vd_source=cb026325b1d587f9669d09fb586bc020) +- [低代码从入门到实战:低代码引擎实践](https://www.bilibili.com/video/BV1aP4y1Q7Xa/) +- [低代码技术在研发团队的应用模式](https://www.bilibili.com/video/BV1L14y1Y72J/) - [阿里低代码引擎项目实战 (1)-引擎 demo 部署到 faas 服务](https://www.bilibili.com/video/BV1B44y1P7GM/) - [【有翻车】阿里低代码引擎项目实战 (2)-保存页面到远端存储](https://www.bilibili.com/video/BV1AS4y1K7DP/) - [阿里巴巴低代码引擎项目实战 (3)-自定义组件接入](https://www.bilibili.com/video/BV1dZ4y1m76S/) From c6e00252568f7429385d31996ee2f9062ca2575e Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Thu, 14 Dec 2023 09:28:13 +0000 Subject: [PATCH 137/219] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index c1d9fe53fb..3b9e4902a2 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.14", + "version": "1.2.15", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 711a5f66b912da315fcdd2a16c65ba188b9623f6 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Sat, 16 Dec 2023 18:30:03 +0800 Subject: [PATCH 138/219] style: remove .lc-workbench-center z-index --- packages/editor-skeleton/src/layouts/workbench.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/editor-skeleton/src/layouts/workbench.less b/packages/editor-skeleton/src/layouts/workbench.less index 97a017523d..9c7a9815dd 100644 --- a/packages/editor-skeleton/src/layouts/workbench.less +++ b/packages/editor-skeleton/src/layouts/workbench.less @@ -363,7 +363,7 @@ body { flex: 1; display: flex; flex-direction: column; - z-index: 10; + .lc-toolbar { display: flex; height: var(--toolbar-height); From 16713f4b848f3648fa93c82d70007fbec4e8a816 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Sun, 17 Dec 2023 16:37:17 +0800 Subject: [PATCH 139/219] feat(skeleton): Add TS defs for modules & optimize Tabs display with array contents --- .../src/components/widget-views/index.tsx | 23 ++++++++--- .../src/layouts/left-fixed-pane.tsx | 7 ++-- .../src/layouts/left-float-pane.tsx | 5 +-- packages/editor-skeleton/src/skeleton.ts | 38 +++++++++---------- packages/editor-skeleton/src/types.ts | 33 +++------------- packages/editor-skeleton/src/widget/panel.ts | 15 +++----- .../src/shell/type/widget-base-config.ts | 27 ++++++++++++- 7 files changed, 78 insertions(+), 70 deletions(-) diff --git a/packages/editor-skeleton/src/components/widget-views/index.tsx b/packages/editor-skeleton/src/components/widget-views/index.tsx index ba49b3d1ab..2b2f6931cb 100644 --- a/packages/editor-skeleton/src/components/widget-views/index.tsx +++ b/packages/editor-skeleton/src/components/widget-views/index.tsx @@ -266,15 +266,28 @@ export class PanelView extends Component<{ } @observer -export class TabsPanelView extends Component<{ container: WidgetContainer<Panel> }> { +export class TabsPanelView extends Component<{ + container: WidgetContainer<Panel>; + // shouldHideSingleTab: 一个布尔值,用于控制当 Tabs 组件只有一个标签时是否隐藏该标签。 + shouldHideSingleTab?: boolean; +}> { render() { const { container } = this.props; const titles: ReactElement[] = []; const contents: ReactElement[] = []; - container.items.forEach((item: any) => { - titles.push(<PanelTitle key={item.id} panel={item} className="lc-tab-title" />); - contents.push(<PanelView key={item.id} panel={item} hideOperationRow hideDragLine />); - }); + // 如果只有一个标签且 shouldHideSingleTab 为 true,则不显示 Tabs + if (this.props.shouldHideSingleTab && container.items.length === 1) { + contents.push(<PanelView key={container.items[0].id} panel={container.items[0]} hideOperationRow hideDragLine />); + } else { + container.items.forEach((item: any) => { + titles.push(<PanelTitle key={item.id} panel={item} className="lc-tab-title" />); + contents.push(<PanelView key={item.id} panel={item} hideOperationRow hideDragLine />); + }); + } + + if (!titles.length) { + return contents; + } return ( <div className="lc-tabs"> diff --git a/packages/editor-skeleton/src/layouts/left-fixed-pane.tsx b/packages/editor-skeleton/src/layouts/left-fixed-pane.tsx index cda600f74a..a56b449079 100644 --- a/packages/editor-skeleton/src/layouts/left-fixed-pane.tsx +++ b/packages/editor-skeleton/src/layouts/left-fixed-pane.tsx @@ -2,17 +2,16 @@ import { Component, Fragment } from 'react'; import classNames from 'classnames'; import { observer } from '@alilc/lowcode-editor-core'; import { Area } from '../area'; -import { PanelConfig } from '../types'; import { Panel } from '../widget/panel'; +import { IPublicTypePanelConfig } from '@alilc/lowcode-types'; @observer -export default class LeftFixedPane extends Component<{ area: Area<PanelConfig, Panel> }> { +export default class LeftFixedPane extends Component<{ area: Area<IPublicTypePanelConfig, Panel> }> { componentDidUpdate() { // FIXME: dirty fix, need deep think this.props.area.skeleton.editor.get('designer')?.touchOffsetObserver(); } - render() { const { area } = this.props; const width = area.current?.config.props?.width; @@ -36,7 +35,7 @@ export default class LeftFixedPane extends Component<{ area: Area<PanelConfig, P } @observer -class Contents extends Component<{ area: Area<PanelConfig, Panel> }> { +class Contents extends Component<{ area: Area<IPublicTypePanelConfig, Panel> }> { render() { const { area } = this.props; return <Fragment>{area.container.items.map((panel) => panel.content)}</Fragment>; diff --git a/packages/editor-skeleton/src/layouts/left-float-pane.tsx b/packages/editor-skeleton/src/layouts/left-float-pane.tsx index 15f4926199..296f083211 100644 --- a/packages/editor-skeleton/src/layouts/left-float-pane.tsx +++ b/packages/editor-skeleton/src/layouts/left-float-pane.tsx @@ -3,11 +3,10 @@ import classNames from 'classnames'; import { observer, Focusable } from '@alilc/lowcode-editor-core'; import { Area } from '../area'; import { Panel } from '../widget/panel'; -import { PanelConfig } from '../types'; -import { IPublicApiProject } from '@alilc/lowcode-types'; +import { IPublicApiProject, IPublicTypePanelConfig } from '@alilc/lowcode-types'; @observer -export default class LeftFloatPane extends Component<{ area: Area<PanelConfig, Panel> }> { +export default class LeftFloatPane extends Component<{ area: Area<IPublicTypePanelConfig, Panel> }> { private dispose?: () => void; private focusing?: Focusable; diff --git a/packages/editor-skeleton/src/skeleton.ts b/packages/editor-skeleton/src/skeleton.ts index 13967e94d6..7ff462391d 100644 --- a/packages/editor-skeleton/src/skeleton.ts +++ b/packages/editor-skeleton/src/skeleton.ts @@ -1,7 +1,6 @@ import { action, makeObservable, obx, engineConfig, IEditor, FocusTracker } from '@alilc/lowcode-editor-core'; import { DockConfig, - PanelConfig, WidgetConfig, PanelDockConfig, DialogDockConfig, @@ -29,6 +28,7 @@ import { IPublicTypeSkeletonConfig, IPublicApiSkeleton, IPublicTypeConfigTransducer, + IPublicTypePanelConfig, } from '@alilc/lowcode-types'; const logger = new Logger({ level: 'warn', bizName: 'skeleton' }); @@ -70,15 +70,15 @@ export interface ISkeleton extends Omit<IPublicApiSkeleton, readonly toolbar: Area<DockConfig | DividerConfig | PanelDockConfig | DialogDockConfig>; - readonly leftFixedArea: Area<PanelConfig, Panel>; + readonly leftFixedArea: Area<IPublicTypePanelConfig, Panel>; - readonly leftFloatArea: Area<PanelConfig, Panel>; + readonly leftFloatArea: Area<IPublicTypePanelConfig, Panel>; - readonly rightArea: Area<PanelConfig, Panel>; + readonly rightArea: Area<IPublicTypePanelConfig, Panel>; - readonly mainArea: Area<WidgetConfig | PanelConfig, Widget | Panel>; + readonly mainArea: Area<WidgetConfig | IPublicTypePanelConfig, Widget | Panel>; - readonly bottomArea: Area<PanelConfig, Panel>; + readonly bottomArea: Area<IPublicTypePanelConfig, Panel>; readonly stages: Area<StageConfig, Stage>; @@ -104,7 +104,7 @@ export interface ISkeleton extends Omit<IPublicApiSkeleton, defaultSetCurrent?: boolean, ): WidgetContainer; - createPanel(config: PanelConfig): Panel; + createPanel(config: IPublicTypePanelConfig): Panel; add(config: IPublicTypeSkeletonConfig, extraConfig?: Record<string, any>): IWidget | Widget | Panel | Stage | Dock | PanelDock | undefined; } @@ -124,15 +124,15 @@ export class Skeleton implements ISkeleton { readonly toolbar: Area<DockConfig | DividerConfig | PanelDockConfig | DialogDockConfig>; - readonly leftFixedArea: Area<PanelConfig, Panel>; + readonly leftFixedArea: Area<IPublicTypePanelConfig, Panel>; - readonly leftFloatArea: Area<PanelConfig, Panel>; + readonly leftFloatArea: Area<IPublicTypePanelConfig, Panel>; - readonly rightArea: Area<PanelConfig, Panel>; + readonly rightArea: Area<IPublicTypePanelConfig, Panel>; - @obx readonly mainArea: Area<WidgetConfig | PanelConfig, Widget | Panel>; + @obx readonly mainArea: Area<WidgetConfig | IPublicTypePanelConfig, Widget | Panel>; - readonly bottomArea: Area<PanelConfig, Panel>; + readonly bottomArea: Area<IPublicTypePanelConfig, Panel>; readonly stages: Area<StageConfig, Stage>; @@ -388,9 +388,9 @@ export class Skeleton implements ISkeleton { return this.widgets.find(widget => widget.name === name); } - createPanel(config: PanelConfig) { + createPanel(config: IPublicTypePanelConfig) { const parsedConfig = this.parseConfig(config); - const panel = new Panel(this, parsedConfig as PanelConfig); + const panel = new Panel(this, parsedConfig as IPublicTypePanelConfig); this.panels.set(panel.name, panel); logger.debug(`Panel created with name: ${panel.name} \nconfig:`, config, '\n current panels: ', this.panels); return panel; @@ -496,7 +496,7 @@ export class Skeleton implements ISkeleton { return this.leftArea.add(parsedConfig as PanelDockConfig); case 'rightArea': case 'right': - return this.rightArea.add(parsedConfig as PanelConfig); + return this.rightArea.add(parsedConfig as IPublicTypePanelConfig); case 'topArea': case 'top': return this.topArea.add(parsedConfig as PanelDockConfig); @@ -508,14 +508,14 @@ export class Skeleton implements ISkeleton { case 'main': case 'center': case 'centerArea': - return this.mainArea.add(parsedConfig as PanelConfig); + return this.mainArea.add(parsedConfig as IPublicTypePanelConfig); case 'bottomArea': case 'bottom': - return this.bottomArea.add(parsedConfig as PanelConfig); + return this.bottomArea.add(parsedConfig as IPublicTypePanelConfig); case 'leftFixedArea': - return this.leftFixedArea.add(parsedConfig as PanelConfig); + return this.leftFixedArea.add(parsedConfig as IPublicTypePanelConfig); case 'leftFloatArea': - return this.leftFloatArea.add(parsedConfig as PanelConfig); + return this.leftFloatArea.add(parsedConfig as IPublicTypePanelConfig); case 'stages': return this.stages.add(parsedConfig as StageConfig); default: diff --git a/packages/editor-skeleton/src/types.ts b/packages/editor-skeleton/src/types.ts index b73dc4adce..8c5f1484a0 100644 --- a/packages/editor-skeleton/src/types.ts +++ b/packages/editor-skeleton/src/types.ts @@ -1,11 +1,11 @@ import { ReactElement, ComponentType } from 'react'; import { IPublicTypeTitleContent, - IPublicTypeI18nData, IPublicTypeWidgetConfigArea, IPublicTypeWidgetBaseConfig, - IPublicTypePanelDockPanelProps, IPublicTypePanelDockProps, + IPublicTypePanelConfigProps, + IPublicTypePanelConfig, } from '@alilc/lowcode-types'; import { IWidget } from './widget/widget'; @@ -66,40 +66,17 @@ export function isDialogDockConfig(obj: any): obj is DialogDockConfig { return obj && obj.type === 'DialogDock'; } -// 窗格扩展 -export interface PanelConfig extends IPublicTypeWidgetBaseConfig { - type: 'Panel'; - content?: string | ReactElement | ComponentType<any> | PanelConfig[]; // as children - props?: PanelProps; -} - -export function isPanelConfig(obj: any): obj is PanelConfig { +export function isPanelConfig(obj: any): obj is IPublicTypePanelConfig { return obj && obj.type === 'Panel'; } -export type HelpTipConfig = string | { url?: string; content?: string | ReactElement }; - -export interface PanelProps extends IPublicTypePanelDockPanelProps { - title?: IPublicTypeTitleContent; - icon?: any; // 冗余字段 - description?: string | IPublicTypeI18nData; - help?: HelpTipConfig; // 显示问号帮助 - hiddenWhenInit?: boolean; // when this is true, by default will be hidden - condition?: (widget: IWidget) => any; - onInit?: (widget: IWidget) => any; - onDestroy?: () => any; - shortcut?: string; // 只有在特定位置,可触发 toggle show - enableDrag?: boolean; // 是否开启通过 drag 调整 宽度 - keepVisibleWhileDragging?: boolean; // 是否在该 panel 范围内拖拽时保持 visible 状态 -} - export interface PanelDockConfig extends IDockBaseConfig { type: 'PanelDock'; panelName?: string; - panelProps?: PanelProps & { + panelProps?: IPublicTypePanelConfigProps & { area?: IPublicTypeWidgetConfigArea; }; - content?: string | ReactElement | ComponentType<any> | PanelConfig[]; // content for pane + content?: string | ReactElement | ComponentType<any> | IPublicTypePanelConfig[]; // content for pane } export function isPanelDockConfig(obj: any): obj is PanelDockConfig { diff --git a/packages/editor-skeleton/src/widget/panel.ts b/packages/editor-skeleton/src/widget/panel.ts index b35af6a212..3a1ce3b00b 100644 --- a/packages/editor-skeleton/src/widget/panel.ts +++ b/packages/editor-skeleton/src/widget/panel.ts @@ -1,10 +1,9 @@ import { createElement, ReactNode } from 'react'; import { obx, computed, makeObservable, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core'; import { uniqueId, createContent } from '@alilc/lowcode-utils'; -import { IPublicTypeTitleContent } from '@alilc/lowcode-types'; +import { IPublicTypeHelpTipConfig, IPublicTypePanelConfig, IPublicTypeTitleContent } from '@alilc/lowcode-types'; import { WidgetContainer } from './widget-container'; import { getEvent } from '@alilc/lowcode-shell'; -import { PanelConfig, HelpTipConfig } from '../types'; import { TitledPanelView, TabsPanelView, PanelView } from '../components/widget-views'; import { ISkeleton } from '../skeleton'; import { composeTitle } from './utils'; @@ -45,6 +44,7 @@ export class Panel implements IWidget { if (this.container) { return createElement(TabsPanelView, { container: this.container, + shouldHideSingleTab: true, }); } @@ -72,15 +72,15 @@ export class Panel implements IWidget { readonly title: IPublicTypeTitleContent; - readonly help?: HelpTipConfig; + readonly help?: IPublicTypeHelpTipConfig; private plain = false; - private container?: WidgetContainer<Panel, PanelConfig>; + private container?: WidgetContainer<Panel, IPublicTypePanelConfig>; @obx.ref public parent?: WidgetContainer; - constructor(readonly skeleton: ISkeleton, readonly config: PanelConfig) { + constructor(readonly skeleton: ISkeleton, readonly config: IPublicTypePanelConfig) { makeObservable(this); const { name, content, props = {} } = config; const { hideTitleBar, title, icon, description, help } = props; @@ -90,9 +90,6 @@ export class Panel implements IWidget { this.plain = hideTitleBar || !title; this.help = help; if (Array.isArray(content)) { - if (content.length === 1) { - // todo: not show tabs - } this.container = this.skeleton.createContainer( name, (item) => { @@ -127,7 +124,7 @@ export class Panel implements IWidget { this.parent = parent; } - add(item: Panel | PanelConfig) { + add(item: Panel | IPublicTypePanelConfig) { return this.container?.add(item); } diff --git a/packages/types/src/shell/type/widget-base-config.ts b/packages/types/src/shell/type/widget-base-config.ts index b23ba0f137..2764ce1927 100644 --- a/packages/types/src/shell/type/widget-base-config.ts +++ b/packages/types/src/shell/type/widget-base-config.ts @@ -1,4 +1,27 @@ -import { IPublicTypeIconType, IPublicTypeTitleContent, IPublicTypeWidgetConfigArea, TipContent } from './'; +import { ReactElement, ComponentType } from 'react'; +import { IPublicTypeI18nData, IPublicTypeIconType, IPublicTypeTitleContent, IPublicTypeWidgetConfigArea, TipContent } from './'; + +export type IPublicTypeHelpTipConfig = string | { url?: string; content?: string | ReactElement }; + +export interface IPublicTypePanelConfigProps extends IPublicTypePanelDockPanelProps { + title?: IPublicTypeTitleContent; + icon?: any; // 冗余字段 + description?: string | IPublicTypeI18nData; + help?: IPublicTypeHelpTipConfig; // 显示问号帮助 + hiddenWhenInit?: boolean; // when this is true, by default will be hidden + condition?: (widget: any) => any; + onInit?: (widget: any) => any; + onDestroy?: () => any; + shortcut?: string; // 只有在特定位置,可触发 toggle show + enableDrag?: boolean; // 是否开启通过 drag 调整 宽度 + keepVisibleWhileDragging?: boolean; // 是否在该 panel 范围内拖拽时保持 visible 状态 +} + +export interface IPublicTypePanelConfig extends IPublicTypeWidgetBaseConfig { + type: 'Panel'; + content?: string | ReactElement | ComponentType<any> | IPublicTypePanelConfig[]; // as children + props?: IPublicTypePanelConfigProps; +} export interface IPublicTypeWidgetBaseConfig { [extra: string]: any; @@ -13,7 +36,7 @@ export interface IPublicTypeWidgetBaseConfig { */ area?: IPublicTypeWidgetConfigArea; props?: Record<string, any>; - content?: any; + content?: string | ReactElement | ComponentType<any> | IPublicTypePanelConfig[]; contentProps?: Record<string, any>; /** From 594abc4e6c967dc75a6e4aedfd132a778b8312a9 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 18 Dec 2023 14:27:31 +0800 Subject: [PATCH 140/219] style(designer): update bem-tools index --- .../designer/src/builtin-simulator/bem-tools/bem-tools.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/designer/src/builtin-simulator/bem-tools/bem-tools.less b/packages/designer/src/builtin-simulator/bem-tools/bem-tools.less index 83a411e566..8c66e85139 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/bem-tools.less +++ b/packages/designer/src/builtin-simulator/bem-tools/bem-tools.less @@ -6,5 +6,5 @@ bottom: 0; right: 0; overflow: visible; - z-index: 800; + z-index: 1; } From 2bf3aa70a70ebde17139330423d0f02d2a1a8945 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 18 Dec 2023 19:16:42 +0800 Subject: [PATCH 141/219] docs: add skeleton.getAreaItems docs --- docs/docs/api/skeleton.md | 17 +++++++++++++++++ packages/types/src/shell/api/skeleton.ts | 8 +++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/docs/docs/api/skeleton.md b/docs/docs/api/skeleton.md index 5bfa239724..ea5672172c 100644 --- a/docs/docs/api/skeleton.md +++ b/docs/docs/api/skeleton.md @@ -297,7 +297,24 @@ showArea(areaName: string): void; hideArea(areaName: string): void; ``` +### getAreaItems + +获取某个区域下的所有面板实例 + +```typescript +/** + * 获取某个区域下的所有面板实例 + * @param areaName IPublicTypeWidgetConfigArea + */ +getAreaItems(areaName: IPublicTypeWidgetConfigArea): IPublicModelSkeletonItem[] | undefined; +``` + +相关类型:[IPublicModelSkeletonItem](https://github.com/alibaba/lowcode-engine/blob/main/packages/shell/src/model/skeleton-item.ts) + + + ### registerConfigTransducer + 注册一个面板的配置转换器(transducer)。 ```typescript diff --git a/packages/types/src/shell/api/skeleton.ts b/packages/types/src/shell/api/skeleton.ts index 9a36aa4690..83a3f97788 100644 --- a/packages/types/src/shell/api/skeleton.ts +++ b/packages/types/src/shell/api/skeleton.ts @@ -1,5 +1,5 @@ import { IPublicModelSkeletonItem } from '../model'; -import { IPublicTypeConfigTransducer, IPublicTypeDisposable, IPublicTypeSkeletonConfig } from '../type'; +import { IPublicTypeConfigTransducer, IPublicTypeDisposable, IPublicTypeSkeletonConfig, IPublicTypeWidgetConfigArea } from '../type'; export interface IPublicApiSkeleton { @@ -20,6 +20,12 @@ export interface IPublicApiSkeleton { */ remove(config: IPublicTypeSkeletonConfig): number | undefined; + /** + * 获取某个区域下的所有面板实例 + * @param areaName IPublicTypeWidgetConfigArea + */ + getAreaItems(areaName: IPublicTypeWidgetConfigArea): IPublicModelSkeletonItem[] | undefined; + /** * 获取面板实例 * @param name 面板名称 From 4a502f823c149fb10aaa178ec9a2de82476bef71 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Tue, 19 Dec 2023 01:32:47 +0000 Subject: [PATCH 142/219] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 3b9e4902a2..457af1fe31 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.15", + "version": "1.2.16", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From e79f68611a4779e30a9bd455dd1d8e20275823f6 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 19 Dec 2023 17:40:20 +0800 Subject: [PATCH 143/219] feat(skeleton): add onDisableWidget & onEnableWidget APIs --- docs/docs/api/skeleton.md | 35 +++++++++++++++++++++--- packages/shell/src/api/skeleton.ts | 34 ++++++++++++++--------- packages/types/src/shell/api/skeleton.ts | 20 +++++++++++--- 3 files changed, 68 insertions(+), 21 deletions(-) diff --git a/docs/docs/api/skeleton.md b/docs/docs/api/skeleton.md index ea5672172c..0713546e19 100644 --- a/docs/docs/api/skeleton.md +++ b/docs/docs/api/skeleton.md @@ -387,7 +387,7 @@ export default controlPanelWidthPlugin; * @param listener * @returns */ -onShowPanel(listener: (...args: any[]) => void): IPublicTypeDisposable; +onShowPanel(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable; ``` 相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts) @@ -403,11 +403,38 @@ onShowPanel(listener: (...args: any[]) => void): IPublicTypeDisposable; * @param listener * @returns */ -onHidePanel(listener: (...args: any[]) => void): IPublicTypeDisposable; +onHidePanel(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable; ``` 相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts) +### onDisableWidget + +监听 Widget 实例 Disable 事件 + +```typescript +/** + * 监听 Widget 实例 Disable 事件 + * @param listener + */ +onDisableWidget(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable; +``` + +相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts) + +### onEnableWidget + +监听 Widget 实例 Enable 事件 + +```typescript +/** + * 监听 Widget 实例 Enable 事件 + * @param listener + */ +onEnableWidget(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable; +``` + +相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts) ### onShowWidget @@ -420,7 +447,7 @@ onHidePanel(listener: (...args: any[]) => void): IPublicTypeDisposable; * @param listener * @returns */ -onShowWidget(listener: (...args: any[]) => void): IPublicTypeDisposable; +onShowWidget(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable; ``` 相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts) @@ -436,7 +463,7 @@ onShowWidget(listener: (...args: any[]) => void): IPublicTypeDisposable; * @param listener * @returns */ -onHideWidget(listener: (...args: any[]) => void): IPublicTypeDisposable; +onHideWidget(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable; ``` 相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts) diff --git a/packages/shell/src/api/skeleton.ts b/packages/shell/src/api/skeleton.ts index 07a1727dd3..c61edf95d0 100644 --- a/packages/shell/src/api/skeleton.ts +++ b/packages/shell/src/api/skeleton.ts @@ -154,16 +154,30 @@ export class Skeleton implements IPublicApiSkeleton { * @param listener * @returns */ - onShowPanel(listener: (...args: any[]) => void): IPublicTypeDisposable { + onShowPanel(listener: (paneName: string, panel: IPublicModelSkeletonItem) => void): IPublicTypeDisposable { const { editor } = this[skeletonSymbol]; editor.eventBus.on(SkeletonEvents.PANEL_SHOW, (name: any, panel: any) => { - // 不泄漏 skeleton - const { skeleton, ...restPanel } = panel; - listener(name, restPanel); + listener(name, new SkeletonItem(panel)); }); return () => editor.eventBus.off(SkeletonEvents.PANEL_SHOW, listener); } + onDisableWidget(listener: (...args: any[]) => void): IPublicTypeDisposable { + const { editor } = this[skeletonSymbol]; + editor.eventBus.on(SkeletonEvents.WIDGET_DISABLE, (name: any, panel: any) => { + listener(name, new SkeletonItem(panel)); + }); + return () => editor.eventBus.off(SkeletonEvents.WIDGET_DISABLE, listener); + } + + onEnableWidget(listener: (...args: any[]) => void): IPublicTypeDisposable { + const { editor } = this[skeletonSymbol]; + editor.eventBus.on(SkeletonEvents.WIDGET_ENABLE, (name: any, panel: any) => { + listener(name, new SkeletonItem(panel)); + }); + return () => editor.eventBus.off(SkeletonEvents.WIDGET_ENABLE, listener); + } + /** * 监听 panel 隐藏事件 * @param listener @@ -172,9 +186,7 @@ export class Skeleton implements IPublicApiSkeleton { onHidePanel(listener: (...args: any[]) => void): IPublicTypeDisposable { const { editor } = this[skeletonSymbol]; editor.eventBus.on(SkeletonEvents.PANEL_HIDE, (name: any, panel: any) => { - // 不泄漏 skeleton - const { skeleton, ...restPanel } = panel; - listener(name, restPanel); + listener(name, new SkeletonItem(panel)); }); return () => editor.eventBus.off(SkeletonEvents.PANEL_HIDE, listener); } @@ -187,9 +199,7 @@ export class Skeleton implements IPublicApiSkeleton { onShowWidget(listener: (...args: any[]) => void): IPublicTypeDisposable { const { editor } = this[skeletonSymbol]; editor.eventBus.on(SkeletonEvents.WIDGET_SHOW, (name: any, panel: any) => { - // 不泄漏 skeleton - const { skeleton, ...rest } = panel; - listener(name, rest); + listener(name, new SkeletonItem(panel)); }); return () => editor.eventBus.off(SkeletonEvents.WIDGET_SHOW, listener); } @@ -202,9 +212,7 @@ export class Skeleton implements IPublicApiSkeleton { onHideWidget(listener: (...args: any[]) => void): IPublicTypeDisposable { const { editor } = this[skeletonSymbol]; editor.eventBus.on(SkeletonEvents.WIDGET_HIDE, (name: any, panel: any) => { - // 不泄漏 skeleton - const { skeleton, ...rest } = panel; - listener(name, rest); + listener(name, new SkeletonItem(panel)); }); return () => editor.eventBus.off(SkeletonEvents.WIDGET_HIDE, listener); } diff --git a/packages/types/src/shell/api/skeleton.ts b/packages/types/src/shell/api/skeleton.ts index 83a3f97788..1bf788e121 100644 --- a/packages/types/src/shell/api/skeleton.ts +++ b/packages/types/src/shell/api/skeleton.ts @@ -95,7 +95,7 @@ export interface IPublicApiSkeleton { * @param listener * @returns */ - onShowPanel(listener: (...args: any[]) => void): IPublicTypeDisposable; + onShowPanel(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable; /** * 监听 Panel 实例隐藏事件 @@ -103,7 +103,19 @@ export interface IPublicApiSkeleton { * @param listener * @returns */ - onHidePanel(listener: (...args: any[]) => void): IPublicTypeDisposable; + onHidePanel(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable; + + /** + * 监听 Widget 实例 Disable 事件 + * @param listener + */ + onDisableWidget(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable; + + /** + * 监听 Widget 实例 Enable 事件 + * @param listener + */ + onEnableWidget(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable; /** * 监听 Widget 显示事件 @@ -111,7 +123,7 @@ export interface IPublicApiSkeleton { * @param listener * @returns */ - onShowWidget(listener: (...args: any[]) => void): IPublicTypeDisposable; + onShowWidget(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable; /** * 监听 Widget 隐藏事件 @@ -119,7 +131,7 @@ export interface IPublicApiSkeleton { * @param listener * @returns */ - onHideWidget(listener: (...args: any[]) => void): IPublicTypeDisposable; + onHideWidget(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable; /** * 注册一个面板的配置转换器(transducer)。 From 733229985b1835ef273770e1b4da363d948121da Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Tue, 19 Dec 2023 09:57:55 +0000 Subject: [PATCH 144/219] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 457af1fe31..ab6edf5cb5 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.16", + "version": "1.2.17", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 73dacadaee254dd0d6a5229f3ad869168360d47f Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 25 Dec 2023 19:44:40 +0800 Subject: [PATCH 145/219] style(skeleton): update setting pane styles --- .../src/components/settings/settings-primary-pane.tsx | 6 ++++-- packages/utils/src/create-icon.tsx | 5 ++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx b/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx index a68647ed0d..747a2ea1df 100644 --- a/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx +++ b/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx @@ -65,8 +65,10 @@ export class SettingsPrimaryPane extends Component<ISettingsPrimaryPaneProps, { {createIcon(settings.componentMeta?.icon, { className: 'lc-settings-navigator-icon', })} - <Title title={settings.componentMeta!.title} /> - <span> x {settings.nodes.length}</span> + <div style={{ marginLeft: '5px' }}> + <Title title={settings.componentMeta!.title} /> + <span> x {settings.nodes.length}</span> + </div> </div> ); } diff --git a/packages/utils/src/create-icon.tsx b/packages/utils/src/create-icon.tsx index 0a5d6c1ff7..621b5c7ab4 100644 --- a/packages/utils/src/create-icon.tsx +++ b/packages/utils/src/create-icon.tsx @@ -30,7 +30,10 @@ export function createIcon( return cloneElement(icon, { ...props }); } if (isReactComponent(icon)) { - return createElement(icon, { ...props }); + return createElement(icon, { + class: props?.className, + ...props, + }); } return <Icon {...icon} {...props} />; From f483970aef86c0e9591ec4f9bdf6fa9be75f5f46 Mon Sep 17 00:00:00 2001 From: eightHundreds <mingoing@outlook.com> Date: Tue, 12 Dec 2023 16:12:45 +0800 Subject: [PATCH 146/219] fix: trigger node.add event on mergeChildren --- packages/designer/src/document/node/node-children.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/designer/src/document/node/node-children.ts b/packages/designer/src/document/node/node-children.ts index bf982cbfa7..65210fe62c 100644 --- a/packages/designer/src/document/node/node-children.ts +++ b/packages/designer/src/document/node/node-children.ts @@ -462,6 +462,9 @@ export class NodeChildren implements INodeChildren { const node: INode = this.owner.document?.createNode(child); this.children.push(node); node.internalSetParent(this.owner); + /* istanbul ignore next */ + const editor = node.document?.designer.editor; + editor?.eventBus.emit('node.add', { node }); }); changed = true; } From f7ba053476302b5b87d01a856e1ab98076591a3a Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 26 Dec 2023 14:52:24 +0800 Subject: [PATCH 147/219] fix(outline-pane): hover invalid --- packages/plugin-outline-pane/src/views/tree.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugin-outline-pane/src/views/tree.tsx b/packages/plugin-outline-pane/src/views/tree.tsx index 675f70c2b3..8428ec944c 100644 --- a/packages/plugin-outline-pane/src/views/tree.tsx +++ b/packages/plugin-outline-pane/src/views/tree.tsx @@ -40,7 +40,7 @@ export default class TreeView extends PureComponent<{ return; } const node = this.getTreeNodeFromEvent(e)?.node; - detecting?.capture(node as any); + node?.id && detecting?.capture(node.id); } private onClick = (e: ReactMouseEvent) => { From 89e912ba1a3a4e33c0de72773f5fda36a09c4702 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Thu, 28 Dec 2023 05:57:44 +0000 Subject: [PATCH 148/219] chore(release): publish 1.2.4 --- lerna.json | 2 +- packages/designer/package.json | 8 ++++---- packages/editor-core/package.json | 6 +++--- packages/editor-skeleton/package.json | 10 +++++----- packages/engine/package.json | 18 +++++++++--------- packages/ignitor/package.json | 2 +- packages/plugin-designer/package.json | 8 ++++---- packages/plugin-outline-pane/package.json | 6 +++--- packages/rax-renderer/package.json | 6 +++--- packages/rax-simulator-renderer/package.json | 10 +++++----- packages/react-renderer/package.json | 4 ++-- packages/react-simulator-renderer/package.json | 10 +++++----- packages/renderer-core/package.json | 8 ++++---- packages/shell/package.json | 14 +++++++------- packages/types/package.json | 2 +- packages/utils/package.json | 4 ++-- packages/workspace/package.json | 12 ++++++------ 17 files changed, 65 insertions(+), 65 deletions(-) diff --git a/lerna.json b/lerna.json index 98ef80f138..323f3fb412 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "lerna": "4.0.0", - "version": "1.2.3", + "version": "1.2.4", "npmClient": "yarn", "useWorkspaces": true, "packages": [ diff --git a/packages/designer/package.json b/packages/designer/package.json index e961451d88..a681a03bc8 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-designer", - "version": "1.2.3", + "version": "1.2.4", "description": "Designer for Ali LowCode Engine", "main": "lib/index.js", "module": "es/index.js", @@ -15,9 +15,9 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-editor-core": "1.2.3", - "@alilc/lowcode-types": "1.2.3", - "@alilc/lowcode-utils": "1.2.3", + "@alilc/lowcode-editor-core": "1.2.4", + "@alilc/lowcode-types": "1.2.4", + "@alilc/lowcode-utils": "1.2.4", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/editor-core/package.json b/packages/editor-core/package.json index 345783c806..ba638df961 100644 --- a/packages/editor-core/package.json +++ b/packages/editor-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-core", - "version": "1.2.3", + "version": "1.2.4", "description": "Core Api for Ali lowCode engine", "license": "MIT", "main": "lib/index.js", @@ -14,8 +14,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.2.3", - "@alilc/lowcode-utils": "1.2.3", + "@alilc/lowcode-types": "1.2.4", + "@alilc/lowcode-utils": "1.2.4", "classnames": "^2.2.6", "debug": "^4.1.1", "intl-messageformat": "^9.3.1", diff --git a/packages/editor-skeleton/package.json b/packages/editor-skeleton/package.json index fa5c1e13e6..e8b42920f7 100644 --- a/packages/editor-skeleton/package.json +++ b/packages/editor-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-skeleton", - "version": "1.2.3", + "version": "1.2.4", "description": "alibaba lowcode editor skeleton", "main": "lib/index.js", "module": "es/index.js", @@ -19,10 +19,10 @@ ], "dependencies": { "@alifd/next": "^1.20.12", - "@alilc/lowcode-designer": "1.2.3", - "@alilc/lowcode-editor-core": "1.2.3", - "@alilc/lowcode-types": "1.2.3", - "@alilc/lowcode-utils": "1.2.3", + "@alilc/lowcode-designer": "1.2.4", + "@alilc/lowcode-editor-core": "1.2.4", + "@alilc/lowcode-types": "1.2.4", + "@alilc/lowcode-utils": "1.2.4", "classnames": "^2.2.6", "react": "^16.8.1", "react-dom": "^16.8.1" diff --git a/packages/engine/package.json b/packages/engine/package.json index c9eef3534c..092b7c39b3 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine", - "version": "1.2.3", + "version": "1.2.4", "description": "An enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系", "main": "lib/engine-core.js", "module": "es/engine-core.js", @@ -19,15 +19,15 @@ "license": "MIT", "dependencies": { "@alifd/next": "^1.19.12", - "@alilc/lowcode-designer": "1.2.3", - "@alilc/lowcode-editor-core": "1.2.3", - "@alilc/lowcode-editor-skeleton": "1.2.3", + "@alilc/lowcode-designer": "1.2.4", + "@alilc/lowcode-editor-core": "1.2.4", + "@alilc/lowcode-editor-skeleton": "1.2.4", "@alilc/lowcode-engine-ext": "^1.0.0", - "@alilc/lowcode-plugin-designer": "1.2.3", - "@alilc/lowcode-plugin-outline-pane": "1.2.3", - "@alilc/lowcode-shell": "1.2.3", - "@alilc/lowcode-utils": "1.2.3", - "@alilc/lowcode-workspace": "1.2.3", + "@alilc/lowcode-plugin-designer": "1.2.4", + "@alilc/lowcode-plugin-outline-pane": "1.2.4", + "@alilc/lowcode-shell": "1.2.4", + "@alilc/lowcode-utils": "1.2.4", + "@alilc/lowcode-workspace": "1.2.4", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/ignitor/package.json b/packages/ignitor/package.json index 71a21484c4..bdc73a24a8 100644 --- a/packages/ignitor/package.json +++ b/packages/ignitor/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-ignitor", - "version": "1.2.3", + "version": "1.2.4", "description": "点火器,bootstrap lce project", "main": "lib/index.js", "private": true, diff --git a/packages/plugin-designer/package.json b/packages/plugin-designer/package.json index 500c0c9611..8a3c532e6a 100644 --- a/packages/plugin-designer/package.json +++ b/packages/plugin-designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-designer", - "version": "1.2.3", + "version": "1.2.4", "description": "alibaba lowcode editor designer plugin", "files": [ "es", @@ -18,9 +18,9 @@ ], "author": "xiayang.xy", "dependencies": { - "@alilc/lowcode-designer": "1.2.3", - "@alilc/lowcode-editor-core": "1.2.3", - "@alilc/lowcode-utils": "1.2.3", + "@alilc/lowcode-designer": "1.2.4", + "@alilc/lowcode-editor-core": "1.2.4", + "@alilc/lowcode-utils": "1.2.4", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/plugin-outline-pane/package.json b/packages/plugin-outline-pane/package.json index 5a2ef38a45..c2b6424d68 100644 --- a/packages/plugin-outline-pane/package.json +++ b/packages/plugin-outline-pane/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-outline-pane", - "version": "1.2.3", + "version": "1.2.4", "description": "Outline pane for Ali lowCode engine", "files": [ "es", @@ -13,8 +13,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.2.3", - "@alilc/lowcode-utils": "1.2.3", + "@alilc/lowcode-types": "1.2.4", + "@alilc/lowcode-utils": "1.2.4", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/rax-renderer/package.json b/packages/rax-renderer/package.json index 837aebc85e..fa66dbb084 100644 --- a/packages/rax-renderer/package.json +++ b/packages/rax-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-renderer", - "version": "1.2.3", + "version": "1.2.4", "description": "Rax renderer for Ali lowCode engine", "main": "lib/index.js", "module": "es/index.js", @@ -30,8 +30,8 @@ "build": "build-scripts build" }, "dependencies": { - "@alilc/lowcode-renderer-core": "1.2.3", - "@alilc/lowcode-utils": "1.2.3", + "@alilc/lowcode-renderer-core": "1.2.4", + "@alilc/lowcode-utils": "1.2.4", "rax-find-dom-node": "^1.0.1" }, "devDependencies": { diff --git a/packages/rax-simulator-renderer/package.json b/packages/rax-simulator-renderer/package.json index dc9b7b1478..511cfa46dc 100644 --- a/packages/rax-simulator-renderer/package.json +++ b/packages/rax-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-simulator-renderer", - "version": "1.2.3", + "version": "1.2.4", "description": "rax simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -13,10 +13,10 @@ "build:umd": "build-scripts build --config build.umd.json" }, "dependencies": { - "@alilc/lowcode-designer": "1.2.3", - "@alilc/lowcode-rax-renderer": "1.2.3", - "@alilc/lowcode-types": "1.2.3", - "@alilc/lowcode-utils": "1.2.3", + "@alilc/lowcode-designer": "1.2.4", + "@alilc/lowcode-rax-renderer": "1.2.4", + "@alilc/lowcode-types": "1.2.4", + "@alilc/lowcode-utils": "1.2.4", "classnames": "^2.2.6", "driver-universal": "^3.1.3", "history": "^5.0.0", diff --git a/packages/react-renderer/package.json b/packages/react-renderer/package.json index 1dceb9c2e7..53764e8d93 100644 --- a/packages/react-renderer/package.json +++ b/packages/react-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-renderer", - "version": "1.2.3", + "version": "1.2.4", "description": "react renderer for ali lowcode engine", "main": "lib/index.js", "module": "es/index.js", @@ -22,7 +22,7 @@ ], "dependencies": { "@alifd/next": "^1.21.16", - "@alilc/lowcode-renderer-core": "1.2.3" + "@alilc/lowcode-renderer-core": "1.2.4" }, "devDependencies": { "@alib/build-scripts": "^0.1.18", diff --git a/packages/react-simulator-renderer/package.json b/packages/react-simulator-renderer/package.json index 8935c92eef..6c07ea42a0 100644 --- a/packages/react-simulator-renderer/package.json +++ b/packages/react-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-simulator-renderer", - "version": "1.2.3", + "version": "1.2.4", "description": "react simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -17,10 +17,10 @@ "test:cov": "build-scripts test --config build.test.json --jest-coverage" }, "dependencies": { - "@alilc/lowcode-designer": "1.2.3", - "@alilc/lowcode-react-renderer": "1.2.3", - "@alilc/lowcode-types": "1.2.3", - "@alilc/lowcode-utils": "1.2.3", + "@alilc/lowcode-designer": "1.2.4", + "@alilc/lowcode-react-renderer": "1.2.4", + "@alilc/lowcode-types": "1.2.4", + "@alilc/lowcode-utils": "1.2.4", "classnames": "^2.2.6", "mobx": "^6.3.0", "mobx-react": "^7.2.0", diff --git a/packages/renderer-core/package.json b/packages/renderer-core/package.json index 4774ae3689..bc55f80975 100644 --- a/packages/renderer-core/package.json +++ b/packages/renderer-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-renderer-core", - "version": "1.2.3", + "version": "1.2.4", "description": "renderer core", "license": "MIT", "main": "lib/index.js", @@ -16,8 +16,8 @@ }, "dependencies": { "@alilc/lowcode-datasource-engine": "^1.0.0", - "@alilc/lowcode-types": "1.2.3", - "@alilc/lowcode-utils": "1.2.3", + "@alilc/lowcode-types": "1.2.4", + "@alilc/lowcode-utils": "1.2.4", "classnames": "^2.2.6", "debug": "^4.1.1", "fetch-jsonp": "^1.1.3", @@ -32,7 +32,7 @@ "devDependencies": { "@alib/build-scripts": "^0.1.18", "@alifd/next": "^1.26.0", - "@alilc/lowcode-designer": "1.2.3", + "@alilc/lowcode-designer": "1.2.4", "@babel/plugin-transform-typescript": "^7.16.8", "@testing-library/react": "^11.2.2", "@types/classnames": "^2.2.11", diff --git a/packages/shell/package.json b/packages/shell/package.json index 2ebf14bbc2..efb5fc1e28 100644 --- a/packages/shell/package.json +++ b/packages/shell/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-shell", - "version": "1.2.3", + "version": "1.2.4", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -13,12 +13,12 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.2.3", - "@alilc/lowcode-editor-core": "1.2.3", - "@alilc/lowcode-editor-skeleton": "1.2.3", - "@alilc/lowcode-types": "1.2.3", - "@alilc/lowcode-utils": "1.2.3", - "@alilc/lowcode-workspace": "1.2.3", + "@alilc/lowcode-designer": "1.2.4", + "@alilc/lowcode-editor-core": "1.2.4", + "@alilc/lowcode-editor-skeleton": "1.2.4", + "@alilc/lowcode-types": "1.2.4", + "@alilc/lowcode-utils": "1.2.4", + "@alilc/lowcode-workspace": "1.2.4", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", diff --git a/packages/types/package.json b/packages/types/package.json index c0b8e203fe..82624356ea 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-types", - "version": "1.2.3", + "version": "1.2.4", "description": "Types for Ali lowCode engine", "files": [ "es", diff --git a/packages/utils/package.json b/packages/utils/package.json index 00efffb8d3..ac0f36502f 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-utils", - "version": "1.2.3", + "version": "1.2.4", "description": "Utils for Ali lowCode engine", "files": [ "lib", @@ -14,7 +14,7 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.2.3", + "@alilc/lowcode-types": "1.2.4", "lodash": "^4.17.21", "mobx": "^6.3.0", "react": "^16" diff --git a/packages/workspace/package.json b/packages/workspace/package.json index 8c09a93b6c..d3868c3307 100644 --- a/packages/workspace/package.json +++ b/packages/workspace/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-workspace", - "version": "1.2.3", + "version": "1.2.4", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -15,11 +15,11 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.2.3", - "@alilc/lowcode-editor-core": "1.2.3", - "@alilc/lowcode-editor-skeleton": "1.2.3", - "@alilc/lowcode-types": "1.2.3", - "@alilc/lowcode-utils": "1.2.3", + "@alilc/lowcode-designer": "1.2.4", + "@alilc/lowcode-editor-core": "1.2.4", + "@alilc/lowcode-editor-skeleton": "1.2.4", + "@alilc/lowcode-types": "1.2.4", + "@alilc/lowcode-utils": "1.2.4", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", From b2abb67440e8ed36aef465d2b072292acb27c4c3 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Thu, 28 Dec 2023 06:22:34 +0000 Subject: [PATCH 149/219] chore(release): publish 1.2.5 --- lerna.json | 2 +- packages/designer/package.json | 8 ++++---- packages/editor-core/package.json | 6 +++--- packages/editor-skeleton/package.json | 10 +++++----- packages/engine/package.json | 18 +++++++++--------- packages/ignitor/package.json | 2 +- packages/plugin-designer/package.json | 8 ++++---- packages/plugin-outline-pane/package.json | 6 +++--- packages/rax-renderer/package.json | 6 +++--- packages/rax-simulator-renderer/package.json | 10 +++++----- packages/react-renderer/package.json | 4 ++-- packages/react-simulator-renderer/package.json | 10 +++++----- packages/renderer-core/package.json | 8 ++++---- packages/shell/package.json | 14 +++++++------- packages/types/package.json | 2 +- packages/utils/package.json | 4 ++-- packages/workspace/package.json | 12 ++++++------ 17 files changed, 65 insertions(+), 65 deletions(-) diff --git a/lerna.json b/lerna.json index 323f3fb412..1170309170 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "lerna": "4.0.0", - "version": "1.2.4", + "version": "1.2.5", "npmClient": "yarn", "useWorkspaces": true, "packages": [ diff --git a/packages/designer/package.json b/packages/designer/package.json index a681a03bc8..0e6e67e882 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-designer", - "version": "1.2.4", + "version": "1.2.5", "description": "Designer for Ali LowCode Engine", "main": "lib/index.js", "module": "es/index.js", @@ -15,9 +15,9 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-editor-core": "1.2.4", - "@alilc/lowcode-types": "1.2.4", - "@alilc/lowcode-utils": "1.2.4", + "@alilc/lowcode-editor-core": "1.2.5", + "@alilc/lowcode-types": "1.2.5", + "@alilc/lowcode-utils": "1.2.5", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/editor-core/package.json b/packages/editor-core/package.json index ba638df961..0875584501 100644 --- a/packages/editor-core/package.json +++ b/packages/editor-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-core", - "version": "1.2.4", + "version": "1.2.5", "description": "Core Api for Ali lowCode engine", "license": "MIT", "main": "lib/index.js", @@ -14,8 +14,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.2.4", - "@alilc/lowcode-utils": "1.2.4", + "@alilc/lowcode-types": "1.2.5", + "@alilc/lowcode-utils": "1.2.5", "classnames": "^2.2.6", "debug": "^4.1.1", "intl-messageformat": "^9.3.1", diff --git a/packages/editor-skeleton/package.json b/packages/editor-skeleton/package.json index e8b42920f7..648ed5be1f 100644 --- a/packages/editor-skeleton/package.json +++ b/packages/editor-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-skeleton", - "version": "1.2.4", + "version": "1.2.5", "description": "alibaba lowcode editor skeleton", "main": "lib/index.js", "module": "es/index.js", @@ -19,10 +19,10 @@ ], "dependencies": { "@alifd/next": "^1.20.12", - "@alilc/lowcode-designer": "1.2.4", - "@alilc/lowcode-editor-core": "1.2.4", - "@alilc/lowcode-types": "1.2.4", - "@alilc/lowcode-utils": "1.2.4", + "@alilc/lowcode-designer": "1.2.5", + "@alilc/lowcode-editor-core": "1.2.5", + "@alilc/lowcode-types": "1.2.5", + "@alilc/lowcode-utils": "1.2.5", "classnames": "^2.2.6", "react": "^16.8.1", "react-dom": "^16.8.1" diff --git a/packages/engine/package.json b/packages/engine/package.json index 092b7c39b3..4caf32c009 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine", - "version": "1.2.4", + "version": "1.2.5", "description": "An enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系", "main": "lib/engine-core.js", "module": "es/engine-core.js", @@ -19,15 +19,15 @@ "license": "MIT", "dependencies": { "@alifd/next": "^1.19.12", - "@alilc/lowcode-designer": "1.2.4", - "@alilc/lowcode-editor-core": "1.2.4", - "@alilc/lowcode-editor-skeleton": "1.2.4", + "@alilc/lowcode-designer": "1.2.5", + "@alilc/lowcode-editor-core": "1.2.5", + "@alilc/lowcode-editor-skeleton": "1.2.5", "@alilc/lowcode-engine-ext": "^1.0.0", - "@alilc/lowcode-plugin-designer": "1.2.4", - "@alilc/lowcode-plugin-outline-pane": "1.2.4", - "@alilc/lowcode-shell": "1.2.4", - "@alilc/lowcode-utils": "1.2.4", - "@alilc/lowcode-workspace": "1.2.4", + "@alilc/lowcode-plugin-designer": "1.2.5", + "@alilc/lowcode-plugin-outline-pane": "1.2.5", + "@alilc/lowcode-shell": "1.2.5", + "@alilc/lowcode-utils": "1.2.5", + "@alilc/lowcode-workspace": "1.2.5", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/ignitor/package.json b/packages/ignitor/package.json index bdc73a24a8..f131dc14c3 100644 --- a/packages/ignitor/package.json +++ b/packages/ignitor/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-ignitor", - "version": "1.2.4", + "version": "1.2.5", "description": "点火器,bootstrap lce project", "main": "lib/index.js", "private": true, diff --git a/packages/plugin-designer/package.json b/packages/plugin-designer/package.json index 8a3c532e6a..d764f7d9ed 100644 --- a/packages/plugin-designer/package.json +++ b/packages/plugin-designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-designer", - "version": "1.2.4", + "version": "1.2.5", "description": "alibaba lowcode editor designer plugin", "files": [ "es", @@ -18,9 +18,9 @@ ], "author": "xiayang.xy", "dependencies": { - "@alilc/lowcode-designer": "1.2.4", - "@alilc/lowcode-editor-core": "1.2.4", - "@alilc/lowcode-utils": "1.2.4", + "@alilc/lowcode-designer": "1.2.5", + "@alilc/lowcode-editor-core": "1.2.5", + "@alilc/lowcode-utils": "1.2.5", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/plugin-outline-pane/package.json b/packages/plugin-outline-pane/package.json index c2b6424d68..f864356fc8 100644 --- a/packages/plugin-outline-pane/package.json +++ b/packages/plugin-outline-pane/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-outline-pane", - "version": "1.2.4", + "version": "1.2.5", "description": "Outline pane for Ali lowCode engine", "files": [ "es", @@ -13,8 +13,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.2.4", - "@alilc/lowcode-utils": "1.2.4", + "@alilc/lowcode-types": "1.2.5", + "@alilc/lowcode-utils": "1.2.5", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/rax-renderer/package.json b/packages/rax-renderer/package.json index fa66dbb084..8173d6e4e1 100644 --- a/packages/rax-renderer/package.json +++ b/packages/rax-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-renderer", - "version": "1.2.4", + "version": "1.2.5", "description": "Rax renderer for Ali lowCode engine", "main": "lib/index.js", "module": "es/index.js", @@ -30,8 +30,8 @@ "build": "build-scripts build" }, "dependencies": { - "@alilc/lowcode-renderer-core": "1.2.4", - "@alilc/lowcode-utils": "1.2.4", + "@alilc/lowcode-renderer-core": "1.2.5", + "@alilc/lowcode-utils": "1.2.5", "rax-find-dom-node": "^1.0.1" }, "devDependencies": { diff --git a/packages/rax-simulator-renderer/package.json b/packages/rax-simulator-renderer/package.json index 511cfa46dc..f264380ec1 100644 --- a/packages/rax-simulator-renderer/package.json +++ b/packages/rax-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-rax-simulator-renderer", - "version": "1.2.4", + "version": "1.2.5", "description": "rax simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -13,10 +13,10 @@ "build:umd": "build-scripts build --config build.umd.json" }, "dependencies": { - "@alilc/lowcode-designer": "1.2.4", - "@alilc/lowcode-rax-renderer": "1.2.4", - "@alilc/lowcode-types": "1.2.4", - "@alilc/lowcode-utils": "1.2.4", + "@alilc/lowcode-designer": "1.2.5", + "@alilc/lowcode-rax-renderer": "1.2.5", + "@alilc/lowcode-types": "1.2.5", + "@alilc/lowcode-utils": "1.2.5", "classnames": "^2.2.6", "driver-universal": "^3.1.3", "history": "^5.0.0", diff --git a/packages/react-renderer/package.json b/packages/react-renderer/package.json index 53764e8d93..2970e93410 100644 --- a/packages/react-renderer/package.json +++ b/packages/react-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-renderer", - "version": "1.2.4", + "version": "1.2.5", "description": "react renderer for ali lowcode engine", "main": "lib/index.js", "module": "es/index.js", @@ -22,7 +22,7 @@ ], "dependencies": { "@alifd/next": "^1.21.16", - "@alilc/lowcode-renderer-core": "1.2.4" + "@alilc/lowcode-renderer-core": "1.2.5" }, "devDependencies": { "@alib/build-scripts": "^0.1.18", diff --git a/packages/react-simulator-renderer/package.json b/packages/react-simulator-renderer/package.json index 6c07ea42a0..030a197082 100644 --- a/packages/react-simulator-renderer/package.json +++ b/packages/react-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-simulator-renderer", - "version": "1.2.4", + "version": "1.2.5", "description": "react simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -17,10 +17,10 @@ "test:cov": "build-scripts test --config build.test.json --jest-coverage" }, "dependencies": { - "@alilc/lowcode-designer": "1.2.4", - "@alilc/lowcode-react-renderer": "1.2.4", - "@alilc/lowcode-types": "1.2.4", - "@alilc/lowcode-utils": "1.2.4", + "@alilc/lowcode-designer": "1.2.5", + "@alilc/lowcode-react-renderer": "1.2.5", + "@alilc/lowcode-types": "1.2.5", + "@alilc/lowcode-utils": "1.2.5", "classnames": "^2.2.6", "mobx": "^6.3.0", "mobx-react": "^7.2.0", diff --git a/packages/renderer-core/package.json b/packages/renderer-core/package.json index bc55f80975..fab0d3f133 100644 --- a/packages/renderer-core/package.json +++ b/packages/renderer-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-renderer-core", - "version": "1.2.4", + "version": "1.2.5", "description": "renderer core", "license": "MIT", "main": "lib/index.js", @@ -16,8 +16,8 @@ }, "dependencies": { "@alilc/lowcode-datasource-engine": "^1.0.0", - "@alilc/lowcode-types": "1.2.4", - "@alilc/lowcode-utils": "1.2.4", + "@alilc/lowcode-types": "1.2.5", + "@alilc/lowcode-utils": "1.2.5", "classnames": "^2.2.6", "debug": "^4.1.1", "fetch-jsonp": "^1.1.3", @@ -32,7 +32,7 @@ "devDependencies": { "@alib/build-scripts": "^0.1.18", "@alifd/next": "^1.26.0", - "@alilc/lowcode-designer": "1.2.4", + "@alilc/lowcode-designer": "1.2.5", "@babel/plugin-transform-typescript": "^7.16.8", "@testing-library/react": "^11.2.2", "@types/classnames": "^2.2.11", diff --git a/packages/shell/package.json b/packages/shell/package.json index efb5fc1e28..86c4c7d11e 100644 --- a/packages/shell/package.json +++ b/packages/shell/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-shell", - "version": "1.2.4", + "version": "1.2.5", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -13,12 +13,12 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.2.4", - "@alilc/lowcode-editor-core": "1.2.4", - "@alilc/lowcode-editor-skeleton": "1.2.4", - "@alilc/lowcode-types": "1.2.4", - "@alilc/lowcode-utils": "1.2.4", - "@alilc/lowcode-workspace": "1.2.4", + "@alilc/lowcode-designer": "1.2.5", + "@alilc/lowcode-editor-core": "1.2.5", + "@alilc/lowcode-editor-skeleton": "1.2.5", + "@alilc/lowcode-types": "1.2.5", + "@alilc/lowcode-utils": "1.2.5", + "@alilc/lowcode-workspace": "1.2.5", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", diff --git a/packages/types/package.json b/packages/types/package.json index 82624356ea..52a5e03ae0 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-types", - "version": "1.2.4", + "version": "1.2.5", "description": "Types for Ali lowCode engine", "files": [ "es", diff --git a/packages/utils/package.json b/packages/utils/package.json index ac0f36502f..976b76341b 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-utils", - "version": "1.2.4", + "version": "1.2.5", "description": "Utils for Ali lowCode engine", "files": [ "lib", @@ -14,7 +14,7 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.2.4", + "@alilc/lowcode-types": "1.2.5", "lodash": "^4.17.21", "mobx": "^6.3.0", "react": "^16" diff --git a/packages/workspace/package.json b/packages/workspace/package.json index d3868c3307..cbc31f3797 100644 --- a/packages/workspace/package.json +++ b/packages/workspace/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-workspace", - "version": "1.2.4", + "version": "1.2.5", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -15,11 +15,11 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.2.4", - "@alilc/lowcode-editor-core": "1.2.4", - "@alilc/lowcode-editor-skeleton": "1.2.4", - "@alilc/lowcode-types": "1.2.4", - "@alilc/lowcode-utils": "1.2.4", + "@alilc/lowcode-designer": "1.2.5", + "@alilc/lowcode-editor-core": "1.2.5", + "@alilc/lowcode-editor-skeleton": "1.2.5", + "@alilc/lowcode-types": "1.2.5", + "@alilc/lowcode-utils": "1.2.5", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", From 7b85a35b2419f5b2390be0243056ac815e140c0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=81=AA=E5=B0=8F=E9=99=88?= <xiaohuoni@users.noreply.github.com> Date: Tue, 2 Jan 2024 18:15:30 +0800 Subject: [PATCH 150/219] feat: zip publisher support browser (#2744) --- modules/code-generator/README.md | 14 ++++- modules/code-generator/package.json | 2 + .../code-generator/src/publisher/zip/index.ts | 18 ++++--- .../code-generator/src/publisher/zip/utils.ts | 3 +- .../tests/public/publisher/zip/zip.test.ts | 51 +++++++++++++++++-- 5 files changed, 74 insertions(+), 14 deletions(-) diff --git a/modules/code-generator/README.md b/modules/code-generator/README.md index 03ce94b54e..1d67b3aa16 100644 --- a/modules/code-generator/README.md +++ b/modules/code-generator/README.md @@ -94,16 +94,26 @@ await CodeGenerator.init(); 4. 出码 ```js -const result = await CodeGenerator.generateCode({ +const project = await CodeGenerator.generateCode({ solution: 'icejs', // 出码方案 (目前内置有 icejs 和 rax ) schema, // 编排搭建出来的 schema }); -console.log(result); // 出码结果(默认是递归结构描述的,可以传 flattenResult: true 以生成扁平结构的结果) +console.log(project); // 出码结果(默认是递归结构描述的,可以传 flattenResult: true 以生成扁平结构的结果) ``` 注:一般来说在浏览器中出码适合做即时预览功能。 +5. 下载 zip 包 + +```js +// 写入到 zip 包 +await CodeGenerator.publishers.zip().publish({ + project, // 上一步生成的 project + projectSlug: 'your-project-slug', // 项目标识 -- 对应下载 your-project-slug.zip 文件 +}); +``` + ### 5)自定义出码 前端框架灵活多变,默认内置的出码方案很难满足所有人的需求,好在此代码生成器支持非常灵活的插件机制 -- 欢迎参考 ./src/plugins/xxx 来编写您自己的出码插件,然后参考 ./src/solutions/xxx 将各种插件组合成一套适合您的业务场景的出码方案。 diff --git a/modules/code-generator/package.json b/modules/code-generator/package.json index 6ff1ecb63f..5c0d91cc08 100644 --- a/modules/code-generator/package.json +++ b/modules/code-generator/package.json @@ -80,6 +80,7 @@ "change-case": "^3.1.0", "commander": "^6.1.0", "debug": "^4.3.2", + "file-saver": "^2.0.5", "fp-ts": "^2.11.9", "fs-extra": "9.x", "glob": "^7.2.0", @@ -109,6 +110,7 @@ "devDependencies": { "@iceworks/spec": "^1.4.2", "@types/babel__traverse": "^7.11.0", + "@types/file-saver": "^2.0.7", "@types/jest": "^27.0.2", "@types/lodash": "^4.14.162", "@types/node": "^14.14.20", diff --git a/modules/code-generator/src/publisher/zip/index.ts b/modules/code-generator/src/publisher/zip/index.ts index cc2f082b27..0ac0b6f67f 100644 --- a/modules/code-generator/src/publisher/zip/index.ts +++ b/modules/code-generator/src/publisher/zip/index.ts @@ -2,9 +2,9 @@ import { ResultDir } from '@alilc/lowcode-types'; import { PublisherFactory, IPublisher, IPublisherFactoryParams, PublisherError } from '../../types'; import { getErrorMessage } from '../../utils/errors'; import { isNodeProcess, writeZipToDisk, generateProjectZip } from './utils'; +import { saveAs } from 'file-saver'; -// export type ZipBuffer = Buffer | Blob; -export type ZipBuffer = Buffer; +export type ZipBuffer = Buffer | Blob; declare type ZipPublisherResponse = string | ZipBuffer; @@ -44,10 +44,16 @@ export const createZipPublisher: PublisherFactory<ZipFactoryParams, ZipPublisher try { const zipContent = await generateProjectZip(projectToPublish); - // If not output path is provided, zip is not written to disk - const projectOutputPath = options.outputPath || outputPath; - if (projectOutputPath && isNodeProcess()) { - await writeZipToDisk(projectOutputPath, zipContent, zipName); + if (isNodeProcess()) { + // If not output path is provided on the node side, zip is not written to disk + const projectOutputPath = options.outputPath || outputPath; + if (projectOutputPath) { + await writeZipToDisk(projectOutputPath, zipContent, zipName); + } + } else { + // the browser end does not require a path + // auto download zip files + saveAs(zipContent as Blob, `${zipName}.zip`); } return { success: true, payload: zipContent }; diff --git a/modules/code-generator/src/publisher/zip/utils.ts b/modules/code-generator/src/publisher/zip/utils.ts index 10e1ad4a68..08d3a12f44 100644 --- a/modules/code-generator/src/publisher/zip/utils.ts +++ b/modules/code-generator/src/publisher/zip/utils.ts @@ -40,8 +40,7 @@ export const writeZipToDisk = ( export const generateProjectZip = async (project: ResultDir): Promise<ZipBuffer> => { let zip = new JSZip(); zip = writeFolderToZip(project, zip, true); - // const zipType = isNodeProcess() ? 'nodebuffer' : 'blob'; - const zipType = 'nodebuffer'; // 目前先只支持 node 调用 + const zipType = isNodeProcess() ? 'nodebuffer' : 'blob'; return zip.generateAsync({ type: zipType }); }; diff --git a/modules/code-generator/tests/public/publisher/zip/zip.test.ts b/modules/code-generator/tests/public/publisher/zip/zip.test.ts index ed37980d03..d51957004a 100644 --- a/modules/code-generator/tests/public/publisher/zip/zip.test.ts +++ b/modules/code-generator/tests/public/publisher/zip/zip.test.ts @@ -1,6 +1,14 @@ import CodeGen from '../../../../src'; +import fileSaver from 'file-saver'; +import * as utils from '../../../../src/publisher/zip/utils'; + +jest.mock('file-saver'); describe('public/publisher/zip/zip', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + it('should works', async () => { const zip = CodeGen.publishers.zip({ outputPath: 'demo-output', @@ -19,15 +27,15 @@ describe('public/publisher/zip/zip', () => { ], }; - expect(zip.getOutputPath()).toMatchInlineSnapshot(`"demo-output"`); + expect(zip.getOutputPath()).toMatchInlineSnapshot('"demo-output"'); - expect(zip.getProject()).toMatchInlineSnapshot(`undefined`); + expect(zip.getProject()).toMatchInlineSnapshot('undefined'); zip.setProject(demoProject); expect(zip.getProject()).toBeTruthy(); - expect(zip.getOutputPath()).toMatchInlineSnapshot(`"demo-output"`); + expect(zip.getOutputPath()).toMatchInlineSnapshot('"demo-output"'); expect(zip.setOutputPath('output')).toBe(undefined); - expect(zip.getOutputPath()).toMatchInlineSnapshot(`"output"`); + expect(zip.getOutputPath()).toMatchInlineSnapshot('"output"'); const publishRes = await zip.publish({ project: demoProject, @@ -41,4 +49,39 @@ describe('public/publisher/zip/zip', () => { const zip = CodeGen.publishers.zip({}); expect(zip.publish()).rejects.toBeTruthy(); }); + + it('should publish the project as a zip file in the browser', async () => { + const zipContent = 'zip content'; + const zipName = 'example-project'; + jest.spyOn(utils, 'isNodeProcess').mockReturnValue(false); + // new Zip 里面也有平台判断,所以这里 mock + jest.spyOn(utils, 'generateProjectZip').mockResolvedValue(zipContent as any); + const spy = jest.spyOn(fileSaver, 'saveAs'); + + const zip = CodeGen.publishers.zip({ + projectSlug: zipName, + }); + + const demoProject = { + name: 'demo', + dirs: [], + files: [ + { + name: 'package', + ext: 'json', + content: '{ "name": "demo", "version": "1.0.0" }', + }, + ], + }; + + zip.setProject(demoProject); + const publishRes = await zip.publish({ + project: demoProject, + }); + + expect(publishRes.success).toBeTruthy(); + expect(spy).toBeCalledWith(zipContent, `${zipName}.zip`); + spy.mockReset(); + spy.mockRestore(); + }); }); From 173978ffd4f8b13f6babcc5c14b2c450bca73eb7 Mon Sep 17 00:00:00 2001 From: wangwei <1021281778@qq.com> Date: Wed, 3 Jan 2024 15:17:40 +0800 Subject: [PATCH 151/219] chore(release): code-gen 1.1.7 --- modules/code-generator/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/code-generator/package.json b/modules/code-generator/package.json index 5c0d91cc08..cd114fa067 100644 --- a/modules/code-generator/package.json +++ b/modules/code-generator/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-code-generator", - "version": "1.1.6", + "version": "1.1.7", "description": "出码引擎 for LowCode Engine", "license": "MIT", "main": "lib/index.js", From e1f3a11c4197317fd9a520ca014b78905096b46f Mon Sep 17 00:00:00 2001 From: LiuTeiTei <ltt_catchyou@163.com> Date: Thu, 4 Jan 2024 18:20:22 +0800 Subject: [PATCH 152/219] fix: trigger onFilterResultChanged when filtered --- .../src/views/filter-tree.ts | 5 +++++ .../src/views/tree-node.tsx | 16 +++++++++++--- .../src/views/tree-title.tsx | 22 +++++++++++++------ 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/packages/plugin-outline-pane/src/views/filter-tree.ts b/packages/plugin-outline-pane/src/views/filter-tree.ts index 2a07e15c6b..793aa03cc5 100644 --- a/packages/plugin-outline-pane/src/views/filter-tree.ts +++ b/packages/plugin-outline-pane/src/views/filter-tree.ts @@ -77,6 +77,11 @@ export const matchTreeNode = ( return matchTreeNode(childNode, keywords, filterOps); }).find(Boolean); + // 如果命中了子节点,需要将该节点展开 + if (matchChild && treeNode.expandable) { + treeNode.setExpanded(true); + } + treeNode.setFilterReult({ filterWorking: true, matchChild, diff --git a/packages/plugin-outline-pane/src/views/tree-node.tsx b/packages/plugin-outline-pane/src/views/tree-node.tsx index be6e6ae2c8..11bd95d12f 100644 --- a/packages/plugin-outline-pane/src/views/tree-node.tsx +++ b/packages/plugin-outline-pane/src/views/tree-node.tsx @@ -34,7 +34,7 @@ class ModalTreeNodeView extends PureComponent<{ } componentDidMount(): void { - const rootTreeNode = this.rootTreeNode; + const { rootTreeNode } = this; rootTreeNode.onExpandableChanged(() => { this.setState({ treeChildren: rootTreeNode.children, @@ -53,7 +53,7 @@ class ModalTreeNodeView extends PureComponent<{ } render() { - const rootTreeNode = this.rootTreeNode; + const { rootTreeNode } = this; const { expanded } = rootTreeNode; const hasVisibleModalNode = !!this.modalNodesManager?.getVisibleModalNode(); @@ -98,6 +98,9 @@ export default class TreeNodeView extends PureComponent<{ conditionFlow: boolean; expandable: boolean; treeChildren: TreeNode[] | null; + filterWorking: boolean; + matchChild: boolean; + matchSelf: boolean; } = { expanded: false, selected: false, @@ -110,6 +113,9 @@ export default class TreeNodeView extends PureComponent<{ conditionFlow: false, expandable: false, treeChildren: [], + filterWorking: false, + matchChild: false, + matchSelf: false, }; eventOffCallbacks: Array<IPublicTypeDisposable | undefined> = []; @@ -154,6 +160,10 @@ export default class TreeNodeView extends PureComponent<{ treeChildren: treeNode.children, }); }); + treeNode.onFilterResultChanged(() => { + const { filterWorking: newFilterWorking, matchChild: newMatchChild, matchSelf: newMatchSelf } = treeNode.filterReult; + this.setState({ filterWorking: newFilterWorking, matchChild: newMatchChild, matchSelf: newMatchSelf }); + }); this.eventOffCallbacks.push( doc?.onDropLocationChanged(() => { this.setState({ @@ -216,7 +226,7 @@ export default class TreeNodeView extends PureComponent<{ let shouldShowModalTreeNode: boolean = this.shouldShowModalTreeNode(); // filter 处理 - const { filterWorking, matchChild, matchSelf } = treeNode.filterReult; + const { filterWorking, matchChild, matchSelf } = this.state; if (!isRootNode && filterWorking && !matchChild && !matchSelf) { // 条件过滤生效时,如果未命中本节点或子节点,则不展示该节点 // 根节点始终展示 diff --git a/packages/plugin-outline-pane/src/views/tree-title.tsx b/packages/plugin-outline-pane/src/views/tree-title.tsx index c8c0e75b09..f822bd644b 100644 --- a/packages/plugin-outline-pane/src/views/tree-title.tsx +++ b/packages/plugin-outline-pane/src/views/tree-title.tsx @@ -29,9 +29,15 @@ export default class TreeTitle extends PureComponent<{ title: string; condition?: boolean; visible?: boolean; + filterWorking: boolean; + keywords: string; + matchSelf: boolean; } = { editing: false, title: '', + filterWorking: false, + keywords: '', + matchSelf: false, }; private lastInput?: HTMLInputElement; @@ -100,6 +106,10 @@ export default class TreeTitle extends PureComponent<{ visible: !hidden, }); }); + treeNode.onFilterResultChanged(() => { + const { filterWorking: newFilterWorking, keywords: newKeywords, matchSelf: newMatchSelf } = treeNode.filterReult; + this.setState({ filterWorking: newFilterWorking, keywords: newKeywords, matchSelf: newMatchSelf }); + }); } deleteClick = () => { const { treeNode } = this.props; @@ -109,7 +119,7 @@ export default class TreeTitle extends PureComponent<{ render() { const { treeNode, isModal } = this.props; const { pluginContext } = treeNode; - const { editing } = this.state; + const { editing, filterWorking, matchSelf, keywords } = this.state; const isCNode = !treeNode.isRoot(); const { node } = treeNode; const { componentMeta } = node; @@ -125,11 +135,9 @@ export default class TreeTitle extends PureComponent<{ marginLeft: -indent, }; } - const { filterWorking, matchSelf, keywords } = treeNode.filterReult; const Extra = pluginContext.extraTitle; const { intlNode, common, config } = pluginContext; - const Tip = common.editorCabin.Tip; - const Title = common.editorCabin.Title; + const { Tip, Title } = common.editorCabin; const couldHide = availableActions.includes('hide'); const couldLock = availableActions.includes('lock'); const couldUnlock = availableActions.includes('unlock'); @@ -253,7 +261,7 @@ class RenameBtn extends PureComponent<{ }> { render() { const { intl, common } = this.props.treeNode.pluginContext; - const Tip = common.editorCabin.Tip; + const { Tip } = common.editorCabin; return ( <div className="tree-node-rename-btn" @@ -274,7 +282,7 @@ class LockBtn extends PureComponent<{ render() { const { treeNode, locked } = this.props; const { intl, common } = this.props.treeNode.pluginContext; - const Tip = common.editorCabin.Tip; + const { Tip } = common.editorCabin; return ( <div className="tree-node-lock-btn" @@ -300,7 +308,7 @@ class HideBtn extends PureComponent<{ render() { const { treeNode, hidden } = this.props; const { intl, common } = treeNode.pluginContext; - const Tip = common.editorCabin.Tip; + const { Tip } = common.editorCabin; return ( <div className="tree-node-hide-btn" From c24c3d8ae59e4ee9cf17c5816f088463aedb5a44 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 5 Jan 2024 10:33:10 +0800 Subject: [PATCH 153/219] feat: add hideComponentAction config --- docs/docs/api/configOptions.md | 6 ++++++ .../builtin-simulator/bem-tools/border-selecting.tsx | 10 +++++++--- packages/editor-core/src/config.ts | 5 +++++ packages/types/src/shell/type/engine-options.ts | 6 ++++++ 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/docs/docs/api/configOptions.md b/docs/docs/api/configOptions.md index aaea28261d..5f6ade710f 100644 --- a/docs/docs/api/configOptions.md +++ b/docs/docs/api/configOptions.md @@ -216,6 +216,12 @@ config.set('enableCondition', false) 是否在只有一个 item 的时候隐藏设置 tabs +#### hideComponentAction + +`@type {boolean}` `@default {false}` + +隐藏设计器辅助层 + #### thisRequiredInJSE `@type {boolean}` `@default {true}` diff --git a/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx b/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx index 4f452727d2..143c67e020 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx +++ b/packages/designer/src/builtin-simulator/bem-tools/border-selecting.tsx @@ -9,7 +9,7 @@ import { ComponentType, } from 'react'; import classNames from 'classnames'; -import { observer, computed, Tip } from '@alilc/lowcode-editor-core'; +import { observer, computed, Tip, engineConfig } from '@alilc/lowcode-editor-core'; import { createIcon, isReactComponent, isActionContentObject } from '@alilc/lowcode-utils'; import { IPublicTypeActionContentObject } from '@alilc/lowcode-types'; import { BuiltinSimulatorHost } from '../host'; @@ -47,14 +47,18 @@ export class BorderSelectingInstance extends Component<{ }); const { hideSelectTools } = observed.node.componentMeta.advanced; + const hideComponentAction = engineConfig.get('hideComponentAction'); if (hideSelectTools) { return null; } return ( - <div className={className} style={style}> - {!dragging && <Toolbar observed={observed} />} + <div + className={className} + style={style} + > + {(!dragging && !hideComponentAction) ? <Toolbar observed={observed} /> : null} </div> ); } diff --git a/packages/editor-core/src/config.ts b/packages/editor-core/src/config.ts index 85e6097801..1c73347b74 100644 --- a/packages/editor-core/src/config.ts +++ b/packages/editor-core/src/config.ts @@ -159,6 +159,11 @@ const VALID_ENGINE_OPTIONS = { type: 'function', description: '应用级设计模式下,窗口为空时展示的占位组件', }, + hideComponentAction: { + type: 'boolean', + description: '是否隐藏设计器辅助层', + default: false, + }, }; const getStrictModeValue = (engineOptions: IPublicTypeEngineOptions, defaultValue: boolean): boolean => { diff --git a/packages/types/src/shell/type/engine-options.ts b/packages/types/src/shell/type/engine-options.ts index f177166530..b570d1990a 100644 --- a/packages/types/src/shell/type/engine-options.ts +++ b/packages/types/src/shell/type/engine-options.ts @@ -177,6 +177,12 @@ export interface IPublicTypeEngineOptions { * 应用级设计模式下,自动打开第一个窗口 */ enableAutoOpenFirstWindow?: boolean; + + /** + * @default false + * 隐藏设计器辅助层 + */ + hideComponentAction?: boolean; } /** From d81eb8d75da665ab9603339bfe78759fe6e2f602 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 5 Jan 2024 10:37:15 +0800 Subject: [PATCH 154/219] style(outline): update selected item style --- packages/plugin-outline-pane/src/views/style.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugin-outline-pane/src/views/style.less b/packages/plugin-outline-pane/src/views/style.less index 8521883b49..8a38ba749b 100644 --- a/packages/plugin-outline-pane/src/views/style.less +++ b/packages/plugin-outline-pane/src/views/style.less @@ -356,7 +356,7 @@ // 选中节点处理 &.selected { & > .tree-node-title { - background: var(--color-block-background-shallow); + background: var(--color-block-background-light); } & > .tree-node-branches::before { From be0456fb398c731c4492fbca83aebc8ed9e9f3f3 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 5 Jan 2024 11:32:28 +0800 Subject: [PATCH 155/219] feat: add commonUI API --- docs/docs/api/commonUI.md | 118 ++++++++++++++++++ packages/designer/src/component-meta.ts | 8 +- .../designer/src/plugin/plugin-context.ts | 3 + packages/designer/src/plugin/plugin-types.ts | 2 + .../editor-core/src/widgets/title/index.tsx | 10 +- packages/engine/src/engine-core.ts | 5 + packages/shell/src/api/commonUI.ts | 43 +++++++ packages/shell/src/api/index.ts | 3 +- packages/shell/src/index.ts | 2 + packages/types/src/shell/api/commonUI.ts | 48 +++++++ packages/types/src/shell/api/index.ts | 1 + .../types/src/shell/model/plugin-context.ts | 7 ++ packages/types/src/shell/type/tip-config.ts | 12 ++ packages/types/src/shell/type/title-config.ts | 27 +++- .../workspace/src/context/base-context.ts | 4 + 15 files changed, 281 insertions(+), 12 deletions(-) create mode 100644 docs/docs/api/commonUI.md create mode 100644 packages/shell/src/api/commonUI.ts create mode 100644 packages/types/src/shell/api/commonUI.ts diff --git a/docs/docs/api/commonUI.md b/docs/docs/api/commonUI.md new file mode 100644 index 0000000000..9d1f706520 --- /dev/null +++ b/docs/docs/api/commonUI.md @@ -0,0 +1,118 @@ +--- +title: commonUI - UI 组件库 +sidebar_position: 11 +--- + +## 简介 +CommonUI API 是一个专为低代码引擎设计的组件 UI 库,使用它开发的插件,可以保证在不同项目和主题切换中能够保持一致性和兼容性。 + +## 组件列表 + +### Tip + +提示组件 + +| 参数 | 说明 | 类型 | 默认值 | +|-----------|--------------|---------------------------------------|--------| +| className | className | string (optional) | | +| children | tip 的内容 | IPublicTypeI18nData \| ReactNode | | +| direction | tip 的方向 | 'top' \| 'bottom' \| 'left' \| 'right' | | + + +### Title + +标题组件 + +| 参数 | 说明 | 类型 | 默认值 | +|-----------|------------|-----------------------------|--------| +| title | 标题内容 | IPublicTypeTitleContent | | +| className | className | string (optional) | | +| onClick | 点击事件 | () => void (optional) | | + +### Balloon +详细文档: [Balloon Documentation](https://fusion.design/pc/component/balloon) + +### Breadcrumb +详细文档: [Breadcrumb Documentation](https://fusion.design/pc/component/breadcrumb) + +### Button +详细文档: [Button Documentation](https://fusion.design/pc/component/button) + +### Card +详细文档: [Card Documentation](https://fusion.design/pc/component/card) + +### Checkbox +详细文档: [Checkbox Documentation](https://fusion.design/pc/component/checkbox) + +### DatePicker +详细文档: [DatePicker Documentation](https://fusion.design/pc/component/datepicker) + +### Dialog +详细文档: [Dialog Documentation](https://fusion.design/pc/component/dialog) + +### Dropdown +详细文档: [Dropdown Documentation](https://fusion.design/pc/component/dropdown) + +### Form +详细文档: [Form Documentation](https://fusion.design/pc/component/form) + +### Icon +详细文档: [Icon Documentation](https://fusion.design/pc/component/icon) + +引擎默认主题支持的 icon 列表:https://fusion.design/64063/component/icon?themeid=20133 + + +### Input +详细文档: [Input Documentation](https://fusion.design/pc/component/input) + +### Loading +详细文档: [Loading Documentation](https://fusion.design/pc/component/loading) + +### Message +详细文档: [Message Documentation](https://fusion.design/pc/component/message) + +### Overlay +详细文档: [Overlay Documentation](https://fusion.design/pc/component/overlay) + +### Pagination +详细文档: [Pagination Documentation](https://fusion.design/pc/component/pagination) + +### Radio +详细文档: [Radio Documentation](https://fusion.design/pc/component/radio) + +### Search +详细文档: [Search Documentation](https://fusion.design/pc/component/search) + +### Select +详细文档: [Select Documentation](https://fusion.design/pc/component/select) + +### SplitButton +详细文档: [SplitButton Documentation](https://fusion.design/pc/component/splitbutton) + +### Step +详细文档: [Step Documentation](https://fusion.design/pc/component/step) + +### Switch +详细文档: [Switch Documentation](https://fusion.design/pc/component/switch) + +### Tab +详细文档: [Tab Documentation](https://fusion.design/pc/component/tab) + +### Table +详细文档: [Table Documentation](https://fusion.design/pc/component/table) + +### Tree +详细文档: [Tree Documentation](https://fusion.design/pc/component/tree) + +### TreeSelect +详细文档: [TreeSelect Documentation](https://fusion.design/pc/component/treeselect) + +### Upload +详细文档: [Upload Documentation](https://fusion.design/pc/component/upload) + +### Divider +详细文档: [Divider Documentation](https://fusion.design/pc/component/divider) + +## 说明 + +如果需要其他组件,可以提issue给我们 \ No newline at end of file diff --git a/packages/designer/src/component-meta.ts b/packages/designer/src/component-meta.ts index 00c4956217..1ee1154f18 100644 --- a/packages/designer/src/component-meta.ts +++ b/packages/designer/src/component-meta.ts @@ -48,13 +48,17 @@ export function buildFilter(rule?: string | string[] | RegExp | IPublicTypeNesti return rule; } if (isRegExp(rule)) { - return (testNode: Node | IPublicTypeNodeSchema) => rule.test(testNode.componentName); + return (testNode: Node | IPublicTypeNodeSchema) => { + return rule.test(testNode.componentName); + }; } const list = ensureAList(rule); if (!list) { return null; } - return (testNode: Node | IPublicTypeNodeSchema) => list.includes(testNode.componentName); + return (testNode: Node | IPublicTypeNodeSchema) => { + return list.includes(testNode.componentName); + }; } export interface IComponentMeta extends IPublicModelComponentMeta<INode> { diff --git a/packages/designer/src/plugin/plugin-context.ts b/packages/designer/src/plugin/plugin-context.ts index 94e296fd1c..7f26a2b4f3 100644 --- a/packages/designer/src/plugin/plugin-context.ts +++ b/packages/designer/src/plugin/plugin-context.ts @@ -19,6 +19,7 @@ import { IPublicApiWorkspace, IPublicEnumPluginRegisterLevel, IPublicModelWindow, + IPublicApiCommonUI, } from '@alilc/lowcode-types'; import { IPluginContextOptions, @@ -45,6 +46,8 @@ export default class PluginContext implements workspace: IPublicApiWorkspace; registerLevel: IPublicEnumPluginRegisterLevel; editorWindow: IPublicModelWindow; + commonUI: IPublicApiCommonUI; + isPluginRegisteredInWorkspace: false; constructor( options: IPluginContextOptions, diff --git a/packages/designer/src/plugin/plugin-types.ts b/packages/designer/src/plugin/plugin-types.ts index 6091170f02..d648067a36 100644 --- a/packages/designer/src/plugin/plugin-types.ts +++ b/packages/designer/src/plugin/plugin-types.ts @@ -18,6 +18,7 @@ import { IPublicTypePluginRegisterOptions, IPublicModelWindow, IPublicEnumPluginRegisterLevel, + IPublicApiCommonUI, } from '@alilc/lowcode-types'; import PluginContext from './plugin-context'; @@ -61,6 +62,7 @@ export interface ILowCodePluginContextPrivate { set editorWindow(window: IPublicModelWindow); set registerLevel(level: IPublicEnumPluginRegisterLevel); set isPluginRegisteredInWorkspace(flag: boolean); + set commonUI(commonUI: IPublicApiCommonUI); } export interface ILowCodePluginContextApiAssembler { assembleApis( diff --git a/packages/editor-core/src/widgets/title/index.tsx b/packages/editor-core/src/widgets/title/index.tsx index 88a15ab29b..7df2676f92 100644 --- a/packages/editor-core/src/widgets/title/index.tsx +++ b/packages/editor-core/src/widgets/title/index.tsx @@ -1,7 +1,7 @@ import { Component, isValidElement, ReactNode } from 'react'; import classNames from 'classnames'; import { createIcon, isI18nData, isTitleConfig } from '@alilc/lowcode-utils'; -import { IPublicTypeTitleContent, IPublicTypeI18nData, IPublicTypeTitleConfig } from '@alilc/lowcode-types'; +import { IPublicTypeI18nData, IPublicTypeTitleConfig, IPublicTypeTitleProps } from '@alilc/lowcode-types'; import { intl } from '../../intl'; import { Tip } from '../tip'; import './title.less'; @@ -36,13 +36,7 @@ import './title.less'; return fragments; } -export class Title extends Component<{ - title: IPublicTypeTitleContent; - className?: string; - onClick?: () => void; - match?: boolean; - keywords?: string; -}> { +export class Title extends Component<IPublicTypeTitleProps> { constructor(props: any) { super(props); this.handleClick = this.handleClick.bind(this); diff --git a/packages/engine/src/engine-core.ts b/packages/engine/src/engine-core.ts index 3ac4c32a75..9f29046fbe 100644 --- a/packages/engine/src/engine-core.ts +++ b/packages/engine/src/engine-core.ts @@ -51,6 +51,7 @@ import { Canvas, Workspace, Config, + CommonUI, } from '@alilc/lowcode-shell'; import { isPlainObject } from '@alilc/lowcode-utils'; import './modules/live-editing'; @@ -111,10 +112,12 @@ const innerSetters = new InnerSetters(); const setters = new Setters(innerSetters); const material = new Material(editor); +const commonUI = new CommonUI(); editor.set('project', project); editor.set('setters' as any, setters); editor.set('material', material); editor.set('innerHotkey', innerHotkey); +editor.set('commonUI' as any, commonUI); const config = new Config(engineConfig); const event = new Event(commonEvent, { prefix: 'common' }); const logger = new Logger({ level: 'warn', bizName: 'common' }); @@ -138,6 +141,7 @@ const pluginContextApiAssembler: ILowCodePluginContextApiAssembler = { context.plugins = plugins; context.logger = new Logger({ level: 'warn', bizName: `plugin:${pluginName}` }); context.workspace = workspace; + context.commonUI = commonUI; context.registerLevel = IPublicEnumPluginRegisterLevel.Default; context.isPluginRegisteredInWorkspace = false; }, @@ -161,6 +165,7 @@ export { common, workspace, canvas, + commonUI, }; // declare this is open-source version export const isOpenSource = true; diff --git a/packages/shell/src/api/commonUI.ts b/packages/shell/src/api/commonUI.ts new file mode 100644 index 0000000000..718b409707 --- /dev/null +++ b/packages/shell/src/api/commonUI.ts @@ -0,0 +1,43 @@ +import { IPublicApiCommonUI } from '@alilc/lowcode-types'; +import { + Tip as InnerTip, + Title as InnerTitle, + } from '@alilc/lowcode-editor-core'; +import { Balloon, Breadcrumb, Button, Card, Checkbox, DatePicker, Dialog, Dropdown, Form, Icon, Input, Loading, Message, Overlay, Pagination, Radio, Search, Select, SplitButton, Step, Switch, Tab, Table, Tree, TreeSelect, Upload, Divider } from '@alifd/next'; + +export class CommonUI implements IPublicApiCommonUI { + Balloon = Balloon; + Breadcrumb = Breadcrumb; + Button = Button; + Card = Card; + Checkbox = Checkbox; + DatePicker = DatePicker; + Dialog = Dialog; + Dropdown = Dropdown; + Form = Form; + Icon = Icon; + Input = Input; + Loading = Loading; + Message = Message; + Overlay = Overlay; + Pagination = Pagination; + Radio = Radio; + Search = Search; + Select = Select; + SplitButton = SplitButton; + Step = Step; + Switch = Switch; + Tab = Tab; + Table = Table; + Tree = Tree; + TreeSelect = TreeSelect; + Upload = Upload; + Divider = Divider; + + get Tip() { + return InnerTip; + } + get Title() { + return InnerTitle; + } +} diff --git a/packages/shell/src/api/index.ts b/packages/shell/src/api/index.ts index 4114926e19..3726020de0 100644 --- a/packages/shell/src/api/index.ts +++ b/packages/shell/src/api/index.ts @@ -10,4 +10,5 @@ export * from './simulator-host'; export * from './skeleton'; export * from './canvas'; export * from './workspace'; -export * from './config'; \ No newline at end of file +export * from './config'; +export * from './commonUI'; \ No newline at end of file diff --git a/packages/shell/src/index.ts b/packages/shell/src/index.ts index 6f79c78bcd..ce09ccaaa7 100644 --- a/packages/shell/src/index.ts +++ b/packages/shell/src/index.ts @@ -28,6 +28,7 @@ import { Workspace, SimulatorHost, Config, + CommonUI, } from './api'; export * from './symbols'; @@ -68,4 +69,5 @@ export { Config, SettingField, SkeletonItem, + CommonUI, }; diff --git a/packages/types/src/shell/api/commonUI.ts b/packages/types/src/shell/api/commonUI.ts new file mode 100644 index 0000000000..3d7bb57bf3 --- /dev/null +++ b/packages/types/src/shell/api/commonUI.ts @@ -0,0 +1,48 @@ +import { IPublicTypeTitleContent } from '../type'; +import { Balloon, Breadcrumb, Button, Card, Checkbox, DatePicker, Dialog, Dropdown, Form, Icon, Input, Loading, Message, Overlay, Pagination, Radio, Search, Select, SplitButton, Step, Switch, Tab, Table, Tree, TreeSelect, Upload, Divider } from '@alifd/next'; + +export interface IPublicApiCommonUI { + Balloon: typeof Balloon; + Breadcrumb: typeof Breadcrumb; + Button: typeof Button; + Card: typeof Card; + Checkbox: typeof Checkbox; + DatePicker: typeof DatePicker; + Dialog: typeof Dialog; + Dropdown: typeof Dropdown; + Form: typeof Form; + Icon: typeof Icon; + Input: typeof Input; + Loading: typeof Loading; + Message: typeof Message; + Overlay: typeof Overlay; + Pagination: typeof Pagination; + Radio: typeof Radio; + Search: typeof Search; + Select: typeof Select; + SplitButton: typeof SplitButton; + Step: typeof Step; + Switch: typeof Switch; + Tab: typeof Tab; + Table: typeof Table; + Tree: typeof Tree; + TreeSelect: typeof TreeSelect; + Upload: typeof Upload; + Divider: typeof Divider; + + /** + * Title 组件 + * @experimental unstable API, pay extra caution when trying to use this + */ + get Tip(): React.ComponentClass<{}>; + + /** + * Tip 组件 + * @experimental unstable API, pay extra caution when trying to use this + */ + get Title(): React.ComponentClass<{ + title: IPublicTypeTitleContent | undefined; + match?: boolean; + keywords?: string | null; + }>; +} \ No newline at end of file diff --git a/packages/types/src/shell/api/index.ts b/packages/types/src/shell/api/index.ts index 3d7d765598..79f1b0dc7c 100644 --- a/packages/types/src/shell/api/index.ts +++ b/packages/types/src/shell/api/index.ts @@ -10,3 +10,4 @@ export * from './plugins'; export * from './logger'; export * from './canvas'; export * from './workspace'; +export * from './commonUI'; diff --git a/packages/types/src/shell/model/plugin-context.ts b/packages/types/src/shell/model/plugin-context.ts index 35e7e38af3..45568424de 100644 --- a/packages/types/src/shell/model/plugin-context.ts +++ b/packages/types/src/shell/model/plugin-context.ts @@ -11,6 +11,7 @@ import { IPluginPreferenceMananger, IPublicApiPlugins, IPublicApiWorkspace, + IPublicApiCommonUI, } from '../api'; import { IPublicEnumPluginRegisterLevel } from '../enum'; import { IPublicModelEngineConfig, IPublicModelWindow } from './'; @@ -102,6 +103,12 @@ export interface IPublicModelPluginContext { */ get workspace(): IPublicApiWorkspace; + /** + * commonUI API + * @tutorial https://lowcode-engine.cn/site/docs/api/commonUI + */ + get commonUI(): IPublicApiCommonUI; + /** * 插件注册层级 * @since v1.1.7 diff --git a/packages/types/src/shell/type/tip-config.ts b/packages/types/src/shell/type/tip-config.ts index fa82ab96f1..f8b271c909 100644 --- a/packages/types/src/shell/type/tip-config.ts +++ b/packages/types/src/shell/type/tip-config.ts @@ -2,8 +2,20 @@ import { IPublicTypeI18nData } from '..'; import { ReactNode } from 'react'; export interface IPublicTypeTipConfig { + + /** + * className + */ className?: string; + + /** + * tip 的内容 + */ children?: IPublicTypeI18nData | ReactNode; theme?: string; + + /** + * tip 的方向 + */ direction?: 'top' | 'bottom' | 'left' | 'right'; } diff --git a/packages/types/src/shell/type/title-config.ts b/packages/types/src/shell/type/title-config.ts index 571502bc5e..f8de287599 100644 --- a/packages/types/src/shell/type/title-config.ts +++ b/packages/types/src/shell/type/title-config.ts @@ -1,26 +1,51 @@ import { ReactNode } from 'react'; -import { IPublicTypeI18nData, IPublicTypeIconType, TipContent } from './'; +import { IPublicTypeI18nData, IPublicTypeIconType, IPublicTypeTitleContent, TipContent } from './'; + +export interface IPublicTypeTitleProps { + + /** + * 标题内容 + */ + title: IPublicTypeTitleContent; + + /** + * className + */ + className?: string; + + /** + * 点击事件 + */ + onClick?: () => void; + match?: boolean; + keywords?: string; +} /** * 描述 props 的 setter title */ export interface IPublicTypeTitleConfig { + /** * 文字描述 */ label?: IPublicTypeI18nData | ReactNode; + /** * hover 后的展现内容 */ tip?: TipContent; + /** * 文档链接,暂未实现 */ docUrl?: string; + /** * 图标 */ icon?: IPublicTypeIconType; + /** * CSS 类 */ diff --git a/packages/workspace/src/context/base-context.ts b/packages/workspace/src/context/base-context.ts index 78f32079ff..e090d1e374 100644 --- a/packages/workspace/src/context/base-context.ts +++ b/packages/workspace/src/context/base-context.ts @@ -32,6 +32,7 @@ import { Workspace, Window, Canvas, + CommonUI, } from '@alilc/lowcode-shell'; import { IPluginPreferenceMananger, @@ -127,11 +128,13 @@ export class BasicContext implements IBasicContext { const logger = getLogger({ level: 'warn', bizName: 'common' }); const skeleton = new Skeleton(innerSkeleton, 'any', true); const canvas = new Canvas(editor, true); + const commonUI = new CommonUI(); editor.set('setters', setters); editor.set('project', project); editor.set('material', material); editor.set('hotkey', hotkey); editor.set('innerHotkey', innerHotkey); + editor.set('commonUI' as any, commonUI); this.innerSetters = innerSetters; this.innerSkeleton = innerSkeleton; this.skeleton = skeleton; @@ -166,6 +169,7 @@ export class BasicContext implements IBasicContext { context.plugins = plugins; context.logger = new Logger({ level: 'warn', bizName: `plugin:${pluginName}` }); context.canvas = canvas; + context.commonUI = commonUI; if (editorWindow) { context.editorWindow = new Window(editorWindow); } From e8aebb9aa35605c33aa69debe13a94e337507441 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Fri, 5 Jan 2024 03:44:36 +0000 Subject: [PATCH 156/219] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index ab6edf5cb5..4d6ef0a770 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.17", + "version": "1.2.18", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From ba53d6c69072b5d6225bd93b94eb596cd4e85d1e Mon Sep 17 00:00:00 2001 From: Arun <arun@arun.blog> Date: Thu, 4 Jan 2024 19:46:30 -0800 Subject: [PATCH 157/219] ci: Use GITHUB_OUTPUT envvar instead of set-output command --- .github/workflows/publish docs.yml | 2 +- .github/workflows/publish engine beta.yml | 2 +- .github/workflows/publish engine.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/publish docs.yml b/.github/workflows/publish docs.yml index e85d08f2a9..139b70239f 100644 --- a/.github/workflows/publish docs.yml +++ b/.github/workflows/publish docs.yml @@ -33,7 +33,7 @@ jobs: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Get version id: get_version - run: echo "::set-output name=version::$(node -p "require('./docs/package.json').version")" + run: echo "version=$(node -p "require('./docs/package.json').version")" >> $GITHUB_OUTPUT comment-pr: needs: publish-docs diff --git a/.github/workflows/publish engine beta.yml b/.github/workflows/publish engine beta.yml index 32c5b4c15b..ed4c374756 100644 --- a/.github/workflows/publish engine beta.yml +++ b/.github/workflows/publish engine beta.yml @@ -27,4 +27,4 @@ jobs: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Get version id: get_version - run: echo "::set-output name=version::$(node -p "require('./package.json').version")" + run: echo "version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT diff --git a/.github/workflows/publish engine.yml b/.github/workflows/publish engine.yml index 6825c66fca..ad4c3963b2 100644 --- a/.github/workflows/publish engine.yml +++ b/.github/workflows/publish engine.yml @@ -26,4 +26,4 @@ jobs: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Get version id: get_version - run: echo "::set-output name=version::$(node -p "require('./package.json').version")" + run: echo "version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT From 31a031ce4e4cc22c377aa9d1ce961c5df4cad58b Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 5 Jan 2024 15:53:58 +0800 Subject: [PATCH 158/219] feat: removed Rax packages, discontinuing support for Rax --- docs/docs/guide/appendix/npms.md | 2 - docs/docs/guide/appendix/repos.md | 16 +- docs/docs/guide/design/renderer.md | 1 - docs/docs/guide/expand/runtime/renderer.md | 1 - docs/docs/participate/index.md | 10 +- docs/docs/specs/lowcode-spec.md | 1 - package.json | 2 +- .../designer/src/builtin-simulator/host.ts | 37 +- .../src/designer/setting/setting-top-entry.ts | 15 +- packages/editor-core/src/config.ts | 2 +- packages/engine/README-zh_CN.md | 2 +- packages/engine/README.md | 2 +- packages/ignitor/build.json | 3 +- packages/rax-renderer/README.md | 49 -- packages/rax-renderer/build.json | 11 - packages/rax-renderer/demo/index.jsx | 35 - packages/rax-renderer/demo/miniapp/app.js | 1 - packages/rax-renderer/demo/miniapp/app.json | 6 - .../demo/miniapp/pages/index.acss | 0 .../demo/miniapp/pages/index.axml | 1 - .../rax-renderer/demo/miniapp/pages/index.js | 4 - .../demo/miniapp/pages/index.json | 6 - .../demo/wechat-miniprogram/app.js | 1 - .../demo/wechat-miniprogram/app.json | 6 - .../demo/wechat-miniprogram/pages/index.js | 4 - .../demo/wechat-miniprogram/pages/index.json | 6 - .../demo/wechat-miniprogram/pages/index.wxml | 1 - .../demo/wechat-miniprogram/pages/index.wxss | 0 packages/rax-renderer/package.json | 54 -- packages/rax-renderer/src/hoc/compFactory.tsx | 82 --- packages/rax-renderer/src/index.ts | 52 -- packages/rax-renderer/src/renderer/block.tsx | 25 - .../rax-renderer/src/renderer/component.tsx | 37 - packages/rax-renderer/src/renderer/page.tsx | 38 - packages/rax-renderer/tsconfig.json | 26 - packages/rax-simulator-renderer/.babelrc | 9 - .../rax-simulator-renderer/babel.config.js | 1 - packages/rax-simulator-renderer/build.json | 3 - .../rax-simulator-renderer/build.plugin.js | 5 - .../rax-simulator-renderer/build.umd.json | 38 - packages/rax-simulator-renderer/package.json | 55 -- .../UnusualComponent/index.less | 0 .../UnusualComponent/index.tsx | 34 - .../src/builtin-components/leaf.tsx | 251 ------- .../src/builtin-components/renderUtils.ts | 83 --- .../src/builtin-components/slot.tsx | 54 -- packages/rax-simulator-renderer/src/host.ts | 4 - .../rax-simulator-renderer/src/image.d.ts | 2 - packages/rax-simulator-renderer/src/index.ts | 7 - .../src/rax-use-router.js | 288 -------- .../src/renderer-view.tsx | 275 ------- .../rax-simulator-renderer/src/renderer.less | 125 ---- .../rax-simulator-renderer/src/renderer.ts | 690 ------------------ .../src/utils/create-defer.ts | 17 - .../src/utils/find-dom-nodes.ts | 18 - .../src/utils/get-client-rects.ts | 13 - .../src/utils/get-closest-node-instance.ts | 0 .../src/utils/get-device-view.ts | 23 - .../src/utils/is-dom-node.ts | 4 - .../src/utils/loader.ts | 114 --- .../src/utils/script.ts | 54 -- .../rax-simulator-renderer/src/utils/style.ts | 75 -- .../rax-simulator-renderer/src/utils/url.ts | 74 -- packages/renderer-core/src/adapter/index.ts | 15 +- .../tests/adapter/adapter.test.ts | 7 +- .../types/src/shell/type/engine-options.ts | 2 +- scripts/build.sh | 6 - scripts/sync.sh | 2 - 68 files changed, 36 insertions(+), 2851 deletions(-) delete mode 100644 packages/rax-renderer/README.md delete mode 100644 packages/rax-renderer/build.json delete mode 100644 packages/rax-renderer/demo/index.jsx delete mode 100644 packages/rax-renderer/demo/miniapp/app.js delete mode 100644 packages/rax-renderer/demo/miniapp/app.json delete mode 100644 packages/rax-renderer/demo/miniapp/pages/index.acss delete mode 100644 packages/rax-renderer/demo/miniapp/pages/index.axml delete mode 100644 packages/rax-renderer/demo/miniapp/pages/index.js delete mode 100644 packages/rax-renderer/demo/miniapp/pages/index.json delete mode 100644 packages/rax-renderer/demo/wechat-miniprogram/app.js delete mode 100644 packages/rax-renderer/demo/wechat-miniprogram/app.json delete mode 100644 packages/rax-renderer/demo/wechat-miniprogram/pages/index.js delete mode 100644 packages/rax-renderer/demo/wechat-miniprogram/pages/index.json delete mode 100644 packages/rax-renderer/demo/wechat-miniprogram/pages/index.wxml delete mode 100644 packages/rax-renderer/demo/wechat-miniprogram/pages/index.wxss delete mode 100644 packages/rax-renderer/package.json delete mode 100644 packages/rax-renderer/src/hoc/compFactory.tsx delete mode 100644 packages/rax-renderer/src/index.ts delete mode 100644 packages/rax-renderer/src/renderer/block.tsx delete mode 100644 packages/rax-renderer/src/renderer/component.tsx delete mode 100644 packages/rax-renderer/src/renderer/page.tsx delete mode 100644 packages/rax-renderer/tsconfig.json delete mode 100644 packages/rax-simulator-renderer/.babelrc delete mode 100644 packages/rax-simulator-renderer/babel.config.js delete mode 100644 packages/rax-simulator-renderer/build.json delete mode 100644 packages/rax-simulator-renderer/build.plugin.js delete mode 100644 packages/rax-simulator-renderer/build.umd.json delete mode 100644 packages/rax-simulator-renderer/package.json delete mode 100644 packages/rax-simulator-renderer/src/builtin-components/UnusualComponent/index.less delete mode 100644 packages/rax-simulator-renderer/src/builtin-components/UnusualComponent/index.tsx delete mode 100644 packages/rax-simulator-renderer/src/builtin-components/leaf.tsx delete mode 100644 packages/rax-simulator-renderer/src/builtin-components/renderUtils.ts delete mode 100644 packages/rax-simulator-renderer/src/builtin-components/slot.tsx delete mode 100644 packages/rax-simulator-renderer/src/host.ts delete mode 100644 packages/rax-simulator-renderer/src/image.d.ts delete mode 100644 packages/rax-simulator-renderer/src/index.ts delete mode 100644 packages/rax-simulator-renderer/src/rax-use-router.js delete mode 100644 packages/rax-simulator-renderer/src/renderer-view.tsx delete mode 100644 packages/rax-simulator-renderer/src/renderer.less delete mode 100644 packages/rax-simulator-renderer/src/renderer.ts delete mode 100644 packages/rax-simulator-renderer/src/utils/create-defer.ts delete mode 100644 packages/rax-simulator-renderer/src/utils/find-dom-nodes.ts delete mode 100644 packages/rax-simulator-renderer/src/utils/get-client-rects.ts delete mode 100644 packages/rax-simulator-renderer/src/utils/get-closest-node-instance.ts delete mode 100644 packages/rax-simulator-renderer/src/utils/get-device-view.ts delete mode 100644 packages/rax-simulator-renderer/src/utils/is-dom-node.ts delete mode 100644 packages/rax-simulator-renderer/src/utils/loader.ts delete mode 100644 packages/rax-simulator-renderer/src/utils/script.ts delete mode 100644 packages/rax-simulator-renderer/src/utils/style.ts delete mode 100644 packages/rax-simulator-renderer/src/utils/url.ts diff --git a/docs/docs/guide/appendix/npms.md b/docs/docs/guide/appendix/npms.md index 93980f32ce..b0292c2739 100644 --- a/docs/docs/guide/appendix/npms.md +++ b/docs/docs/guide/appendix/npms.md @@ -12,8 +12,6 @@ sidebar_position: 3 | @alilc/lowcode-engine | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/engine | | @alilc/lowcode-plugin-designer | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/plugin-designer | | @alilc/lowcode-plugin-outline-pane | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/plugin-outline-pane | -| @alilc/lowcode-rax-renderer | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/rax-renderer | -| @alilc/lowcode-rax-simulator-renderer | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/rax-simulator-renderer | | @alilc/lowcode-react-renderer | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/react-renderer | | @alilc/lowcode-react-simulator-renderer | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/react-simulator-renderer | | @alilc/lowcode-renderer-core | [https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) | packages/renderer-core | diff --git a/docs/docs/guide/appendix/repos.md b/docs/docs/guide/appendix/repos.md index 4fbfdc12cb..87852258d2 100644 --- a/docs/docs/guide/appendix/repos.md +++ b/docs/docs/guide/appendix/repos.md @@ -15,15 +15,13 @@ sidebar_position: 2 5. ignitor 6. plugin-designer 7. plugin-outline-pane -8. rax-renderer -9. rax-simulator-renderer -10. react-renderer -11. react-simulator-renderer -12. renderer-core -13. types -14. utils -15. material-parser -16. code-generator +8. react-renderer +9. react-simulator-renderer +10. renderer-core +11. types +12. utils +13. material-parser +14. code-generator ## 2. 引擎官方扩展包 包含了常用的设置器(setter)、跟 setter 绑定的插件等 diff --git a/docs/docs/guide/design/renderer.md b/docs/docs/guide/design/renderer.md index 4c3021b54e..4a8c43f329 100644 --- a/docs/docs/guide/design/renderer.md +++ b/docs/docs/guide/design/renderer.md @@ -11,7 +11,6 @@ sidebar_position: 4 ## npm 包与仓库信息 - React 框架渲染 npm 包:@alilc/lowcode-react-renderer -- Rax 框架渲染 npm 包:@alilc/lowcode-rax-renderer - 仓库:[https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) 下的 - packages/renderer-core - packages/react-renderer diff --git a/docs/docs/guide/expand/runtime/renderer.md b/docs/docs/guide/expand/runtime/renderer.md index 71eb755980..4e6d914bbf 100644 --- a/docs/docs/guide/expand/runtime/renderer.md +++ b/docs/docs/guide/expand/runtime/renderer.md @@ -40,7 +40,6 @@ ReactDOM.render(( ), document.getElementById('root')); ``` -- rax-renderer:npm 包替换为 @alilc/lowcode-rax-renderer #### ### 项目使用示例 > [设计器 demo](https://lowcode-engine.cn/demo/demo-general/index.html) diff --git a/docs/docs/participate/index.md b/docs/docs/participate/index.md index 4540fa640d..e09f2ddad2 100644 --- a/docs/docs/participate/index.md +++ b/docs/docs/participate/index.md @@ -47,15 +47,7 @@ npm install && npm run setup [ "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/react-simulator-renderer.css", "http://localhost:5555/css/ReactSimulatorRenderer.css" - ], - [ - "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/rax-simulator-renderer.js", - "http://localhost:5555/js/RaxSimulatorRenderer.js" - ], - [ - "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/rax-simulator-renderer.css", - "http://localhost:5555/css/RaxSimulatorRenderer.css" - ], + ] ] } ``` diff --git a/docs/docs/specs/lowcode-spec.md b/docs/docs/specs/lowcode-spec.md index 59ff85586c..c277214106 100644 --- a/docs/docs/specs/lowcode-spec.md +++ b/docs/docs/specs/lowcode-spec.md @@ -499,7 +499,6 @@ try { - 说明:组件即将从 DOM 中移除 - componentDidCatch(error, info) - 说明:组件捕获到异常 -- Rax:目前没有使用生命周期,使用 hooks 替代生命周期; 该对象由一系列 key-value 组成,key 为生命周期方法名,value 为 JSFunction 的描述,详见下方示例: diff --git a/package.json b/package.json index caabbeeb13..047b287b98 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "yarn": "^1.22.17", "rimraf": "^3.0.2", "@types/react-router": "5.1.18", - "@alilc/build-plugin-lce": "^0.0.3", + "@alilc/build-plugin-lce": "^0.0.4", "babel-jest": "^26.5.2", "@alilc/lowcode-test-mate": "^1.0.1" }, diff --git a/packages/designer/src/builtin-simulator/host.ts b/packages/designer/src/builtin-simulator/host.ts index eb855e4498..6efe6a68b5 100644 --- a/packages/designer/src/builtin-simulator/host.ts +++ b/packages/designer/src/builtin-simulator/host.ts @@ -39,6 +39,7 @@ import { isDragAnyObject, isDragNodeObject, isLocationData, + Logger, } from '@alilc/lowcode-utils'; import { isShaken, @@ -72,6 +73,8 @@ import { IScroller } from '../designer/scroller'; import { isElementNode, isDOMNodeVisible } from '../utils/misc'; import { debounce } from 'lodash'; +const logger = new Logger({ level: 'warn', bizName: 'designer' }); + export type LibraryItem = IPublicTypePackage & { package: string; library: string; @@ -122,21 +125,6 @@ const defaultSimulatorUrl = (() => { return urls; })(); -const defaultRaxSimulatorUrl = (() => { - const publicPath = getPublicPath(); - let urls; - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const [_, prefix = '', dev] = /^(.+?)(\/js)?\/?$/.exec(publicPath) || []; - if (dev) { - urls = [`${prefix}/css/rax-simulator-renderer.css`, `${prefix}/js/rax-simulator-renderer.js`]; - } else if (process.env.NODE_ENV === 'production') { - urls = [`${prefix}/rax-simulator-renderer.css`, `${prefix}/rax-simulator-renderer.js`]; - } else { - urls = [`${prefix}/rax-simulator-renderer.css`, `${prefix}/rax-simulator-renderer.js`]; - } - return urls; -})(); - const defaultEnvironment = [ // https://g.alicdn.com/mylib/??react/16.11.0/umd/react.production.min.js,react-dom/16.8.6/umd/react-dom.production.min.js,prop-types/15.7.2/prop-types.min.js assetItem( @@ -151,17 +139,6 @@ const defaultEnvironment = [ ), ]; -const defaultRaxEnvironment = [ - assetItem( - AssetType.JSText, - 'window.Rax=parent.Rax;window.React=parent.React;window.ReactDOM=parent.ReactDOM;window.VisualEngineUtils=parent.VisualEngineUtils;window.VisualEngine=parent.VisualEngine', - ), - assetItem( - AssetType.JSText, - 'window.PropTypes=parent.PropTypes;React.PropTypes=parent.PropTypes; window.__REACT_DEVTOOLS_GLOBAL_HOOK__ = window.parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;', - ), -]; - export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProps> { readonly isSimulator = true; @@ -467,11 +444,15 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp const libraryAsset: AssetList = this.buildLibrary(); + if (this.renderEnv === 'rax') { + logger.error('After LowcodeEngine v1.3.0, Rax is no longer supported.'); + } + const vendors = [ // required & use once assetBundle( this.get('environment') || - (this.renderEnv === 'rax' ? defaultRaxEnvironment : defaultEnvironment), + defaultEnvironment, AssetLevel.Environment, ), // required & use once @@ -484,7 +465,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp // required & use once assetBundle( this.get('simulatorUrl') || - (this.renderEnv === 'rax' ? defaultRaxSimulatorUrl : defaultSimulatorUrl), + defaultSimulatorUrl, AssetLevel.Runtime, ), ]; diff --git a/packages/designer/src/designer/setting/setting-top-entry.ts b/packages/designer/src/designer/setting/setting-top-entry.ts index f89ff8a62b..85be74b7f6 100644 --- a/packages/designer/src/designer/setting/setting-top-entry.ts +++ b/packages/designer/src/designer/setting/setting-top-entry.ts @@ -1,4 +1,4 @@ -import { IPublicTypeCustomView, IPublicModelEditor, IPublicModelSettingTopEntry } from '@alilc/lowcode-types'; +import { IPublicTypeCustomView, IPublicModelEditor, IPublicModelSettingTopEntry, IPublicApiSetters } from '@alilc/lowcode-types'; import { isCustomView } from '@alilc/lowcode-utils'; import { computed, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core'; import { ISettingEntry } from './setting-entry-type'; @@ -6,7 +6,6 @@ import { ISettingField, SettingField } from './setting-field'; import { INode } from '../../document'; import type { IComponentMeta } from '../../component-meta'; import { IDesigner } from '../designer'; -import { Setters } from '@alilc/lowcode-shell'; function generateSessionId(nodes: INode[]) { return nodes @@ -19,18 +18,18 @@ export interface ISettingTopEntry extends ISettingEntry, IPublicModelSettingTopE INode, ISettingField > { - purge(): void; - - items: Array<ISettingField | IPublicTypeCustomView>; - readonly top: ISettingTopEntry; readonly parent: ISettingTopEntry; readonly path: never[]; + items: Array<ISettingField | IPublicTypeCustomView>; + componentMeta: IComponentMeta | null; + purge(): void; + getExtraPropValue(propName: string): void; setExtraPropValue(propName: string, value: any): void; @@ -92,7 +91,7 @@ export class SettingTopEntry implements ISettingTopEntry { readonly designer: IDesigner | undefined; - readonly setters: Setters; + readonly setters: IPublicApiSetters; disposeFunctions: any[] = []; @@ -103,7 +102,7 @@ export class SettingTopEntry implements ISettingTopEntry { this.id = generateSessionId(nodes); this.first = nodes[0]; this.designer = this.first.document?.designer; - this.setters = editor.get('setters') as Setters; + this.setters = editor.get('setters') as IPublicApiSetters; // setups this.setupComponentMeta(); diff --git a/packages/editor-core/src/config.ts b/packages/editor-core/src/config.ts index 1c73347b74..a5da74742d 100644 --- a/packages/editor-core/src/config.ts +++ b/packages/editor-core/src/config.ts @@ -44,7 +44,7 @@ const VALID_ENGINE_OPTIONS = { }, renderEnv: { type: 'string', - enum: ['react', 'rax', 'any string value'], + enum: ['react', 'any string value'], default: 'react', description: '渲染器类型', }, diff --git a/packages/engine/README-zh_CN.md b/packages/engine/README-zh_CN.md index c99e98cf6c..5442aa58bd 100644 --- a/packages/engine/README-zh_CN.md +++ b/packages/engine/README-zh_CN.md @@ -126,7 +126,7 @@ https://cdn.jsdelivr.net/npm/@alilc/lowcode-react-simulator-renderer@1.0.18/dist ``` #### 方式 5:使用自有 cdn -将源码中 packages/engine/dist 和 packages/(react|rax)-simulator-renderer/dist 下的文件传至你的 cdn 提供商 +将源码中 packages/engine/dist 和 packages/react-simulator-renderer/dist 下的文件传至你的 cdn 提供商 ## 🔗 相关链接 diff --git a/packages/engine/README.md b/packages/engine/README.md index 52bce86163..ae4e7fd43b 100644 --- a/packages/engine/README.md +++ b/packages/engine/README.md @@ -126,7 +126,7 @@ https://cdn.jsdelivr.net/npm/@alilc/lowcode-react-simulator-renderer@1.0.18/dist ``` #### Method 5: Use your own cdn -Pass the files under packages/engine/dist and packages/(react|rax)-simulator-renderer/dist in the source code to your cdn provider +Pass the files under packages/engine/dist and packages/react-simulator-renderer/dist in the source code to your cdn provider ## 🔗 Related Links diff --git a/packages/ignitor/build.json b/packages/ignitor/build.json index 218373247c..f1956cf527 100644 --- a/packages/ignitor/build.json +++ b/packages/ignitor/build.json @@ -1,8 +1,7 @@ { "entry": { "AliLowCodeEngine": "../engine/src/index.ts", - "ReactSimulatorRenderer": "../react-simulator-renderer/src/index.ts", - "RaxSimulatorRenderer": "../rax-simulator-renderer/src/index.ts" + "ReactSimulatorRenderer": "../react-simulator-renderer/src/index.ts" }, "vendor": false, "devServer": { diff --git a/packages/rax-renderer/README.md b/packages/rax-renderer/README.md deleted file mode 100644 index 7b430de630..0000000000 --- a/packages/rax-renderer/README.md +++ /dev/null @@ -1,49 +0,0 @@ -# Rax Renderer - -Rax 渲染模块。 - -## 安装 - -``` -$ npm install @alilc/lowcode-rax-renderer --save -``` - -## 使用 - -```js -import { createElement, render } from 'rax'; -import DriverUniversal from 'driver-universal'; -import RaxRenderer from '@ali/lowcode-rax-renderer'; - -const components = { - View, - Text -}; - -const schema = { - componentName: 'Page', - fileName: 'home', - children: [ - { - componentName: 'View', - children: [ - { - componentName: 'Text', - props: { - type: 'primary' - }, - children: ['Welcome to Your Rax App'] - } - ] - } - ] -}; - -render( - <RaxRenderer - schema={schema} - components={components} - />, - document.getElementById('root'), { driver: DriverUniversal } -); -``` diff --git a/packages/rax-renderer/build.json b/packages/rax-renderer/build.json deleted file mode 100644 index 3edf143801..0000000000 --- a/packages/rax-renderer/build.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "plugins": [ - [ - "build-plugin-rax-component", - { - "type": "rax", - "targets": ["web"] - } - ] - ] -} diff --git a/packages/rax-renderer/demo/index.jsx b/packages/rax-renderer/demo/index.jsx deleted file mode 100644 index cfcae2a201..0000000000 --- a/packages/rax-renderer/demo/index.jsx +++ /dev/null @@ -1,35 +0,0 @@ -import { createElement, render } from 'rax'; -import DriverUniversal from 'driver-universal'; -import View from 'rax-view'; -import Text from 'rax-text'; -import { Engine } from '../src/index'; - -const components = { - View, - Text, -}; - -const schema = { - componentName: 'Page', - fileName: 'home', - props: {}, - children: [ - { - componentName: 'View', - props: {}, - children: [ - { - componentName: 'Text', - props: { - type: 'primary', - }, - children: ['Welcome to Your Rax App!'], - }, - ], - }, - ], -}; - -render(<Engine schema={schema} components={components} />, document.getElementById('root'), { - driver: DriverUniversal, -}); diff --git a/packages/rax-renderer/demo/miniapp/app.js b/packages/rax-renderer/demo/miniapp/app.js deleted file mode 100644 index 3482935519..0000000000 --- a/packages/rax-renderer/demo/miniapp/app.js +++ /dev/null @@ -1 +0,0 @@ -App({}); diff --git a/packages/rax-renderer/demo/miniapp/app.json b/packages/rax-renderer/demo/miniapp/app.json deleted file mode 100644 index 94127c774c..0000000000 --- a/packages/rax-renderer/demo/miniapp/app.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "pages": ["pages/index"], - "window": { - "defaultTitle": "demo" - } -} diff --git a/packages/rax-renderer/demo/miniapp/pages/index.acss b/packages/rax-renderer/demo/miniapp/pages/index.acss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/rax-renderer/demo/miniapp/pages/index.axml b/packages/rax-renderer/demo/miniapp/pages/index.axml deleted file mode 100644 index 41b536b4ce..0000000000 --- a/packages/rax-renderer/demo/miniapp/pages/index.axml +++ /dev/null @@ -1 +0,0 @@ -<my-component></my-component> diff --git a/packages/rax-renderer/demo/miniapp/pages/index.js b/packages/rax-renderer/demo/miniapp/pages/index.js deleted file mode 100644 index 687d87e197..0000000000 --- a/packages/rax-renderer/demo/miniapp/pages/index.js +++ /dev/null @@ -1,4 +0,0 @@ -Page({ - onLoad() {}, - onShow() {}, -}); diff --git a/packages/rax-renderer/demo/miniapp/pages/index.json b/packages/rax-renderer/demo/miniapp/pages/index.json deleted file mode 100644 index 89b15c54ca..0000000000 --- a/packages/rax-renderer/demo/miniapp/pages/index.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "defaultTitle": "Miniapp Rax Text demo", - "usingComponents": { - "my-component": "../components/Target/index" - } -} diff --git a/packages/rax-renderer/demo/wechat-miniprogram/app.js b/packages/rax-renderer/demo/wechat-miniprogram/app.js deleted file mode 100644 index 3482935519..0000000000 --- a/packages/rax-renderer/demo/wechat-miniprogram/app.js +++ /dev/null @@ -1 +0,0 @@ -App({}); diff --git a/packages/rax-renderer/demo/wechat-miniprogram/app.json b/packages/rax-renderer/demo/wechat-miniprogram/app.json deleted file mode 100644 index be00ced601..0000000000 --- a/packages/rax-renderer/demo/wechat-miniprogram/app.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "pages": ["pages/index"], - "window": { - "title": "demo" - } -} diff --git a/packages/rax-renderer/demo/wechat-miniprogram/pages/index.js b/packages/rax-renderer/demo/wechat-miniprogram/pages/index.js deleted file mode 100644 index 687d87e197..0000000000 --- a/packages/rax-renderer/demo/wechat-miniprogram/pages/index.js +++ /dev/null @@ -1,4 +0,0 @@ -Page({ - onLoad() {}, - onShow() {}, -}); diff --git a/packages/rax-renderer/demo/wechat-miniprogram/pages/index.json b/packages/rax-renderer/demo/wechat-miniprogram/pages/index.json deleted file mode 100644 index 9448c84eaf..0000000000 --- a/packages/rax-renderer/demo/wechat-miniprogram/pages/index.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "title": "Wechat MiniProgram Rax Text demo", - "usingComponents": { - "my-component": "../components/Target/index" - } -} diff --git a/packages/rax-renderer/demo/wechat-miniprogram/pages/index.wxml b/packages/rax-renderer/demo/wechat-miniprogram/pages/index.wxml deleted file mode 100644 index 41b536b4ce..0000000000 --- a/packages/rax-renderer/demo/wechat-miniprogram/pages/index.wxml +++ /dev/null @@ -1 +0,0 @@ -<my-component></my-component> diff --git a/packages/rax-renderer/demo/wechat-miniprogram/pages/index.wxss b/packages/rax-renderer/demo/wechat-miniprogram/pages/index.wxss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/rax-renderer/package.json b/packages/rax-renderer/package.json deleted file mode 100644 index 8173d6e4e1..0000000000 --- a/packages/rax-renderer/package.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "name": "@alilc/lowcode-rax-renderer", - "version": "1.2.5", - "description": "Rax renderer for Ali lowCode engine", - "main": "lib/index.js", - "module": "es/index.js", - "miniappConfig": { - "main": "lib/miniapp/index", - "main:wechat": "lib/wechat-miniprogram/index" - }, - "files": [ - "dist", - "es", - "lib" - ], - "keywords": [ - "low-code", - "lowcode", - "Rax" - ], - "engines": { - "npm": ">=3.0.0" - }, - "peerDependencies": { - "prop-types": "^15.7.2", - "rax": "^1.1.0" - }, - "scripts": { - "start": "build-scripts start", - "build": "build-scripts build" - }, - "dependencies": { - "@alilc/lowcode-renderer-core": "1.2.5", - "@alilc/lowcode-utils": "1.2.5", - "rax-find-dom-node": "^1.0.1" - }, - "devDependencies": { - "@alib/build-scripts": "^0.1.0", - "build-plugin-rax-component": "^0.2.11", - "driver-universal": "^3.1.3" - }, - "publishConfig": { - "access": "public", - "registry": "https://registry.npmjs.org/" - }, - "repository": { - "type": "http", - "url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/rax-renderer" - }, - "license": "MIT", - "homepage": "https://github.com/alibaba/lowcode-engine/#readme", - "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6", - "bugs": "https://github.com/alibaba/lowcode-engine/issues" -} diff --git a/packages/rax-renderer/src/hoc/compFactory.tsx b/packages/rax-renderer/src/hoc/compFactory.tsx deleted file mode 100644 index 1c821ab6d9..0000000000 --- a/packages/rax-renderer/src/hoc/compFactory.tsx +++ /dev/null @@ -1,82 +0,0 @@ -// @ts-nocheck - -import { Component, forwardRef } from 'rax'; -import PropTypes from 'prop-types'; -import { AppHelper } from '@alilc/lowcode-utils'; -import { utils, contextFactory } from '@alilc/lowcode-renderer-core'; -import componentRendererFactory from '../renderer/component'; -import blockRendererFactory from '../renderer/block'; - -const { forEach, isFileSchema } = utils; - -export default function compFactory(schema, components = {}, componentsMap = {}, config = {}) { - // 自定义组件需要有自己独立的appHelper - const appHelper = new AppHelper(config); - const CompRenderer = componentRendererFactory(); - const BlockRenderer = blockRendererFactory(); - const AppContext = contextFactory(); - - class LNCompView extends Component { - static displayName = 'LceCompFactory'; - - static version = config.version || '0.0.0'; - - static contextType = AppContext; - - static propTypes = { - forwardedRef: PropTypes.func, - }; - - render() { - if (!schema || schema.componentName !== 'Component' || !isFileSchema(schema)) { - console.warn('自定义组件模型结构异常!'); - return null; - } - const { forwardedRef, ...otherProps } = this.props; - // 低代码组件透传应用上下文 - const ctx = ['utils', 'constants', 'history', 'location', 'match']; - ctx.forEach(key => { - if (!appHelper[key] && this.context?.appHelper && this.context?.appHelper[key]) { - appHelper.set(key, this.context.appHelper[key]); - } - }); - // 支持通过context透传国际化配置 - const localeProps = {}; - const { locale, messages } = this.context; - if (locale && messages && messages[schema.fileName]) { - localeProps.locale = locale; - localeProps.messages = messages[schema.fileName]; - } - const props = { - ...schema.defaultProps, - ...localeProps, - ...otherProps, - __schema: schema, - ref: forwardedRef, - }; - - return ( - <AppContext.Consumer> - {context => { - this.context = context; - return ( - <CompRenderer - {...props} - __appHelper={appHelper} - __components={{ ...components, Component: CompRenderer, Block: BlockRenderer }} - __componentsMap={componentsMap} - /> - ); - }} - </AppContext.Consumer> - ); - } - } - - const ResComp = forwardRef((props, ref) => <LNCompView {...props} forwardedRef={ref} />); - forEach(schema.static, (val, key) => { - ResComp[key] = val; - }); - ResComp.version = config.version || '0.0.0'; - return ResComp; -} diff --git a/packages/rax-renderer/src/index.ts b/packages/rax-renderer/src/index.ts deleted file mode 100644 index 1947aa5aec..0000000000 --- a/packages/rax-renderer/src/index.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { Component, PureComponent, createElement, createContext, forwardRef } from 'rax'; -import findDOMNode from 'rax-find-dom-node'; -import { - adapter, - addonRendererFactory, - tempRendererFactory, - rendererFactory, -} from '@alilc/lowcode-renderer-core'; -import pageRendererFactory from './renderer/page'; -import componentRendererFactory from './renderer/component'; -import blockRendererFactory from './renderer/block'; -import CompFactory from './hoc/compFactory'; - -adapter.setRuntime({ - Component, - PureComponent, - createContext, - createElement, - forwardRef, - findDOMNode, -}); - -adapter.setRenderers({ - PageRenderer: pageRendererFactory(), - ComponentRenderer: componentRendererFactory(), - BlockRenderer: blockRendererFactory(), - AddonRenderer: addonRendererFactory(), - TempRenderer: tempRendererFactory(), -}); - -function factory() { - const Renderer = rendererFactory(); - return class extends Renderer { - constructor(props: any, context: any) { - super(props, context); - } - - isValidComponent(obj: any) { - return obj?.prototype?.setState || obj?.prototype instanceof Component; - } - }; -} - -const RaxRenderer: any = factory(); -const Engine: any = RaxRenderer; - -export { - Engine, - CompFactory, -}; - -export default RaxRenderer; diff --git a/packages/rax-renderer/src/renderer/block.tsx b/packages/rax-renderer/src/renderer/block.tsx deleted file mode 100644 index 8fa4a27316..0000000000 --- a/packages/rax-renderer/src/renderer/block.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { blockRendererFactory, types } from '@alilc/lowcode-renderer-core'; - -const raxBlockRendererFactory: () => any = () => { - const OriginBlock = blockRendererFactory(); - return class BlockRenderer extends OriginBlock { - render() { - // @ts-ignore - const that: types.IRenderer = this; - const { __schema, __components } = that.props; - if (that.__checkSchema(__schema)) { - return '区块 schema 结构异常!'; - } - that.__debug(`render - ${__schema.fileName}`); - - const children = ((context) => { - that.context = context; - that.__generateCtx({}); - that.__render(); - return that.__renderComp((__components as any)?.Block, { blockContext: that }); - }); - return that.__renderContextConsumer(children); - } - }; -}; -export default raxBlockRendererFactory; diff --git a/packages/rax-renderer/src/renderer/component.tsx b/packages/rax-renderer/src/renderer/component.tsx deleted file mode 100644 index 9943b3c2f1..0000000000 --- a/packages/rax-renderer/src/renderer/component.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { componentRendererFactory, types } from '@alilc/lowcode-renderer-core'; - -const raxComponentRendererFactory: () => any = () => { - const OriginComponent = componentRendererFactory(); - return class ComponentRenderer extends OriginComponent { - render() { - // @ts-ignore - const that: types.IRenderer = this; - const { __schema, __components } = that.props; - if (that.__checkSchema(__schema)) { - return '自定义组件 schema 结构异常!'; - } - that.__debug(`render - ${__schema.fileName}`); - - const { noContainer } = that.__parseData(__schema.props); - - const children = ((context) => { - that.context = context; - that.__generateCtx({ component: that }); - that.__render(); - // 传 null,使用内置的 div 来渲染,解决在页面中渲染 vc-component 报错的问题 - return that.__renderComp(null, { - compContext: that, - blockContext: that, - }); - }); - const content = that.__renderContextConsumer(children); - - if (noContainer) { - return content; - } - - return that.__renderContent(content); - } - }; -}; -export default raxComponentRendererFactory; diff --git a/packages/rax-renderer/src/renderer/page.tsx b/packages/rax-renderer/src/renderer/page.tsx deleted file mode 100644 index f6ebd3f7cf..0000000000 --- a/packages/rax-renderer/src/renderer/page.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { pageRendererFactory, types } from '@alilc/lowcode-renderer-core'; - -const raxPageRendererFactory: () => any = () => { - const OriginPage = pageRendererFactory(); - return class PageRenderer extends OriginPage { - async componentDidUpdate() { - // @ts-ignore - super.componentDidUpdate(...arguments); - } - - render() { - // @ts-ignore - const that: types.IRenderer = this; - const { __schema, __components } = that.props; - if (that.__checkSchema(__schema)) { - return '页面 schema 结构异常!'; - } - that.__debug(`render - ${__schema?.fileName}`); - - const { Page } = __components as any; - if (Page) { - const children = ((context) => { - that.context = context; - that.__render(); - return that.__renderComp(Page, { pageContext: that }); - }); - return that.__renderContextConsumer(children); - } - - return that.__renderContent(that.__renderContextConsumer((context) => { - that.context = context; - return that.__renderContextProvider({ pageContext: that }); - })); - } - }; -}; - -export default raxPageRendererFactory; \ No newline at end of file diff --git a/packages/rax-renderer/tsconfig.json b/packages/rax-renderer/tsconfig.json deleted file mode 100644 index 7e264d1f05..0000000000 --- a/packages/rax-renderer/tsconfig.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "lib": ["es2015", "dom"], - "target": "esnext", - "module": "esnext", - "moduleResolution": "node", - "strict": false, - "strictPropertyInitialization": false, - "allowSyntheticDefaultImports": true, - "esModuleInterop": true, - "jsx": "react", - "jsxFactory": "createElement", - "importHelpers": true, - "experimentalDecorators": true, - "emitDecoratorMetadata": true, - "sourceMap": true, - "forceConsistentCasingInFileNames": true, - "resolveJsonModule": true, - "skipLibCheck": true, - "outDir": "lib" - }, - "exclude": ["test", "lib", "es", "node_modules"], - "include": [ - "src" - ] -} diff --git a/packages/rax-simulator-renderer/.babelrc b/packages/rax-simulator-renderer/.babelrc deleted file mode 100644 index e0e2e5f343..0000000000 --- a/packages/rax-simulator-renderer/.babelrc +++ /dev/null @@ -1,9 +0,0 @@ -{ - "plugins": [ - ["@babel/plugin-transform-react-jsx", { - "pragma": "createElement", // default pragma is React.createElement - "pragmaFrag": "createFragment", // default is React.Fragment - "throwIfNamespace": false // defaults to true - }] - ] -} diff --git a/packages/rax-simulator-renderer/babel.config.js b/packages/rax-simulator-renderer/babel.config.js deleted file mode 100644 index c5986f2bc0..0000000000 --- a/packages/rax-simulator-renderer/babel.config.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('../../babel.config'); \ No newline at end of file diff --git a/packages/rax-simulator-renderer/build.json b/packages/rax-simulator-renderer/build.json deleted file mode 100644 index e7ae1dcf7a..0000000000 --- a/packages/rax-simulator-renderer/build.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "plugins": ["@alilc/build-plugin-lce", "./build.plugin.js"] -} diff --git a/packages/rax-simulator-renderer/build.plugin.js b/packages/rax-simulator-renderer/build.plugin.js deleted file mode 100644 index d613f1f56a..0000000000 --- a/packages/rax-simulator-renderer/build.plugin.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = ({ onGetWebpackConfig }) => { - onGetWebpackConfig((config) => { - config.performance.hints(false); - }); -}; diff --git a/packages/rax-simulator-renderer/build.umd.json b/packages/rax-simulator-renderer/build.umd.json deleted file mode 100644 index 833c92b246..0000000000 --- a/packages/rax-simulator-renderer/build.umd.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "entry": { - "rax-simulator-renderer": "src/index" - }, - "sourceMap": true, - "library": "___RaxSimulatorRenderer___", - "libraryTarget": "umd", - "externals": { - "react": "var window.React", - "react-dom": "var window.ReactDOM", - "prop-types": "var window.PropTypes", - "@alifd/next": "var Next", - "@alilc/lowcode-engine-ext": "var window.AliLowCodeEngineExt", - "rax": "var window.Rax", - "moment": "var moment", - "lodash": "var _" - }, - "polyfill": false, - "outputDir": "dist", - "vendor": false, - "ignoreHtmlTemplate": true, - "plugins": [ - "build-plugin-react-app", - [ - "build-plugin-fusion", - { - "externalNext": "umd" - } - ], - [ - "build-plugin-moment-locales", - { - "locales": ["zh-cn"] - } - ], - "./build.plugin.js" - ] -} diff --git a/packages/rax-simulator-renderer/package.json b/packages/rax-simulator-renderer/package.json deleted file mode 100644 index f264380ec1..0000000000 --- a/packages/rax-simulator-renderer/package.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "name": "@alilc/lowcode-rax-simulator-renderer", - "version": "1.2.5", - "description": "rax simulator renderer for alibaba lowcode designer", - "main": "lib/index.js", - "module": "es/index.js", - "license": "MIT", - "files": [ - "dist" - ], - "scripts": { - "build": "NODE_OPTIONS=--max_old_space_size=8192 build-scripts build", - "build:umd": "build-scripts build --config build.umd.json" - }, - "dependencies": { - "@alilc/lowcode-designer": "1.2.5", - "@alilc/lowcode-rax-renderer": "1.2.5", - "@alilc/lowcode-types": "1.2.5", - "@alilc/lowcode-utils": "1.2.5", - "classnames": "^2.2.6", - "driver-universal": "^3.1.3", - "history": "^5.0.0", - "lodash": "^4.17.19", - "mobx": "^6.3.0", - "mobx-react": "^7.2.0", - "path-to-regexp": "3.2.0", - "rax-find-dom-node": "^1.0.0", - "react": "^16", - "react-dom": "^16.7.0" - }, - "devDependencies": { - "@alib/build-scripts": "^0.1.18", - "@babel/plugin-transform-react-jsx": "^7.10.4", - "@types/classnames": "^2.2.7", - "@types/node": "^13.7.1", - "@types/rax": "^1.0.0", - "@types/react": "^16", - "@types/react-dom": "^16", - "build-plugin-rax-component": "^0.2.11" - }, - "peerDependencies": { - "rax": "^1.1.0" - }, - "publishConfig": { - "access": "public", - "registry": "https://registry.npmjs.org/" - }, - "repository": { - "type": "http", - "url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/rax-simulator-renderer" - }, - "homepage": "https://github.com/alibaba/lowcode-engine/#readme", - "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6", - "bugs": "https://github.com/alibaba/lowcode-engine/issues" -} diff --git a/packages/rax-simulator-renderer/src/builtin-components/UnusualComponent/index.less b/packages/rax-simulator-renderer/src/builtin-components/UnusualComponent/index.less deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/rax-simulator-renderer/src/builtin-components/UnusualComponent/index.tsx b/packages/rax-simulator-renderer/src/builtin-components/UnusualComponent/index.tsx deleted file mode 100644 index 6608942c4b..0000000000 --- a/packages/rax-simulator-renderer/src/builtin-components/UnusualComponent/index.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { Component } from 'rax'; -import lg from '@ali/vu-logger'; - -import './index.less'; - -export class UnknownComponent extends Component { - props: { - _componentName: string; - }; - - render() { - lg.log('ERROR_NO_COMPONENT_VIEW'); - lg.error('Error component information:', this.props); - return <div className="engine-unknow-component">组件 {this.props._componentName} 无视图,请打开控制台排查</div>; - } -} - -export class FaultComponent extends Component { - props: { - _componentName: string; - }; - - render() { - return <div className="engine-fault-component">组件 {this.props._componentName} 渲染错误,请打开控制台排查</div>; - } -} - -export class HiddenComponent extends Component { - render() { - return <div className="engine-hidden-component">在本页面不显示</div>; - } -} - -export default { FaultComponent, HiddenComponent, UnknownComponent }; diff --git a/packages/rax-simulator-renderer/src/builtin-components/leaf.tsx b/packages/rax-simulator-renderer/src/builtin-components/leaf.tsx deleted file mode 100644 index 5276b0018d..0000000000 --- a/packages/rax-simulator-renderer/src/builtin-components/leaf.tsx +++ /dev/null @@ -1,251 +0,0 @@ -import { Component } from 'rax'; - -class Leaf extends Component { - static displayName = 'Leaf'; - - static componentMetadata = { - componentName: 'Leaf', - configure: { - props: [{ - name: 'children', - setter: 'StringSetter', - }], - // events/className/style/general/directives - supports: false, - }, - }; - - render() { - const { children } = this.props; - return children; - } -} - -export default Leaf; - -// import { Component, createElement } from 'rax'; -// import findDOMNode from 'rax-find-dom-node'; -// import { each, get, omit } from 'lodash'; -// import { getView, setNativeNode, createNodeStyleSheet } from '../renderUtils'; - -// import { FaultComponent, HiddenComponent, UnknownComponent } from '../UnusualComponent'; - -// export interface ILeaf { -// leaf: any; -// } -// export default class Leaf extends Component<ILeaf, {}> { -// static displayName = 'Leaf'; - -// state = { -// hasError: false, -// }; - -// willDetach: any[]; - -// styleSheet: any; - -// context: any; -// refs: any; - -// componentWillMount() { -// const { leaf } = this.props; -// this.willDetach = [ -// leaf.onPropsChange(() => { -// // 强制刷新 -// this.setState(this.state); -// }), -// leaf.onChildrenChange(() => { -// // 强制刷新 -// this.setState(this.state); -// }), -// leaf.onStatusChange((status: { dropping: boolean }, field: string) => { -// // console.log({...status}, field) -// if (status.dropping !== false) { -// // 当 dropping 为 Insertion 对象时,强制渲染会出错,原因待查 -// return; -// } -// if (field === 'dragging' || field === 'dropping' || field === 'pseudo' || field === 'visibility') { -// // 强制刷新 -// this.setState(this.state); -// } -// }), -// ]; - -// /** -// * while props replaced -// * bind the new event on it -// */ -// leaf.onPropsReplace(() => { -// this.willDetach[0](); -// this.willDetach[0] = leaf.onPropsChange(() => { -// // 强制刷新 -// this.setState(this.state); -// }); -// }); -// } - -// componentDidMount() { -// this.modifyDOM(); -// } - -// shouldComponentUpdate() { -// // forceUpdate 的替代方案 -// return true; -// // const pageCanRefresh = this.leaf.getPage().canRefresh(); -// // if (pageCanRefresh) { -// // return pageCanRefresh; -// // } -// // const getExtProps = obj => { -// // const { leaf, ...props } = obj; -// // return props; -// // }; -// // return !shallowEqual(getExtProps(this.props), getExtProps(nextProps)); -// } - -// componentDidUpdate() { -// this.modifyDOM(); -// } - -// componentWillUnmount() { -// if (this.willDetach) { -// this.willDetach.forEach((off) => off()); -// } -// setNativeNode(this.props.leaf, null); -// } - -// componentDidCatch() { -// this.setState({ hasError: true }, () => { -// console.log('error'); -// }); -// } - -// modifyDOM() { -// const shell = findDOMNode(this); -// const { leaf } = this.props; -// // 与 React 不同,rax 的 findDOMNode 找不到节点时, -// // shell 会是 <!-- empty -->,而不是 null, -// // 所以这里进行是否为注释的判断 -// if (shell && shell.nodeType !== window.Node.COMMENT_NODE) { -// setNativeNode(leaf, shell); -// if (leaf.getStatus('dragging')) { -// get(shell, 'classList').add('engine-dragging'); -// } else { -// get(shell, 'classList').remove('engine-dragging'); -// } -// each(get(shell, 'classList'), (cls) => { -// if (cls.substring(0, 8) === '-pseudo-') { -// get(shell, 'classList').remove(cls); -// } -// }); -// const pseudo = leaf.getStatus('pseudo'); -// if (pseudo) { -// get(shell, 'classList').add(`-pseudo-${pseudo}`); -// } -// } else { -// setNativeNode(leaf, null); -// } -// } - -// render() { -// const props = omit(this.props, ['leaf']); -// const { leaf } = this.props; -// const componentName = leaf.getComponentName(); - -// const View = getView(componentName); - -// const newProps = { -// _componentName: componentName, -// }; - -// if (!View) { -// return createElement(UnknownComponent, { -// // _componentName: componentName, -// ...newProps, -// }); -// } - -// let staticProps = { -// ...leaf.getStaticProps(false), -// ...props, -// _componentName: componentName, -// _leaf: leaf, -// componentId: leaf.getId(), -// }; - -// if (!leaf.isVisibleInPane()) { -// return null; -// } - -// if (!leaf.isVisible()) { -// return createElement(HiddenComponent, { -// ...staticProps, -// }); -// } - -// if (this.state.hasError) { -// return createElement(FaultComponent, { -// // _componentName: componentName, -// ...newProps, -// }); -// } - -// if (this.styleSheet) { -// this.styleSheet.parentNode.removeChild(this.styleSheet); -// } - -// this.styleSheet = createNodeStyleSheet(staticProps); - -// if (leaf.ableToModifyChildren()) { -// const children = leaf -// .getChildren() -// .filter((child: any) => child.getComponentName() !== 'Slot') -// .map((child: any) => -// createElement(Leaf, { -// key: child.getId(), -// leaf: child, -// }), -// ); -// // const insertion = leaf.getStatus('dropping'); -// // InsertionGhost 都是React节点,用Rax渲染会报错,后面这些节点需要通过Rax组件来实现 -// // if (children.length < 1 && insertion && insertion.getIndex() !== null) { - -// // //children = []; -// // children = [<InsertionGhost key="insertion" />]; -// // } else if (insertion && insertion.isNearEdge()) { -// // if (insertion.isNearAfter()) { -// // children.push(<InsertionGhost key="insertion" />); -// // } else { -// // children.unshift(<InsertionGhost key="insertion" />); -// // } -// // } -// staticProps = { -// ...staticProps, -// ...this.processSlots(this.props.leaf.getChildren()), -// }; - -// return createElement( -// View, -// { -// ...staticProps, -// }, -// children, -// ); -// } - -// return createElement(View, { -// ...staticProps, -// }); -// } - -// processSlots(children: Rax.RaxNodeArray) { -// const slots: any = {}; -// children && -// children.length && -// children.forEach((child: any) => { -// if (child.getComponentName() === 'Slot') { -// slots[child.getPropValue('slotName')] = <Leaf key={child.getId()} leaf={child} />; -// } -// }); -// return slots; -// } -// } diff --git a/packages/rax-simulator-renderer/src/builtin-components/renderUtils.ts b/packages/rax-simulator-renderer/src/builtin-components/renderUtils.ts deleted file mode 100644 index 10f8438fb2..0000000000 --- a/packages/rax-simulator-renderer/src/builtin-components/renderUtils.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { isObject } from 'lodash'; -import { css } from '@alilc/lowcode-utils'; - -const { toCss } = css; -const engine = (window as any).VisualEngine; -const { Trunk, Viewport } = engine; - -export const NativeNodeCache: any = {}; - -function ucfirst(s: string) { - return s.charAt(0).toUpperCase() + s.substring(1); -} - -export function shallowEqual(obj: { [key: string]: string }, tObj: { [key: string]: string }) { - for (const i in obj) { - if (Object.prototype.hasOwnProperty.call(obj, i) && obj[i] !== tObj[i]) { - return false; - } - } - return true; -} - -export function createNodeStyleSheet(props: any) { - if (props && props.fieldId) { - let styleProp = props.__style__; - - if (isObject(styleProp)) { - styleProp = toCss(styleProp); - } - - if (typeof styleProp === 'string') { - const s = document.createElement('style'); - const cssId = `_style_pesudo_${ props.fieldId}`; - const cssClass = `_css_pesudo_${ props.fieldId}`; - - props.className = cssClass; - s.setAttribute('type', 'text/css'); - s.setAttribute('id', cssId); - document.getElementsByTagName('head')[0].appendChild(s); - - s.appendChild( - document.createTextNode( - styleProp - .replace(/(\d+)rpx/g, (a, b) => { - return `${b / 2}px`; - }) - .replace(/:root/g, `.${ cssClass}`), - ), - ); - return s; - } - } -} - -export function setNativeNode(leaf: any, node: Rax.RaxNode) { - const id = leaf.getId(); - if (NativeNodeCache[id] === node) { - return; - } - NativeNodeCache[id] = node; - leaf.mountChange(); -} - -export function getView(componentName: string) { - // let view = new Trunk().getPrototypeView(componentName); - let view = Trunk.getPrototypeView(componentName); - if (!view) { - return null; - } - const viewport = Viewport.getViewport(); - if (viewport) { - const [mode, device] = viewport.split('-', 2).map(ucfirst); - if (view.hasOwnProperty(device)) { - view = view[device]; - } - - if (view.hasOwnProperty(mode)) { - view = view[mode]; - } - } - - return view; -} diff --git a/packages/rax-simulator-renderer/src/builtin-components/slot.tsx b/packages/rax-simulator-renderer/src/builtin-components/slot.tsx deleted file mode 100644 index 3a77491bc0..0000000000 --- a/packages/rax-simulator-renderer/src/builtin-components/slot.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import { Component } from 'rax'; - -class Slot extends Component { - static displayName = 'Slot'; - - static componentMetadata = { - componentName: 'Slot', - configure: { - props: [{ - name: '___title', - title: { - type: 'i18n', - 'en-US': 'Slot Title', - 'zh-CN': '插槽标题', - }, - setter: 'StringSetter', - defaultValue: '插槽容器', - }, { - name: '___params', - title: { - type: 'i18n', - 'en-US': 'Slot Params', - 'zh-CN': '插槽入参', - }, - setter: { - componentName: 'ArraySetter', - props: { - itemSetter: { - componentName: 'StringSetter', - props: { - placeholder: { - type: 'i18n', - 'zh-CN': '参数名称', - 'en-US': 'Argument Name', - }, - }, - }, - }, - }, - }], - // events/className/style/general/directives - supports: false, - }, - }; - - render() { - const { children } = this.props; - return ( - <div className="lc-container">{children}</div> - ); - } -} - -export default Slot; diff --git a/packages/rax-simulator-renderer/src/host.ts b/packages/rax-simulator-renderer/src/host.ts deleted file mode 100644 index c5cf2e3e1c..0000000000 --- a/packages/rax-simulator-renderer/src/host.ts +++ /dev/null @@ -1,4 +0,0 @@ -// NOTE: 仅做类型标注,切勿做其它用途 -import { BuiltinSimulatorHost } from '@alilc/lowcode-designer'; - -export const host: BuiltinSimulatorHost = (window as any).LCSimulatorHost; diff --git a/packages/rax-simulator-renderer/src/image.d.ts b/packages/rax-simulator-renderer/src/image.d.ts deleted file mode 100644 index 7ed4ad925c..0000000000 --- a/packages/rax-simulator-renderer/src/image.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -declare module 'rax-find-dom-node'; -declare module '@alilc/lowcode-rax-renderer/lib/index'; diff --git a/packages/rax-simulator-renderer/src/index.ts b/packages/rax-simulator-renderer/src/index.ts deleted file mode 100644 index 3a88726657..0000000000 --- a/packages/rax-simulator-renderer/src/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -import renderer from './renderer'; - -if (typeof window !== 'undefined') { - (window as any).SimulatorRenderer = renderer; -} - -export default renderer; diff --git a/packages/rax-simulator-renderer/src/rax-use-router.js b/packages/rax-simulator-renderer/src/rax-use-router.js deleted file mode 100644 index 9a399a9478..0000000000 --- a/packages/rax-simulator-renderer/src/rax-use-router.js +++ /dev/null @@ -1,288 +0,0 @@ -// Inspired by react-router and universal-router -import { useState, useEffect, useLayoutEffect, createElement } from 'rax'; -import pathToRegexp from 'path-to-regexp'; - -const cache = {}; -function decodeParam(val) { - try { - return decodeURIComponent(val); - } catch (err) { - return val; - } -} - -function matchPath(route, pathname, parentParams) { - let { path, routes, exact: end = true, strict = false, sensitive = false } = route; - // If not has path or has routes that should do not exact match - if (path == null || routes) { - end = false; - } - - // Default path is empty - path = path || ''; - - const regexpCacheKey = `${path}|${end}|${strict}|${sensitive}`; - const keysCacheKey = `${regexpCacheKey }|`; - - let regexp = cache[regexpCacheKey]; - const keys = cache[keysCacheKey] || []; - - if (!regexp) { - regexp = pathToRegexp(path, keys, { - end, - strict, - sensitive, - }); - cache[regexpCacheKey] = regexp; - cache[keysCacheKey] = keys; - } - - const result = regexp.exec(pathname); - if (!result) { - return null; - } - - const url = result[0]; - const params = { ...parentParams, history: router.history, location: router.history.location }; - - for (let i = 1; i < result.length; i++) { - const key = keys[i - 1]; - const prop = key.name; - const value = result[i]; - if (value !== undefined || !Object.prototype.hasOwnProperty.call(params, prop)) { - if (key.repeat) { - params[prop] = value ? value.split(key.delimiter).map(decodeParam) : []; - } else { - params[prop] = value ? decodeParam(value) : value; - } - } - } - - return { - path: !end && url.charAt(url.length - 1) === '/' ? url.slice(1) : url, - params, - }; -} - -function matchRoute(route, baseUrl, pathname, parentParams) { - let matched; - let childMatches; - let childIndex = 0; - - return { - next() { - if (!matched) { - matched = matchPath(route, pathname, parentParams); - - if (matched) { - return { - done: false, - $: { - route, - baseUrl, - path: matched.path, - params: matched.params, - }, - }; - } - } - - if (matched && route.routes) { - while (childIndex < route.routes.length) { - if (!childMatches) { - const childRoute = route.routes[childIndex]; - childRoute.parent = route; - - childMatches = matchRoute( - childRoute, - baseUrl + matched.path, - pathname.slice(matched.path.length), - matched.params, - ); - } - - const childMatch = childMatches.next(); - if (!childMatch.done) { - return { - done: false, - $: childMatch.$, - }; - } - - childMatches = null; - childIndex++; - } - } - - return { done: true }; - }, - }; -} - -let _initialized = false; -let _routerConfig = null; -const router = { - history: null, - handles: [], - errorHandler() { }, - addHandle(handle) { - return router.handles.push(handle); - }, - removeHandle(handleId) { - router.handles[handleId - 1] = null; - }, - triggerHandles(component) { - router.handles.forEach((handle) => { - handle && handle(component); - }); - }, - match(fullpath) { - if (fullpath == null) return; - - router.fullpath = fullpath; - - const parent = router.root; - const matched = matchRoute( - parent, - parent.path, - fullpath, - ); - - function next(parent) { - const current = matched.next(); - - if (current.done) { - const error = new Error(`No match for ${fullpath}`); - return router.errorHandler(error, router.history.location); - } - - let { component } = current.$.route; - if (typeof component === 'function') { - component = component(current.$.params, router.history.location); - } - if (component instanceof Promise) { - // Lazy loading component by import('./Foo') - return component.then((component) => { - // Check current fullpath avoid router has changed before lazy loading complete - if (fullpath === router.fullpath) { - router.triggerHandles(component); - } - }); - } else if (component != null) { - router.triggerHandles(component); - return component; - } else { - return next(parent); - } - } - - return next(parent); - }, -}; - -function matchLocation({ pathname }) { - router.match(pathname); -} - - -function getInitialComponent(routerConfig) { - let InitialComponent = []; - - if (_routerConfig === null) { - if (process.env.NODE_ENV !== 'production') { - if (!routerConfig) { - throw new Error('Error: useRouter should have routerConfig, see: https://www.npmjs.com/package/rax-use-router.'); - } - if (!routerConfig.history || !routerConfig.routes) { - throw new Error('Error: routerConfig should contain history and routes, see: https://www.npmjs.com/package/rax-use-router.'); - } - } - _routerConfig = routerConfig; - } - if (_routerConfig.InitialComponent) { - InitialComponent = _routerConfig.InitialComponent; - } - router.history = _routerConfig.history; - - return InitialComponent; -} - -let unlisten = null; -let handleId = null; -let pathes = ''; -export function useRouter(routerConfig) { - const [component, setComponent] = useState(getInitialComponent(routerConfig)); - - let newPathes = ''; - if (routerConfig) { - _routerConfig = routerConfig; - const { routes } = _routerConfig; - router.root = Array.isArray(routes) ? { routes } : routes; - if (Array.isArray(routes)) { - newPathes = routes.map(it => it.path).join(','); - } else { - newPathes = routes.path; - } - } - if (_initialized && _routerConfig.history) { - if (newPathes !== pathes) { - matchLocation(_routerConfig.history.location); - pathes = newPathes; - } - } - - useLayoutEffect(() => { - if (unlisten) { - unlisten(); - unlisten = null; - } - - if (handleId) { - router.removeHandle(handleId); - handleId = null; - } - - const { history } = _routerConfig; - const { routes } = _routerConfig; - - router.root = Array.isArray(routes) ? { routes } : routes; - - handleId = router.addHandle((component) => { - setComponent(component); - }); - - // Init path match - if (_initialized || !_routerConfig.InitialComponent) { - matchLocation(history.location); - pathes = newPathes; - } - - unlisten = history.listen(({ location }) => { - matchLocation(location); - pathes = newPathes; - }); - - _initialized = true; - - return () => { - pathes = ''; - router.removeHandle(handleId); - handleId = null; - unlisten(); - unlisten = null; - }; - }, []); - - return { component }; -} - -export function withRouter(Component) { - function Wrapper(props) { - const { history } = router; - return createElement(Component, { ...props, history, location: history.location }); - } - - Wrapper.displayName = `withRouter(${ Component.displayName || Component.name })`; - Wrapper.WrappedComponent = Component; - return Wrapper; -} diff --git a/packages/rax-simulator-renderer/src/renderer-view.tsx b/packages/rax-simulator-renderer/src/renderer-view.tsx deleted file mode 100644 index bc39cddea0..0000000000 --- a/packages/rax-simulator-renderer/src/renderer-view.tsx +++ /dev/null @@ -1,275 +0,0 @@ -import RaxRenderer from '@alilc/lowcode-rax-renderer'; -import { History } from 'history'; -import { Component, createElement, Fragment } from 'rax'; -import { useRouter } from './rax-use-router'; -import { DocumentInstance, SimulatorRendererContainer } from './renderer'; -import './renderer.less'; -import { uniqueId } from '@alilc/lowcode-utils'; -import { GlobalEvent } from '@alilc/lowcode-types'; -import { host } from './host'; - -// patch cloneElement avoid lost keyProps -const originCloneElement = (window as any).Rax.cloneElement; -(window as any).Rax.cloneElement = (child: any, { _leaf, ...props }: any = {}, ...rest: any[]) => { - if (child.ref && props.ref) { - const dRef = props.ref; - const cRef = child.ref; - props.ref = (x: any) => { - if (cRef) { - if (typeof cRef === 'function') { - cRef(x); - } else { - try { - cRef.current = x; - } catch (e) { - console.error(e); - } - } - } - if (dRef) { - if (typeof dRef === 'function') { - dRef(x); - } else { - try { - dRef.current = x; - } catch (e) { - console.error(e); - } - } - } - }; - } - return originCloneElement(child, props, ...rest); -}; - -export default class SimulatorRendererView extends Component<{ rendererContainer: SimulatorRendererContainer }> { - private unlisten: any; - - componentDidMount() { - const { rendererContainer } = this.props; - this.unlisten = rendererContainer.onLayoutChange(() => { - this.forceUpdate(); - }); - } - - componentWillUnmount() { - if (this.unlisten) { - this.unlisten(); - } - } - - render() { - const { rendererContainer } = this.props; - return ( - <Layout rendererContainer={rendererContainer}> - <Routes rendererContainer={rendererContainer} history={rendererContainer.history} /> - </Layout> - ); - } -} - -export const Routes = (props: { - rendererContainer: SimulatorRendererContainer; - history: History; -}) => { - const { rendererContainer, history } = props; - const { documentInstances } = rendererContainer; - - const routes = { - history, - routes: documentInstances.map(instance => { - return { - path: instance.path, - component: (props: any) => <Renderer key={instance.id} rendererContainer={rendererContainer} documentInstance={instance} {...props} />, - }; - }), - }; - const { component } = useRouter(routes); - return component; -}; - -function ucfirst(s: string) { - return s.charAt(0).toUpperCase() + s.substring(1); -} -function getDeviceView(view: any, device: string, mode: string) { - if (!view || typeof view === 'string') { - return view; - } - - // compatible vision Mobile | Preview - device = ucfirst(device); - if (device === 'Mobile' && view.hasOwnProperty(device)) { - view = view[device]; - } - mode = ucfirst(mode); - if (mode === 'Preview' && view.hasOwnProperty(mode)) { - view = view[mode]; - } - return view; -} - -class Layout extends Component<{ rendererContainer: SimulatorRendererContainer }> { - constructor(props: any) { - super(props); - this.props.rendererContainer.onReRender(() => { - this.forceUpdate(); - }); - } - - render() { - const { rendererContainer, children } = this.props; - const { layout } = rendererContainer; - - if (layout) { - const { Component, props, componentName } = layout; - if (Component) { - return <Component props={props}>{children}</Component>; - } - if (componentName && rendererContainer.getComponent(componentName)) { - return createElement( - rendererContainer.getComponent(componentName), - { - ...props, - rendererContainer, - }, - [children], - ); - } - } - - return <Fragment>{children}</Fragment>; - } -} - -class Renderer extends Component<{ - rendererContainer: SimulatorRendererContainer; - documentInstance: DocumentInstance; -}> { - private unlisten: any; - private key: string; - private startTime: number | null = null; - - componentWillMount() { - this.key = uniqueId('renderer'); - } - - componentDidMount() { - const { documentInstance } = this.props; - this.unlisten = documentInstance.onReRender((params) => { - if (params && params.shouldRemount) { - this.key = uniqueId('renderer'); - } - this.forceUpdate(); - }); - } - - componentWillUnmount() { - if (this.unlisten) { - this.unlisten(); - } - } - shouldComponentUpdate() { - return false; - } - - componentDidUpdate() { - if (this.startTime) { - const time = Date.now() - this.startTime; - const nodeCount = host.designer.currentDocument?.getNodeCount?.(); - host.designer.editor?.eventBus.emit(GlobalEvent.Node.Rerender, { - componentName: 'Renderer', - type: 'All', - time, - nodeCount, - }); - } - } - - schemaChangedSymbol = false; - - getSchemaChangedSymbol = () => { - return this.schemaChangedSymbol; - }; - - setSchemaChangedSymbol = (symbol: boolean) => { - this.schemaChangedSymbol = symbol; - }; - - render() { - const { documentInstance } = this.props; - const { container, document } = documentInstance; - const { designMode, device } = container; - const { rendererContainer: renderer } = this.props; - this.startTime = Date.now(); - this.schemaChangedSymbol = false; - - return ( - <RaxRenderer - schema={documentInstance.schema} - components={renderer.components} - appHelper={renderer.context} - context={renderer.context} - device={device} - designMode={renderer.designMode} - key={this.key} - __host={host} - __container={container} - suspended={documentInstance.suspended} - self={documentInstance.scope} - onCompGetRef={(schema: any, ref: any) => { - documentInstance.mountInstance(schema.id, ref); - }} - thisRequiredInJSE={host.thisRequiredInJSE} - documentId={document.id} - getNode={(id: string) => documentInstance.getNode(id) as any} - rendererName="PageRenderer" - customCreateElement={(Component: any, props: any, children: any) => { - const { __id, ...viewProps } = props; - viewProps.componentId = __id; - const leaf = documentInstance.getNode(__id); - viewProps._leaf = leaf; - viewProps._componentName = leaf?.componentName; - // 如果是容器 && 无children && 高宽为空 增加一个占位容器,方便拖动 - if ( - !viewProps.dataSource && - leaf?.isContainer() && - (children == null || (Array.isArray(children) && !children.length)) && - (!viewProps.style || Object.keys(viewProps.style).length === 0) - ) { - children = ( - <div className="lc-container-placeholder" style={viewProps.placeholderStyle}> - {viewProps.placeholder || '拖拽组件或模板到这里'} - </div> - ); - } - - // if (viewProps._componentName === 'Menu') { - // Object.assign(viewProps, { - // _componentName: 'Menu', - // className: '_css_pesudo_menu_kbrzyh0f', - // context: { VE: (window as any).VisualLowCodeRenderer }, - // direction: undefined, - // events: { ignored: true }, - // fieldId: 'menu_kbrzyh0f', - // footer: '', - // header: '', - // mode: 'inline', - // onItemClick: { ignored: true }, - // onSelect: { ignored: true }, - // popupAlign: 'follow', - // selectMode: false, - // triggerType: 'click', - // }); - // console.info('menuprops', viewProps); - // } - - return createElement( - getDeviceView(Component, device, designMode), - viewProps, - leaf?.isContainer() ? (children == null ? [] : Array.isArray(children) ? children : [children]) : children, - ); - }} - /> - ); - } -} diff --git a/packages/rax-simulator-renderer/src/renderer.less b/packages/rax-simulator-renderer/src/renderer.less deleted file mode 100644 index b71dde9896..0000000000 --- a/packages/rax-simulator-renderer/src/renderer.less +++ /dev/null @@ -1,125 +0,0 @@ -body, html { - display: block; - background: white; - padding: 0; - margin: 0; -} - -html.engine-cursor-move, html.engine-cursor-move * { - cursor: grabbing !important; -} - -html.engine-cursor-copy, html.engine-cursor-copy * { - cursor: copy !important; -} - -html.engine-cursor-ew-resize, html.engine-cursor-ew-resize * { - cursor: ew-resize !important; -} - -::-webkit-scrollbar { - display: none; -} - -.lc-container { - &:empty { - background: #f2f3f5; - color: #a7b1bd; - outline: 1px dashed rgba(31, 56, 88, 0.2); - outline-offset: -1px !important; - height: 66px; - max-height: 100%; - min-width: 140px; - text-align: center; - overflow: hidden; - display: flex; - align-items: center; - &:before { - content: '\62D6\62FD\7EC4\4EF6\6216\6A21\677F\5230\8FD9\91CC'; - font-size: 14px; - z-index: 1; - width: 100%; - white-space: nowrap; - height: 100%; - display: flex; - align-items: center; - justify-content: center; - } - } -} - -.engine-empty { - background: #f2f3f5; - color: #a7b1bd; - outline: 1px dashed rgba(31, 56, 88, 0.2); - outline-offset: -1px !important; - height: 66px; - max-height: 100%; - min-width: 140px; - text-align: center; - overflow: hidden; - display: flex; - align-items: center; -} - -.engine-empty:before { - content: '\62D6\62FD\7EC4\4EF6\6216\6A21\677F\5230\8FD9\91CC'; - font-size: 14px; - z-index: 1; - width: 100%; - white-space: nowrap; - height: 100%; - display: flex; - align-items: center; - justify-content: center; -} - -.lc-container-placeholder { - min-height: 60px; - height: 100%; - width: 100%; - background-color: rgb(240, 240, 240); - border: 1px dotted; - color: rgb(167, 177, 189); - display: flex; - align-items: center; - justify-content: center; - font-size: 14px; -} - -body.engine-document { - &:after, &:before { - content: ""; - display: table; - } - &:after { - clear: both; - } - - /* - .next-input-group, - .next-checkbox-group,.next-date-picker,.next-input,.next-month-picker, - .next-number-picker,.next-radio-group,.next-range,.next-range-picker, - .next-rating,.next-select,.next-switch,.next-time-picker,.next-upload, - .next-year-picker, - .next-breadcrumb-item,.next-calendar-header,.next-calendar-table { - pointer-events: none !important; - } */ -} - -.engine-live-editing { - cursor: text; - outline: none; - box-shadow: 0 0 0 2px rgb(102, 188, 92); - user-select: text; -} - -/* stylelint-disable-next-line selector-max-id */ -#app { - height: 100vh; -} - - -.luna-page { - height: 100%; -} diff --git a/packages/rax-simulator-renderer/src/renderer.ts b/packages/rax-simulator-renderer/src/renderer.ts deleted file mode 100644 index 64ec2d2c69..0000000000 --- a/packages/rax-simulator-renderer/src/renderer.ts +++ /dev/null @@ -1,690 +0,0 @@ -import { BuiltinSimulatorRenderer, Component, IBaseNode, IDocumentModel } from '@alilc/lowcode-designer'; -import { IPublicTypeComponentSchema, IPublicTypeNodeSchema, IPublicTypeNpmInfo, IPublicEnumTransformStage, IPublicTypeNodeInstance, IPublicTypeProjectSchema } from '@alilc/lowcode-types'; -import { Asset, compatibleLegaoSchema, cursor, isElement, isESModule, isLowcodeProjectSchema, isComponentSchema, isPlainObject, isReactComponent, setNativeSelection } from '@alilc/lowcode-utils'; -import LowCodeRenderer from '@alilc/lowcode-rax-renderer'; -import { computed, observable as obx, makeObservable, configure } from 'mobx'; -import DriverUniversal from 'driver-universal'; -import { createMemoryHistory, MemoryHistory } from 'history'; -// @ts-ignore -import Rax, { ComponentType, createElement, render as raxRender, shared } from 'rax'; -import Leaf from './builtin-components/leaf'; -import Slot from './builtin-components/slot'; -import { host } from './host'; -import SimulatorRendererView from './renderer-view'; -import { raxFindDOMNodes } from './utils/find-dom-nodes'; -import { getClientRects } from './utils/get-client-rects'; -import loader from './utils/loader'; -import { parseQuery, withQueryParams } from './utils/url'; -import { IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core'; - -configure({ enforceActions: 'never' }); -const { Instance } = shared; - -export interface LibraryMap { - [key: string]: string; -} - -const SYMBOL_VNID = Symbol('_LCNodeId'); -const SYMBOL_VDID = Symbol('_LCDocId'); - -const INTERNAL = '_internal'; - -function accessLibrary(library: string | object) { - if (typeof library !== 'string') { - return library; - } - - return (window as any)[library]; -} - -// Slot/Leaf and Fragment|FunctionComponent polyfill(ref) - -const builtinComponents = { - Slot, - Leaf, -}; - -function buildComponents( - libraryMap: LibraryMap, - componentsMap: { [componentName: string]: IPublicTypeNpmInfo | ComponentType<any> | IPublicTypeComponentSchema }, - createComponent: (schema: IPublicTypeProjectSchema<IPublicTypeComponentSchema>) => Component | null, -) { - const components: any = { - ...builtinComponents, - }; - Object.keys(componentsMap).forEach((componentName) => { - let component = componentsMap[componentName]; - if (component && (isLowcodeProjectSchema(component) || isComponentSchema(component))) { - if (isComponentSchema(component)) { - components[componentName] = createComponent({ - version: '', - componentsMap: [], - componentsTree: [component], - }); - } else { - components[componentName] = createComponent(component); - } - } else if (isReactComponent(component)) { - components[componentName] = component; - } else { - component = findComponent(libraryMap, componentName, component as IPublicTypeNpmInfo); - if (component) { - components[componentName] = component; - } - } - }); - return components; -} - -let REACT_KEY = ''; -function cacheReactKey(el: Element): Element { - if (REACT_KEY !== '') { - return el; - } - // react17 采用 __reactFiber 开头 - REACT_KEY = Object.keys(el).find( - (key) => key.startsWith('__reactInternalInstance$') || key.startsWith('__reactFiber$'), - ) || ''; - if (!REACT_KEY && (el as HTMLElement).parentElement) { - return cacheReactKey((el as HTMLElement).parentElement!); - } - return el; -} - -function checkInstanceMounted(instance: any): boolean { - if (isElement(instance)) { - return instance.parentElement != null; - } - return true; -} - -function isValidDesignModeRaxComponentInstance( - raxComponentInst: any, -): raxComponentInst is { - props: { - _leaf: Exclude<IPublicTypeNodeInstance<any>['node'], null | undefined>; - }; -} { - const leaf = raxComponentInst?.props?._leaf; - return leaf && typeof leaf === 'object' && leaf.isNode; -} - -export class DocumentInstance { - private instancesMap = new Map<string, any[]>(); - - private emitter: IEventBus = createModuleEventBus('DocumentInstance'); - - get schema(): any { - return this.document.export(IPublicEnumTransformStage.Render); - } - - constructor(readonly container: SimulatorRendererContainer, readonly document: IDocumentModel) { - makeObservable(this); - } - - @computed get suspended(): any { - return false; - } - - @computed get scope(): any { - return null; - } - - get path(): string { - return `/${ this.document.fileName}`; - } - - get id() { - return this.document.id; - } - - private unmountIntance(id: string, instance: any) { - const instances = this.instancesMap.get(id); - if (instances) { - const i = instances.indexOf(instance); - if (i > -1) { - instances.splice(i, 1); - host.setInstance(this.document.id, id, instances); - } - } - } - - refresh() { - this.emitter.emit('rerender', { shouldRemount: true }); - } - - onReRender(fn: () => void) { - this.emitter.on('rerender', fn); - return () => { - this.emitter.removeListener('renderer', fn); - }; - } - - mountInstance(id: string, instance: any) { - const docId = this.document.id; - const { instancesMap } = this; - if (instance == null) { - let instances = this.instancesMap.get(id); - if (instances) { - instances = instances.filter(checkInstanceMounted); - if (instances.length > 0) { - instancesMap.set(id, instances); - host.setInstance(this.document.id, id, instances); - } else { - instancesMap.delete(id); - host.setInstance(this.document.id, id, null); - } - } - return; - } - const unmountIntance = this.unmountIntance.bind(this); - const origId = (instance as any)[SYMBOL_VNID]; - if (origId && origId !== id) { - // 另外一个节点的 instance 在此被复用了,需要从原来地方卸载 - unmountIntance(origId, instance); - } - if (isElement(instance)) { - cacheReactKey(instance); - } else if (origId !== id) { - // 涵盖 origId == null || origId !== id 的情况 - let origUnmount: any = instance.componentWillUnmount; - if (origUnmount && origUnmount.origUnmount) { - origUnmount = origUnmount.origUnmount; - } - // hack! delete instance from map - const newUnmount = function (this: any) { - unmountIntance(id, instance); - origUnmount && origUnmount.call(this); - }; - (newUnmount as any).origUnmount = origUnmount; - instance.componentWillUnmount = newUnmount; - } - - (instance as any)[SYMBOL_VNID] = id; - (instance as any)[SYMBOL_VDID] = docId; - let instances = this.instancesMap.get(id); - if (instances) { - const l = instances.length; - instances = instances.filter(checkInstanceMounted); - let updated = instances.length !== l; - if (!instances.includes(instance)) { - instances.push(instance); - updated = true; - } - if (!updated) { - return; - } - } else { - instances = [instance]; - } - instancesMap.set(id, instances); - host.setInstance(this.document.id, id, instances); - } - - mountContext(docId: string, id: string, ctx: object) { - // this.ctxMap.set(id, ctx); - } - - getComponentInstances(id: string): any[] | null { - return this.instancesMap.get(id) || null; - } - - getNode(id: string): IBaseNode<IPublicTypeNodeSchema> | null { - return this.document.getNode(id); - } -} - -export class SimulatorRendererContainer implements BuiltinSimulatorRenderer { - readonly isSimulatorRenderer = true; - private dispose?: () => void; - readonly history: MemoryHistory; - - private emitter: IEventBus = createModuleEventBus('SimulatorRendererContainer'); - - @obx.ref private _documentInstances: DocumentInstance[] = []; - get documentInstances() { - return this._documentInstances; - } - - get currentDocumentInstance() { - return this._documentInstances.find((item) => item.id === host.project.currentDocument?.id); - } - - constructor() { - this.dispose = host.connect(this, () => { - // sync layout config - this._layout = host.project.get('config').layout; - // todo: split with others, not all should recompute - if (this._libraryMap !== host.libraryMap || this._componentsMap !== host.designer.componentsMap) { - this._libraryMap = host.libraryMap || {}; - this._componentsMap = host.designer.componentsMap; - this.buildComponents(); - } - - // sync designMode - this._designMode = host.designMode; - - this._locale = host.locale; - - // sync requestHandlersMap - this._requestHandlersMap = host.requestHandlersMap; - - // sync device - this._device = host.device; - - this.emitter.emit('layoutChange'); - }); - const documentInstanceMap = new Map<string, DocumentInstance>(); - let initialEntry = '/'; - let firstRun = true; - host.autorun(() => { - this._documentInstances = host.project.documents.map((doc) => { - let inst = documentInstanceMap.get(doc.id); - if (!inst) { - inst = new DocumentInstance(this, doc); - documentInstanceMap.set(doc.id, inst); - } - return inst; - }); - - const path = host.project.currentDocument ? documentInstanceMap.get(host.project.currentDocument.id)!.path : '/'; - if (firstRun) { - initialEntry = path; - firstRun = false; - } else { - if (this.history.location.pathname !== path) { - this.history.replace(path); - } - this.emitter.emit('layoutChange'); - } - }); - const history = createMemoryHistory({ - initialEntries: [initialEntry], - }); - this.history = history; - history.listen(({ location }) => { - host.project.open(location.pathname.slice(1)); - }); - host.componentsConsumer.consume(async (componentsAsset) => { - if (componentsAsset) { - await this.load(componentsAsset); - this.buildComponents(); - } - }); - this._appContext = { - utils: { - router: { - push(path: string, params?: object) { - history.push(withQueryParams(path, params)); - }, - replace(path: string, params?: object) { - history.replace(withQueryParams(path, params)); - }, - back() { - history.back(); - }, - }, - legaoBuiltins: { - getUrlParams() { - const { search } = history.location; - return parseQuery(search); - }, - }, - }, - constants: {}, - requestHandlersMap: this._requestHandlersMap, - }; - host.injectionConsumer.consume((data) => { - // sync utils, i18n, contants,... config - }); - } - - @obx private _layout: any = null; - @computed get layout(): any { - // TODO: parse layout Component - return this._layout; - } - set layout(value: any) { - this._layout = value; - } - - private _libraryMap: { [key: string]: string } = {}; - private buildComponents() { - // TODO: remove this.createComponent - this._components = buildComponents(this._libraryMap, this._componentsMap, this.createComponent.bind(this)); - } - @obx.ref private _components: Record<string, React.FC | React.ComponentClass> | null = {}; - @computed get components(): Record<string, React.FC | React.ComponentClass> { - // 根据 device 选择不同组件,进行响应式 - // 更好的做法是,根据 device 选择加载不同的组件资源,甚至是 simulatorUrl - return this._components || {}; - } - // context from: utils、constants、history、location、match - @obx.ref private _appContext = {}; - @computed get context(): any { - return this._appContext; - } - @obx.ref private _designMode: string = 'design'; - @computed get designMode(): any { - return this._designMode; - } - @obx.ref private _device: string = 'default'; - @computed get device() { - return this._device; - } - @obx.ref private _locale: string | undefined = undefined; - @computed get locale() { - return this._locale; - } - @obx.ref private _requestHandlersMap = null; - @computed get requestHandlersMap(): any { - return this._requestHandlersMap; - } - @obx.ref private _componentsMap = {}; - @computed get componentsMap(): any { - return this._componentsMap; - } - - /** - * 加载资源 - */ - load(asset: Asset): Promise<any> { - return loader.load(asset); - } - - async loadAsyncLibrary(asyncLibraryMap: Record<string, any>) { - } - - getComponent(componentName: string) { - const paths = componentName.split('.'); - const subs: string[] = []; - - while (true) { - const component = this._components?.[componentName]; - if (component) { - return getSubComponent(component, subs); - } - - const sub = paths.pop(); - if (!sub) { - return null; - } - subs.unshift(sub); - componentName = paths.join('.'); - } - } - - getNodeInstance(dom: HTMLElement): IPublicTypeNodeInstance<any> | null { - const INTERNAL = '_internal'; - let instance: any = dom; - if (!isElement(instance)) { - return { - docId: instance.props._leaf.document.id, - nodeId: instance.props._leaf.getId(), - instance, - node: instance.props._leaf, - }; - } - instance = Instance.get(dom); - - let loopNum = 0; // 防止由于某种意外而导致死循环 - while (instance && instance[INTERNAL] && loopNum < 1000) { - if (isValidDesignModeRaxComponentInstance(instance)) { - // if (instance && SYMBOL_VNID in instance) { - // const docId = (instance.props as any).schema.docId; - return { - docId: instance.props._leaf.document?.id || '', - nodeId: instance.props._leaf.getId(), - instance, - node: instance.props._leaf, - }; - } - - instance = getRaxVDomParentInstance(instance); - loopNum += 1; - } - - return null; - } - - getClosestNodeInstance(from: any, nodeId?: string): IPublicTypeNodeInstance<any> | null { - const el: any = from; - if (el) { - // if (isElement(el)) { - // el = cacheReactKey(el); - // } else { - // return getNodeInstance(el, specId); - // } - return this.getNodeInstance(el); - } - return null; - } - - findDOMNodes(instance: any, selector?: string): Array<Element | Text> | null { - let el = instance; - if (selector) { - el = document.querySelector(selector); - } - try { - return raxFindDOMNodes(el); - } catch (e) { - // ignore - } - if (el && el.type && el.props && el.props.componentId) { - el = document.querySelector(`${el.type}[componentid=${el.props.componentId}]`); - } else { - console.error(instance); - throw new Error('This instance may not a valid element'); - } - return raxFindDOMNodes(el); - } - - getClientRects(element: Element | Text) { - return getClientRects(element); - } - - setNativeSelection(enableFlag: boolean) { - setNativeSelection(enableFlag); - } - setDraggingState(state: boolean) { - cursor.setDragging(state); - } - setCopyState(state: boolean) { - cursor.setCopy(state); - } - clearState() { - cursor.release(); - } - - onLayoutChange(cb: () => void) { - this.emitter.on('layoutChange', cb); - return () => { - this.emitter.removeListener('layoutChange', cb); - }; - } - - onReRender(fn: () => void) { - this.emitter.on('rerender', fn); - return () => { - this.emitter.removeListener('renderer', fn); - }; - } - - rerender() { - this.currentDocumentInstance?.refresh(); - } - - stopAutoRepaintNode() { - } - - enableAutoRepaintNode() { - } - - createComponent(schema: IPublicTypeProjectSchema<IPublicTypeComponentSchema>): Component | null { - const _schema: IPublicTypeProjectSchema<IPublicTypeComponentSchema> = { - ...schema, - componentsTree: schema.componentsTree.map(compatibleLegaoSchema), - }; - - const componentsTreeSchema = _schema.componentsTree[0]; - - if (componentsTreeSchema.componentName === 'Component' && componentsTreeSchema.css) { - const doc = window.document; - const s = doc.createElement('style'); - s.setAttribute('type', 'text/css'); - s.setAttribute('id', `Component-${componentsTreeSchema.id || ''}`); - s.appendChild(doc.createTextNode(componentsTreeSchema.css || '')); - doc.getElementsByTagName('head')[0].appendChild(s); - } - - const renderer = this; - const { componentsMap: components } = renderer; - - class LowCodeComp extends Rax.Component { - render() { - const extraProps = getLowCodeComponentProps(this.props); - // @ts-ignore - return createElement(LowCodeRenderer, { - ...extraProps, - schema: componentsTreeSchema, - components, - designMode: '', - locale: renderer.locale, - messages: _schema.i18n || {}, - device: renderer.device, - appHelper: renderer.context, - rendererName: 'LowCodeRenderer', - thisRequiredInJSE: host.thisRequiredInJSE, - customCreateElement: (Comp: any, props: any, children: any) => { - const componentMeta = host.currentDocument?.getComponentMeta(Comp.displayName); - if (componentMeta?.isModal) { - return null; - } - - const { __id, __designMode, ...viewProps } = props; - // mock _leaf,减少性能开销 - const _leaf = { - isEmpty: () => false, - isMock: true, - }; - viewProps._leaf = _leaf; - return createElement(Comp, viewProps, children); - }, - }); - } - } - - return LowCodeComp; - } - - private _running = false; - run() { - if (this._running) { - return; - } - this._running = true; - const containerId = 'app'; - let container = document.getElementById(containerId); - if (!container) { - container = document.createElement('div'); - document.body.appendChild(container); - container.id = containerId; - } - - // ==== compatiable vision - document.documentElement.classList.add('engine-page'); - document.body.classList.add('engine-document'); // important! Stylesheet.invoke depends - - raxRender(createElement(SimulatorRendererView, { - rendererContainer: this, - }), container, { - driver: DriverUniversal, - }); - host.project.setRendererReady(this); - } -} - -function getSubComponent(library: any, paths: string[]) { - const l = paths.length; - if (l < 1 || !library) { - return library; - } - let i = 0; - let component: any; - while (i < l) { - const key = paths[i]!; - let ex: any; - try { - component = library[key]; - } catch (e) { - ex = e; - component = null; - } - if (i === 0 && component == null && key === 'default') { - if (ex) { - return l === 1 ? library : null; - } - component = library; - } else if (component == null) { - return null; - } - library = component; - i++; - } - return component; -} - -function findComponent(libraryMap: LibraryMap, componentName: string, npm?: IPublicTypeNpmInfo) { - if (!npm) { - return accessLibrary(componentName); - } - // libraryName the key access to global - // export { exportName } from xxx exportName === global.libraryName.exportName - // export exportName from xxx exportName === global.libraryName.default || global.libraryName - // export { exportName as componentName } from package - // if exportName == null exportName === componentName; - // const componentName = exportName.subName, if exportName empty subName donot use - const exportName = npm.exportName || npm.componentName || componentName; - const libraryName = libraryMap[npm.package] || exportName; - const library = accessLibrary(libraryName); - const paths = npm.exportName && npm.subName ? npm.subName.split('.') : []; - if (npm.destructuring) { - paths.unshift(exportName); - } else if (isESModule(library)) { - paths.unshift('default'); - } - return getSubComponent(library, paths); -} - -function getLowCodeComponentProps(props: any) { - if (!props || !isPlainObject(props)) { - return props; - } - const newProps: any = {}; - Object.keys(props).forEach(k => { - if (['children', 'componentId', '__designMode', '_componentName', '_leaf'].includes(k)) { - return; - } - newProps[k] = props[k]; - }); - return newProps; -} - -/** - * 获取 Rax 里面 VDOM 的上一级的实例 - * 注意:Rax 的 development 的包是带有 __parentInstance, - * 但是 production 的包 __parentInstance 会被压缩掉, - * 所以这里遍历下其中的所有值,尝试找到有 _internal 的那个(别的值不会带有这个属性的) - */ -function getRaxVDomParentInstance(instance: { _internal: any }) { - const internalInstance = instance._internal; - return internalInstance.__parentInstance || - Object.values(internalInstance).find(v => ( - v !== null && - v !== instance && - typeof v === 'object' && - typeof (v as {_internal: unknown})._internal === 'object' - )); -} - -export default new SimulatorRendererContainer(); diff --git a/packages/rax-simulator-renderer/src/utils/create-defer.ts b/packages/rax-simulator-renderer/src/utils/create-defer.ts deleted file mode 100644 index e7997365a0..0000000000 --- a/packages/rax-simulator-renderer/src/utils/create-defer.ts +++ /dev/null @@ -1,17 +0,0 @@ -export interface Defer<T = any> { - resolve(value?: T | PromiseLike<T>): void; - reject(reason?: any): void; - promise(): Promise<T>; -} - -export function createDefer<T = any>(): Defer<T> { - const r: any = {}; - const promise = new Promise<T>((resolve, reject) => { - r.resolve = resolve; - r.reject = reject; - }); - - r.promise = () => promise; - - return r; -} diff --git a/packages/rax-simulator-renderer/src/utils/find-dom-nodes.ts b/packages/rax-simulator-renderer/src/utils/find-dom-nodes.ts deleted file mode 100644 index 106af2efac..0000000000 --- a/packages/rax-simulator-renderer/src/utils/find-dom-nodes.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { isElement } from '@alilc/lowcode-utils'; -import findDOMNode from 'rax-find-dom-node'; -// import { isDOMNode } from './is-dom-node'; - -export function raxFindDOMNodes(instance: any): Array<Element | Text> | null { - if (!instance) { - return null; - } - if (isElement(instance)) { - return [instance]; - } - // eslint-disable-next-line react/no-find-dom-node - const result = findDOMNode(instance); - if (Array.isArray(result)) { - return result; - } - return [result]; -} diff --git a/packages/rax-simulator-renderer/src/utils/get-client-rects.ts b/packages/rax-simulator-renderer/src/utils/get-client-rects.ts deleted file mode 100644 index dd13aba81e..0000000000 --- a/packages/rax-simulator-renderer/src/utils/get-client-rects.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { isElement } from '@alilc/lowcode-utils'; - -// a range for test TextNode clientRect -const cycleRange = document.createRange(); - -export function getClientRects(node: Element | Text) { - if (isElement(node)) { - return [node.getBoundingClientRect()]; - } - - cycleRange.selectNode(node); - return Array.from(cycleRange.getClientRects()); -} diff --git a/packages/rax-simulator-renderer/src/utils/get-closest-node-instance.ts b/packages/rax-simulator-renderer/src/utils/get-closest-node-instance.ts deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/rax-simulator-renderer/src/utils/get-device-view.ts b/packages/rax-simulator-renderer/src/utils/get-device-view.ts deleted file mode 100644 index 9005562599..0000000000 --- a/packages/rax-simulator-renderer/src/utils/get-device-view.ts +++ /dev/null @@ -1,23 +0,0 @@ -function ucfirst(s: string) { - return s.charAt(0).toUpperCase() + s.substring(1); -} -function getDeviceView(view: any, device: string, mode: string) { - if (!view || typeof view === 'string') { - return view; - } - - // compatible vision Mobile | Preview - device = ucfirst(device); - if (device === 'Mobile' && view.hasOwnProperty(device)) { - view = view[device]; - } - mode = ucfirst(mode); - if (mode === 'Preview' && view.hasOwnProperty(mode)) { - view = view[mode]; - } - return view; -} - -export default { - getDeviceView, -}; diff --git a/packages/rax-simulator-renderer/src/utils/is-dom-node.ts b/packages/rax-simulator-renderer/src/utils/is-dom-node.ts deleted file mode 100644 index bfbeb79c1f..0000000000 --- a/packages/rax-simulator-renderer/src/utils/is-dom-node.ts +++ /dev/null @@ -1,4 +0,0 @@ -export function isDOMNode(node: any): node is Element | Text { - if (!node) return false; - return node.nodeType && (node.nodeType === Node.ELEMENT_NODE || node.nodeType === Node.TEXT_NODE); -} diff --git a/packages/rax-simulator-renderer/src/utils/loader.ts b/packages/rax-simulator-renderer/src/utils/loader.ts deleted file mode 100644 index 436e51c441..0000000000 --- a/packages/rax-simulator-renderer/src/utils/loader.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { load, evaluate } from './script'; -import StylePoint from './style'; -import { - Asset, - AssetLevel, - AssetLevels, - AssetType, - AssetList, - isAssetBundle, - isAssetItem, - assetItem, - AssetItem, - isCSSUrl, -} from '@alilc/lowcode-utils'; - -function parseAssetList(scripts: any, styles: any, assets: AssetList, level?: AssetLevel) { - for (const asset of assets) { - parseAsset(scripts, styles, asset, level); - } -} - -function parseAsset(scripts: any, styles: any, asset: Asset | undefined | null, level?: AssetLevel) { - if (!asset) { - return; - } - if (Array.isArray(asset)) { - return parseAssetList(scripts, styles, asset, level); - } - - if (isAssetBundle(asset)) { - if (asset.assets) { - if (Array.isArray(asset.assets)) { - parseAssetList(scripts, styles, asset.assets, asset.level || level); - } else { - parseAsset(scripts, styles, asset.assets, asset.level || level); - } - return; - } - return; - } - - if (!isAssetItem(asset)) { - asset = assetItem(isCSSUrl(asset) ? AssetType.CSSUrl : AssetType.JSUrl, asset, level)!; - } - - let lv = asset.level || level; - - if (!lv || AssetLevel[lv] == null) { - lv = AssetLevel.App; - } - - asset.level = lv; - if (asset.type === AssetType.CSSUrl || asset.type == AssetType.CSSText) { - styles[lv].push(asset); - } else { - scripts[lv].push(asset); - } -} - -export class AssetLoader { - async load(asset: Asset) { - const styles: any = {}; - const scripts: any = {}; - AssetLevels.forEach(lv => { - styles[lv] = []; - scripts[lv] = []; - }); - parseAsset(scripts, styles, asset); - const styleQueue: AssetItem[] = styles[AssetLevel.Environment].concat( - styles[AssetLevel.Library], - styles[AssetLevel.Theme], - styles[AssetLevel.Runtime], - styles[AssetLevel.App], - ); - const scriptQueue: AssetItem[] = scripts[AssetLevel.Environment].concat( - scripts[AssetLevel.Library], - scripts[AssetLevel.Theme], - scripts[AssetLevel.Runtime], - scripts[AssetLevel.App], - ); - await Promise.all( - styleQueue.map(({ content, level, type, id }) => this.loadStyle(content, level!, type === AssetType.CSSUrl, id)), - ); - await Promise.all(scriptQueue.map(({ content, type }) => this.loadScript(content, type === AssetType.JSUrl))); - } - - private stylePoints = new Map<string, StylePoint>(); - - private loadStyle(content: string | undefined | null, level: AssetLevel, isUrl?: boolean, id?: string) { - if (!content) { - return; - } - let point: StylePoint | undefined; - if (id) { - point = this.stylePoints.get(id); - if (!point) { - point = new StylePoint(level, id); - this.stylePoints.set(id, point); - } - } else { - point = new StylePoint(level); - } - return isUrl ? point.applyUrl(content) : point.applyText(content); - } - - private loadScript(content: string | undefined | null, isUrl?: boolean) { - if (!content) { - return; - } - return isUrl ? load(content) : evaluate(content); - } -} - -export default new AssetLoader(); diff --git a/packages/rax-simulator-renderer/src/utils/script.ts b/packages/rax-simulator-renderer/src/utils/script.ts deleted file mode 100644 index 81841ff6d2..0000000000 --- a/packages/rax-simulator-renderer/src/utils/script.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { createDefer } from './create-defer'; - -export function evaluate(script: string) { - const scriptEl = document.createElement('script'); - scriptEl.text = script; - document.head.appendChild(scriptEl); - document.head.removeChild(scriptEl); -} - -export function load(url: string) { - const node: any = document.createElement('script'); - - // node.setAttribute('crossorigin', 'anonymous'); - - node.onload = onload; - node.onerror = onload; - - const i = createDefer(); - - function onload(e: any) { - node.onload = null; - node.onerror = null; - if (e.type === 'load') { - i.resolve(); - } else { - i.reject(); - } - // document.head.removeChild(node); - // node = null; - } - - // node.async = true; - node.src = url; - - document.head.appendChild(node); - - return i.promise(); -} - -export function evaluateExpression(expr: string) { - // eslint-disable-next-line no-new-func - const fn = new Function(expr); - return fn(); -} - -export function newFunction(args: string, code: string) { - try { - // eslint-disable-next-line no-new-func - return new Function(args, code); - } catch (e) { - console.warn('Caught error, Cant init func'); - return null; - } -} diff --git a/packages/rax-simulator-renderer/src/utils/style.ts b/packages/rax-simulator-renderer/src/utils/style.ts deleted file mode 100644 index 91dbbc6345..0000000000 --- a/packages/rax-simulator-renderer/src/utils/style.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { createDefer } from './create-defer'; - -export default class StylePoint { - private lastContent: string | undefined; - - private lastUrl: string | undefined; - - private placeholder: Element | Text; - - constructor(readonly level: number, readonly id?: string) { - let placeholder: any; - if (id) { - placeholder = document.head.querySelector(`style[data-id="${id}"]`); - } - if (!placeholder) { - placeholder = document.createTextNode(''); - const meta = document.head.querySelector(`meta[level="${level}"]`); - if (meta) { - document.head.insertBefore(placeholder, meta); - } else { - document.head.appendChild(placeholder); - } - } - this.placeholder = placeholder; - } - - applyText(content: string) { - if (this.lastContent === content) { - return; - } - this.lastContent = content; - this.lastUrl = undefined; - const element = document.createElement('style'); - element.setAttribute('type', 'text/css'); - if (this.id) { - element.setAttribute('data-id', this.id); - } - element.appendChild(document.createTextNode(content)); - document.head.insertBefore(element, this.placeholder.parentNode === document.head ? this.placeholder.nextSibling : null); - document.head.removeChild(this.placeholder); - this.placeholder = element; - } - - applyUrl(url: string) { - if (this.lastUrl === url) { - return; - } - this.lastContent = undefined; - this.lastUrl = url; - const element = document.createElement('link'); - element.onload = onload; - element.onerror = onload; - - const i = createDefer(); - function onload(e: any) { - element.onload = null; - element.onerror = null; - if (e.type === 'load') { - i.resolve(); - } else { - i.reject(); - } - } - - element.href = url; - element.rel = 'stylesheet'; - if (this.id) { - element.setAttribute('data-id', this.id); - } - document.head.insertBefore(element, this.placeholder.parentNode === document.head ? this.placeholder.nextSibling : null); - document.head.removeChild(this.placeholder); - this.placeholder = element; - return i.promise(); - } -} diff --git a/packages/rax-simulator-renderer/src/utils/url.ts b/packages/rax-simulator-renderer/src/utils/url.ts deleted file mode 100644 index d720323b3a..0000000000 --- a/packages/rax-simulator-renderer/src/utils/url.ts +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Parse queryString - * @param {String} str '?q=query&b=test' - * @return {Object} - */ -export function parseQuery(str: string): object { - const ret: any = {}; - - if (typeof str !== 'string') { - return ret; - } - - const s = str.trim().replace(/^(\?|#|&)/, ''); - - if (!s) { - return ret; - } - - s.split('&').forEach((param) => { - const parts = param.replace(/\+/g, ' ').split('='); - let key = parts.shift()!; - let val: any = parts.length > 0 ? parts.join('=') : undefined; - - key = decodeURIComponent(key); - - val = val === undefined ? null : decodeURIComponent(val); - - if (ret[key] === undefined) { - ret[key] = val; - } else if (Array.isArray(ret[key])) { - ret[key].push(val); - } else { - ret[key] = [ret[key], val]; - } - }); - - return ret; -} - -/** - * Stringify object to query parammeters - * @param {Object} obj - * @return {String} - */ -export function stringifyQuery(obj: any): string { - const param: string[] = []; - Object.keys(obj).forEach((key) => { - let value = obj[key]; - if (value && typeof value === 'object') { - value = JSON.stringify(value); - } - param.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`); - }); - return param.join('&'); -} - -export function uriEncode(uri: string) { - return encodeURIComponent(uri); -} - -export function uriDecode(uri: string) { - return decodeURIComponent(uri); -} - -export function withQueryParams(url: string, params?: object) { - const queryStr = params ? stringifyQuery(params) : ''; - if (queryStr === '') { - return url; - } - const urlSplit = url.split('#'); - const hash = urlSplit[1] ? `#${urlSplit[1]}` : ''; - const urlWithoutHash = urlSplit[0]; - return `${urlWithoutHash}${~urlWithoutHash.indexOf('?') ? '&' : '?'}${queryStr}${hash}`; -} diff --git a/packages/renderer-core/src/adapter/index.ts b/packages/renderer-core/src/adapter/index.ts index 12896b1372..7a56bc039e 100644 --- a/packages/renderer-core/src/adapter/index.ts +++ b/packages/renderer-core/src/adapter/index.ts @@ -2,7 +2,6 @@ import { IRuntime, IRendererModules, IGeneralConstructor } from '../types'; export enum Env { React = 'react', - Rax = 'rax', } class Adapter { @@ -22,22 +21,22 @@ class Adapter { initRuntime() { const Component: IGeneralConstructor = class <T = any, S = any> { - setState() {} - forceUpdate() {} - render() {} state: Readonly<S>; props: Readonly<T> & Readonly<{ children?: any | undefined }>; refs: Record<string, unknown>; context: Record<string, unknown>; - }; - const PureComponent = class <T = any, S = any> { setState() {} forceUpdate() {} render() {} + }; + const PureComponent = class <T = any, S = any> { state: Readonly<S>; props: Readonly<T> & Readonly<{ children?: any | undefined }>; refs: Record<string, unknown>; context: Record<string, unknown>; + setState() {} + forceUpdate() {} + render() {} }; const createElement = () => {}; const createContext = () => {}; @@ -85,10 +84,6 @@ class Adapter { return this.env === Env.React; } - isRax() { - return this.env === Env.Rax; - } - setRenderers(renderers: IRendererModules) { this.renderers = renderers; } diff --git a/packages/renderer-core/tests/adapter/adapter.test.ts b/packages/renderer-core/tests/adapter/adapter.test.ts index a838602fbe..57d92d1d42 100644 --- a/packages/renderer-core/tests/adapter/adapter.test.ts +++ b/packages/renderer-core/tests/adapter/adapter.test.ts @@ -79,15 +79,10 @@ describe('test src/adapter ', () => { }); - it('setEnv/.env/isReact/isRax works', () => { + it('setEnv/.env/isReact works', () => { adapter.setEnv(Env.React); expect(adapter.env).toBe(Env.React); expect(adapter.isReact()).toBeTruthy(); - expect(adapter.isRax()).toBeFalsy(); - adapter.setEnv(Env.Rax); - expect(adapter.env).toBe(Env.Rax); - expect(adapter.isRax()).toBeTruthy(); - expect(adapter.isReact()).toBeFalsy(); }); it('setRenderers/getRenderers works', () => { diff --git a/packages/types/src/shell/type/engine-options.ts b/packages/types/src/shell/type/engine-options.ts index b570d1990a..72078c8107 100644 --- a/packages/types/src/shell/type/engine-options.ts +++ b/packages/types/src/shell/type/engine-options.ts @@ -41,7 +41,7 @@ export interface IPublicTypeEngineOptions { /** * 渲染器类型,默认值:'react' */ - renderEnv?: 'react' | 'rax' | string; + renderEnv?: 'react' | string; /** * 设备类型映射器,处理设计器与渲染器中 device 的映射 diff --git a/scripts/build.sh b/scripts/build.sh index 92b0a99c23..0d96598e62 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -9,8 +9,6 @@ lerna run build \ --scope @alilc/lowcode-designer \ --scope @alilc/lowcode-plugin-designer \ --scope @alilc/lowcode-plugin-outline-pane \ - --scope @alilc/lowcode-rax-renderer \ - --scope @alilc/lowcode-rax-simulator-renderer \ --scope @alilc/lowcode-react-renderer \ --scope @alilc/lowcode-react-simulator-renderer \ --scope @alilc/lowcode-renderer-core \ @@ -20,13 +18,9 @@ lerna run build \ lerna run build:umd \ --scope @alilc/lowcode-engine \ - --scope @alilc/lowcode-rax-simulator-renderer \ --scope @alilc/lowcode-react-simulator-renderer \ --scope @alilc/lowcode-react-renderer \ --stream cp ./packages/react-simulator-renderer/dist/js/* ./packages/engine/dist/js/ cp ./packages/react-simulator-renderer/dist/css/* ./packages/engine/dist/css/ - -cp ./packages/rax-simulator-renderer/dist/js/* ./packages/engine/dist/js/ -cp ./packages/rax-simulator-renderer/dist/css/* ./packages/engine/dist/css/ \ No newline at end of file diff --git a/scripts/sync.sh b/scripts/sync.sh index 98895c7234..e9840eeca6 100755 --- a/scripts/sync.sh +++ b/scripts/sync.sh @@ -10,8 +10,6 @@ tnpm sync @alilc/lowcode-designer tnpm sync @alilc/lowcode-plugin-designer tnpm sync @alilc/lowcode-plugin-outline-pane tnpm sync @alilc/lowcode-renderer-core -tnpm sync @alilc/lowcode-rax-renderer -tnpm sync @alilc/lowcode-rax-simulator-renderer tnpm sync @alilc/lowcode-react-renderer tnpm sync @alilc/lowcode-react-simulator-renderer tnpm sync @alilc/lowcode-engine From d47c2d2f91a57aa4f19fa5bbc8b1dfb3ded88da9 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Fri, 5 Jan 2024 08:09:04 +0000 Subject: [PATCH 159/219] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 4d6ef0a770..6659eaf853 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.18", + "version": "1.2.19", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 1b00c61a32027084e531a0ffacb2a9a2020fbcbf Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 8 Jan 2024 14:46:27 +0800 Subject: [PATCH 160/219] feat(engine): add context menu --- .gitignore | 2 + docs/docs/api/commonUI.md | 20 ++ docs/docs/api/configOptions.md | 6 + docs/docs/guide/expand/editor/theme.md | 1 + .../designer/src/context-menu-actions.scss | 10 + packages/designer/src/context-menu-actions.ts | 145 +++++++++++++++ packages/designer/src/designer/designer.ts | 11 +- packages/designer/src/index.ts | 1 + packages/editor-core/src/config.ts | 5 + packages/engine/src/engine-core.ts | 3 + .../src/inner-plugins/default-context-menu.ts | 172 ++++++++++++++++++ packages/engine/src/locale/en-US.json | 9 + packages/engine/src/locale/index.ts | 14 ++ packages/engine/src/locale/zh-CN.json | 9 + packages/shell/src/api/commonUI.ts | 4 + packages/shell/src/api/material.ts | 14 ++ .../shell/src/components/context-menu.tsx | 46 +++++ packages/types/src/shell/api/commonUI.ts | 8 +- packages/types/src/shell/api/material.ts | 20 +- packages/types/src/shell/enum/context-menu.ts | 7 + packages/types/src/shell/enum/index.ts | 3 +- packages/types/src/shell/type/context-menu.ts | 57 ++++++ .../types/src/shell/type/engine-options.ts | 6 + packages/types/src/shell/type/index.ts | 3 +- packages/utils/src/context-menu.scss | 33 ++++ packages/utils/src/context-menu.tsx | 138 ++++++++++++++ packages/utils/src/index.ts | 1 + 27 files changed, 743 insertions(+), 5 deletions(-) create mode 100644 packages/designer/src/context-menu-actions.scss create mode 100644 packages/designer/src/context-menu-actions.ts create mode 100644 packages/engine/src/inner-plugins/default-context-menu.ts create mode 100644 packages/engine/src/locale/en-US.json create mode 100644 packages/engine/src/locale/index.ts create mode 100644 packages/engine/src/locale/zh-CN.json create mode 100644 packages/shell/src/components/context-menu.tsx create mode 100644 packages/types/src/shell/enum/context-menu.ts create mode 100644 packages/types/src/shell/type/context-menu.ts create mode 100644 packages/utils/src/context-menu.scss create mode 100644 packages/utils/src/context-menu.tsx diff --git a/.gitignore b/.gitignore index 05159f0473..6a19ae3e0c 100644 --- a/.gitignore +++ b/.gitignore @@ -108,3 +108,5 @@ typings/ # codealike codealike.json .node + +.must.config.js \ No newline at end of file diff --git a/docs/docs/api/commonUI.md b/docs/docs/api/commonUI.md index 9d1f706520..ef7af7f415 100644 --- a/docs/docs/api/commonUI.md +++ b/docs/docs/api/commonUI.md @@ -29,6 +29,26 @@ CommonUI API 是一个专为低代码引擎设计的组件 UI 库,使用它开 | className | className | string (optional) | | | onClick | 点击事件 | () => void (optional) | | +### ContextMenu + +| 参数 | 说明 | 类型 | 默认值 | +|--------|----------------------------------------------------|------------------------------------|--------| +| menus | 定义上下文菜单的动作数组 | IPublicTypeContextMenuAction[] | | +| children | 组件的子元素 | React.ReactElement[] | | + +**IPublicTypeContextMenuAction Interface** + +| 参数 | 说明 | 类型 | 默认值 | +|------------|--------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------|----------------------------------------| +| name | 动作的唯一标识符<br>Unique identifier for the action | string | | +| title | 显示的标题,可以是字符串或国际化数据<br>Display title, can be a string or internationalized data | string \| IPublicTypeI18nData (optional) | | +| type | 菜单项类型<br>Menu item type | IPublicEnumContextMenuType (optional) | IPublicEnumPContextMenuType.MENU_ITEM | +| action | 点击时执行的动作,可选<br>Action to execute on click, optional | (nodes: IPublicModelNode[]) => void (optional) | | +| items | 子菜单项或生成子节点的函数,可选,仅支持两级<br>Sub-menu items or function to generate child node, optional | Omit<IPublicTypeContextMenuAction, 'items'>[] \| ((nodes: IPublicModelNode[]) => Omit<IPublicTypeContextMenuAction, 'items'>[]) (optional) | | +| condition | 显示条件函数<br>Function to determine display condition | (nodes: IPublicModelNode[]) => boolean (optional) | | +| disabled | 禁用条件函数,可选<br>Function to determine disabled condition, optional | (nodes: IPublicModelNode[]) => boolean (optional) | | + + ### Balloon 详细文档: [Balloon Documentation](https://fusion.design/pc/component/balloon) diff --git a/docs/docs/api/configOptions.md b/docs/docs/api/configOptions.md index 5f6ade710f..67d2fae2c1 100644 --- a/docs/docs/api/configOptions.md +++ b/docs/docs/api/configOptions.md @@ -185,6 +185,12 @@ config.set('enableCondition', false) `@type {boolean}` `@default {false}` +#### enableContextMenu - 开启右键菜单 + +`@type {boolean}` `@default {false}` + +是否开启右键菜单 + #### disableDetecting `@type {boolean}` `@default {false}` diff --git a/docs/docs/guide/expand/editor/theme.md b/docs/docs/guide/expand/editor/theme.md index ef0e04d28d..1c442c5132 100644 --- a/docs/docs/guide/expand/editor/theme.md +++ b/docs/docs/guide/expand/editor/theme.md @@ -128,6 +128,7 @@ sidebar_position: 9 - `--pane-title-height`: 面板标题高度 - `--pane-title-font-size`: 面板标题字体大小 - `--pane-title-padding`: 面板标题边距 +- `--context-menu-item-height`: 右键菜单项高度 diff --git a/packages/designer/src/context-menu-actions.scss b/packages/designer/src/context-menu-actions.scss new file mode 100644 index 0000000000..863c929447 --- /dev/null +++ b/packages/designer/src/context-menu-actions.scss @@ -0,0 +1,10 @@ +.engine-context-menu { + &.next-menu.next-ver .next-menu-item { + padding-right: 30px; + + .next-menu-item-inner { + height: var(--context-menu-item-height, 30px); + line-height: var(--context-menu-item-height, 30px); + } + } +} \ No newline at end of file diff --git a/packages/designer/src/context-menu-actions.ts b/packages/designer/src/context-menu-actions.ts new file mode 100644 index 0000000000..053e4f0313 --- /dev/null +++ b/packages/designer/src/context-menu-actions.ts @@ -0,0 +1,145 @@ +import { IPublicTypeContextMenuAction, IPublicEnumContextMenuType, IPublicTypeContextMenuItem, IPublicApiMaterial } from '@alilc/lowcode-types'; +import { IDesigner, INode } from './designer'; +import { parseContextMenuAsReactNode, parseContextMenuProperties } from '@alilc/lowcode-utils'; +import { Menu } from '@alifd/next'; +import { engineConfig } from '@alilc/lowcode-editor-core'; +import './context-menu-actions.scss'; + +export interface IContextMenuActions { + actions: IPublicTypeContextMenuAction[]; + + adjustMenuLayoutFn: (actions: IPublicTypeContextMenuItem[]) => IPublicTypeContextMenuItem[]; + + addMenuAction: IPublicApiMaterial['addContextMenuOption']; + + removeMenuAction: IPublicApiMaterial['removeContextMenuOption']; + + adjustMenuLayout: IPublicApiMaterial['adjustContextMenuLayout']; +} + +export class ContextMenuActions implements IContextMenuActions { + actions: IPublicTypeContextMenuAction[] = []; + + designer: IDesigner; + + dispose: Function[]; + + enableContextMenu: boolean; + + constructor(designer: IDesigner) { + this.designer = designer; + this.dispose = []; + + engineConfig.onGot('enableContextMenu', (enable) => { + if (this.enableContextMenu === enable) { + return; + } + this.enableContextMenu = enable; + this.dispose.forEach(d => d()); + if (enable) { + this.initEvent(); + } + }); + } + + handleContextMenu = ( + nodes: INode[], + event: MouseEvent, + ) => { + const designer = this.designer; + event.stopPropagation(); + event.preventDefault(); + + const actions = designer.contextMenuActions.actions; + + const { bounds } = designer.project.simulator?.viewport || { bounds: { left: 0, top: 0 } }; + const { left: simulatorLeft, top: simulatorTop } = bounds; + + let destroyFn: Function | undefined; + + const destroy = () => { + destroyFn?.(); + }; + + const menus: IPublicTypeContextMenuItem[] = parseContextMenuProperties(actions, { + nodes: nodes.map(d => designer.shellModelFactory.createNode(d)!), + destroy, + }); + + if (!menus.length) { + return; + } + + const layoutMenu = designer.contextMenuActions.adjustMenuLayoutFn(menus); + + const menuNode = parseContextMenuAsReactNode(layoutMenu, { + destroy, + nodes: nodes.map(d => designer.shellModelFactory.createNode(d)!), + designer, + }); + + const target = event.target; + + const { top, left } = target?.getBoundingClientRect(); + + const menuInstance = Menu.create({ + target: event.target, + offset: [event.clientX - left + simulatorLeft, event.clientY - top + simulatorTop], + children: menuNode, + className: 'engine-context-menu', + }); + + destroyFn = (menuInstance as any).destroy; + }; + + initEvent() { + const designer = this.designer; + this.dispose.push( + designer.editor.eventBus.on('designer.builtinSimulator.contextmenu', ({ + node, + originalEvent, + }: { + node: INode; + originalEvent: MouseEvent; + }) => { + // 如果右键的节点不在 当前选中的节点中,选中该节点 + if (!designer.currentSelection.has(node.id)) { + designer.currentSelection.select(node.id); + } + const nodes = designer.currentSelection.getNodes(); + this.handleContextMenu(nodes, originalEvent); + }), + (() => { + const handleContextMenu = (e: MouseEvent) => { + this.handleContextMenu([], e); + }; + + document.addEventListener('contextmenu', handleContextMenu); + + return () => { + document.removeEventListener('contextmenu', handleContextMenu); + }; + })(), + ); + } + + adjustMenuLayoutFn: (actions: IPublicTypeContextMenuItem[]) => IPublicTypeContextMenuItem[] = (actions) => actions; + + addMenuAction(action: IPublicTypeContextMenuAction) { + this.actions.push({ + type: IPublicEnumContextMenuType.MENU_ITEM, + ...action, + }); + } + + removeMenuAction(name: string) { + const i = this.actions.findIndex((action) => action.name === name); + if (i > -1) { + this.actions.splice(i, 1); + } + } + + adjustMenuLayout(fn: (actions: IPublicTypeContextMenuItem[]) => IPublicTypeContextMenuItem[]) { + this.adjustMenuLayoutFn = fn; + } +} \ No newline at end of file diff --git a/packages/designer/src/designer/designer.ts b/packages/designer/src/designer/designer.ts index d7e17e84ca..1dd4bc04e6 100644 --- a/packages/designer/src/designer/designer.ts +++ b/packages/designer/src/designer/designer.ts @@ -20,7 +20,7 @@ import { } from '@alilc/lowcode-types'; import { mergeAssets, IPublicTypeAssetsJson, isNodeSchema, isDragNodeObject, isDragNodeDataObject, isLocationChildrenDetail, Logger } from '@alilc/lowcode-utils'; import { IProject, Project } from '../project'; -import { Node, DocumentModel, insertChildren, INode } from '../document'; +import { Node, DocumentModel, insertChildren, INode, ISelection } from '../document'; import { ComponentMeta, IComponentMeta } from '../component-meta'; import { INodeSelector, Component } from '../simulator'; import { Scroller } from './scroller'; @@ -32,6 +32,7 @@ import { OffsetObserver, createOffsetObserver } from './offset-observer'; import { ISettingTopEntry, SettingTopEntry } from './setting'; import { BemToolsManager } from '../builtin-simulator/bem-tools/manager'; import { ComponentActions } from '../component-actions'; +import { ContextMenuActions, IContextMenuActions } from '../context-menu-actions'; const logger = new Logger({ level: 'warn', bizName: 'designer' }); @@ -72,12 +73,16 @@ export interface IDesigner { get componentActions(): ComponentActions; + get contextMenuActions(): ContextMenuActions; + get editor(): IPublicModelEditor; get detecting(): Detecting; get simulatorComponent(): ComponentType<any> | undefined; + get currentSelection(): ISelection; + createScroller(scrollable: IPublicTypeScrollable): IPublicModelScroller; refreshComponentMetasMap(): void; @@ -122,6 +127,8 @@ export class Designer implements IDesigner { readonly componentActions = new ComponentActions(); + readonly contextMenuActions: IContextMenuActions; + readonly activeTracker = new ActiveTracker(); readonly detecting = new Detecting(); @@ -198,6 +205,8 @@ export class Designer implements IDesigner { this.postEvent('dragstart', e); }); + this.contextMenuActions = new ContextMenuActions(this); + this.dragon.onDrag((e) => { if (this.props?.onDrag) { this.props.onDrag(e); diff --git a/packages/designer/src/index.ts b/packages/designer/src/index.ts index 489d81482f..11e6453b8a 100644 --- a/packages/designer/src/index.ts +++ b/packages/designer/src/index.ts @@ -6,3 +6,4 @@ export * from './project'; export * from './builtin-simulator'; export * from './plugin'; export * from './types'; +export * from './context-menu-actions'; diff --git a/packages/editor-core/src/config.ts b/packages/editor-core/src/config.ts index a5da74742d..c4ff407b9a 100644 --- a/packages/editor-core/src/config.ts +++ b/packages/editor-core/src/config.ts @@ -159,6 +159,11 @@ const VALID_ENGINE_OPTIONS = { type: 'function', description: '应用级设计模式下,窗口为空时展示的占位组件', }, + enableContextMenu: { + type: 'boolean', + description: '是否开启右键菜单', + default: false, + }, hideComponentAction: { type: 'boolean', description: '是否隐藏设计器辅助层', diff --git a/packages/engine/src/engine-core.ts b/packages/engine/src/engine-core.ts index 9f29046fbe..29b4a7f038 100644 --- a/packages/engine/src/engine-core.ts +++ b/packages/engine/src/engine-core.ts @@ -62,6 +62,7 @@ import { setterRegistry } from './inner-plugins/setter-registry'; import { defaultPanelRegistry } from './inner-plugins/default-panel-registry'; import { shellModelFactory } from './modules/shell-model-factory'; import { builtinHotkey } from './inner-plugins/builtin-hotkey'; +import { defaultContextMenu } from './inner-plugins/default-context-menu'; import { OutlinePlugin } from '@alilc/lowcode-plugin-outline-pane'; export * from './modules/skeleton-types'; @@ -78,6 +79,7 @@ async function registryInnerPlugin(designer: IDesigner, editor: IEditor, plugins await plugins.register(defaultPanelRegistryPlugin); await plugins.register(builtinHotkey); await plugins.register(registerDefaults, {}, { autoInit: true }); + await plugins.register(defaultContextMenu); return () => { plugins.delete(OutlinePlugin.pluginName); @@ -86,6 +88,7 @@ async function registryInnerPlugin(designer: IDesigner, editor: IEditor, plugins plugins.delete(defaultPanelRegistryPlugin.pluginName); plugins.delete(builtinHotkey.pluginName); plugins.delete(registerDefaults.pluginName); + plugins.delete(defaultContextMenu.pluginName); }; } diff --git a/packages/engine/src/inner-plugins/default-context-menu.ts b/packages/engine/src/inner-plugins/default-context-menu.ts new file mode 100644 index 0000000000..86feb17d97 --- /dev/null +++ b/packages/engine/src/inner-plugins/default-context-menu.ts @@ -0,0 +1,172 @@ +import { + IPublicEnumContextMenuType, + IPublicEnumTransformStage, + IPublicModelNode, + IPublicModelPluginContext, + IPublicTypeNodeSchema, +} from '@alilc/lowcode-types'; +import { isProjectSchema } from '@alilc/lowcode-utils'; +import { Notification } from '@alifd/next'; +import { intl } from '../locale'; + +function getNodesSchema(nodes: IPublicModelNode[]) { + const componentsTree = nodes.map((node) => node?.exportSchema(IPublicEnumTransformStage.Clone)); + const data = { type: 'nodeSchema', componentsMap: {}, componentsTree }; + return data; +} + +async function getClipboardText(): Promise<IPublicTypeNodeSchema[]> { + return new Promise((resolve, reject) => { + // 使用 Clipboard API 读取剪贴板内容 + navigator.clipboard.readText().then( + (text) => { + try { + const data = JSON.parse(text); + if (isProjectSchema(data)) { + resolve(data.componentsTree); + } else { + Notification.open({ + content: intl('NotValidNodeData'), + type: 'error', + }); + reject( + new Error(intl('NotValidNodeData')), + ); + } + } catch (error) { + Notification.open({ + content: intl('NotValidNodeData'), + type: 'error', + }); + reject(error); + } + }, + (err) => { + reject(err); + }, + ); + }); +} + +export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { + const { material, canvas } = ctx; + const { clipboard } = canvas; + + return { + init() { + material.addContextMenuOption({ + name: 'selectComponent', + title: intl('SelectComponents'), + condition: (nodes) => { + return nodes.length === 1; + }, + items: [ + { + name: 'nodeTree', + type: IPublicEnumContextMenuType.NODE_TREE, + }, + ], + }); + + material.addContextMenuOption({ + name: 'copyAndPaste', + title: intl('Copy'), + condition: (nodes) => { + return nodes.length === 1; + }, + action(nodes) { + const node = nodes[0]; + const { document: doc, parent, index } = node; + if (parent) { + const newNode = doc?.insertNode(parent, node, (index ?? 0) + 1, true); + newNode?.select(); + } + }, + }); + + material.addContextMenuOption({ + name: 'copy', + title: intl('Copy.1'), + action(nodes) { + if (!nodes || nodes.length < 1) { + return; + } + + const data = getNodesSchema(nodes); + clipboard.setData(data); + }, + }); + + material.addContextMenuOption({ + name: 'zhantieToBottom', + title: intl('PasteToTheBottom'), + condition: (nodes) => { + return nodes.length === 1; + }, + async action(nodes) { + if (!nodes || nodes.length < 1) { + return; + } + + const node = nodes[0]; + const { document: doc, parent, index } = node; + + try { + const nodeSchema = await getClipboardText(); + if (parent) { + nodeSchema.forEach((schema, schemaIndex) => { + doc?.insertNode(parent, schema, (index ?? 0) + 1 + schemaIndex, true); + }); + } + } catch (error) { + console.error(error); + } + }, + }); + + material.addContextMenuOption({ + name: 'zhantieToInner', + title: intl('PasteToTheInside'), + condition: (nodes) => { + return nodes.length === 1; + }, + disabled: (nodes) => { + // 获取粘贴数据 + const node = nodes[0]; + return !node.isContainerNode; + }, + async action(nodes) { + const node = nodes[0]; + const { document: doc, parent } = node; + + try { + const nodeSchema = await getClipboardText(); + if (parent) { + const index = node.children?.size || 0; + + if (parent) { + nodeSchema.forEach((schema, schemaIndex) => { + doc?.insertNode(node, schema, (index ?? 0) + 1 + schemaIndex, true); + }); + } + } + } catch (error) { + console.error(error); + } + }, + }); + + material.addContextMenuOption({ + name: 'delete', + title: intl('Delete'), + action(nodes) { + nodes.forEach((node) => { + node.remove(); + }); + }, + }); + }, + }; +}; + +defaultContextMenu.pluginName = '___default_context_menu___'; diff --git a/packages/engine/src/locale/en-US.json b/packages/engine/src/locale/en-US.json new file mode 100644 index 0000000000..1cdb06f28b --- /dev/null +++ b/packages/engine/src/locale/en-US.json @@ -0,0 +1,9 @@ +{ + "NotValidNodeData": "Not valid node data", + "SelectComponents": "Select components", + "Copy": "Copy", + "Copy.1": "Copy", + "PasteToTheBottom": "Paste to the bottom", + "PasteToTheInside": "Paste to the inside", + "Delete": "Delete" +} diff --git a/packages/engine/src/locale/index.ts b/packages/engine/src/locale/index.ts new file mode 100644 index 0000000000..510fcf056a --- /dev/null +++ b/packages/engine/src/locale/index.ts @@ -0,0 +1,14 @@ +import { createIntl } from '@alilc/lowcode-editor-core'; +import enUS from './en-US.json'; +import zhCN from './zh-CN.json'; + +const { intl } = createIntl?.({ + 'en-US': enUS, + 'zh-CN': zhCN, +}) || { + intl: (id) => { + return zhCN[id]; + }, +}; + +export { intl, enUS, zhCN }; diff --git a/packages/engine/src/locale/zh-CN.json b/packages/engine/src/locale/zh-CN.json new file mode 100644 index 0000000000..ba0f87f8e6 --- /dev/null +++ b/packages/engine/src/locale/zh-CN.json @@ -0,0 +1,9 @@ +{ + "NotValidNodeData": "不是有效的节点数据", + "SelectComponents": "选择组件", + "Copy": "复制", + "Copy.1": "拷贝", + "PasteToTheBottom": "粘贴至下方", + "PasteToTheInside": "粘贴至内部", + "Delete": "删除" +} diff --git a/packages/shell/src/api/commonUI.ts b/packages/shell/src/api/commonUI.ts index 718b409707..9f40afa119 100644 --- a/packages/shell/src/api/commonUI.ts +++ b/packages/shell/src/api/commonUI.ts @@ -4,6 +4,7 @@ import { Title as InnerTitle, } from '@alilc/lowcode-editor-core'; import { Balloon, Breadcrumb, Button, Card, Checkbox, DatePicker, Dialog, Dropdown, Form, Icon, Input, Loading, Message, Overlay, Pagination, Radio, Search, Select, SplitButton, Step, Switch, Tab, Table, Tree, TreeSelect, Upload, Divider } from '@alifd/next'; +import { ContextMenu } from '../components/context-menu'; export class CommonUI implements IPublicApiCommonUI { Balloon = Balloon; @@ -40,4 +41,7 @@ export class CommonUI implements IPublicApiCommonUI { get Title() { return InnerTitle; } + get ContextMenu() { + return ContextMenu; + } } diff --git a/packages/shell/src/api/material.ts b/packages/shell/src/api/material.ts index 39b21848e0..f0c37d8a4d 100644 --- a/packages/shell/src/api/material.ts +++ b/packages/shell/src/api/material.ts @@ -13,6 +13,8 @@ import { IPublicTypeNpmInfo, IPublicModelEditor, IPublicTypeDisposable, + IPublicTypeContextMenuAction, + IPublicTypeContextMenuItem, } from '@alilc/lowcode-types'; import { Workspace as InnerWorkspace } from '@alilc/lowcode-workspace'; import { editorSymbol, designerSymbol } from '../symbols'; @@ -190,4 +192,16 @@ export class Material implements IPublicApiMaterial { dispose.forEach(d => d && d()); }; } + + addContextMenuOption(option: IPublicTypeContextMenuAction) { + this[designerSymbol].contextMenuActions.addMenuAction(option); + } + + removeContextMenuOption(name: string) { + this[designerSymbol].contextMenuActions.removeMenuAction(name); + } + + adjustContextMenuLayout(fn: (actions: IPublicTypeContextMenuItem[]) => IPublicTypeContextMenuItem[]) { + this[designerSymbol].contextMenuActions.adjustMenuLayout(fn); + } } diff --git a/packages/shell/src/components/context-menu.tsx b/packages/shell/src/components/context-menu.tsx new file mode 100644 index 0000000000..0085e1c777 --- /dev/null +++ b/packages/shell/src/components/context-menu.tsx @@ -0,0 +1,46 @@ +import { Menu } from '@alifd/next'; +import { parseContextMenuAsReactNode, parseContextMenuProperties } from '@alilc/lowcode-utils'; +import { engineConfig } from '@alilc/lowcode-editor-core'; +import { IPublicTypeContextMenuAction } from '@alilc/lowcode-types'; +import React from 'react'; + +export function ContextMenu({ children, menus }: { + menus: IPublicTypeContextMenuAction[]; + children: React.ReactElement[]; +}): React.ReactElement<any, string | React.JSXElementConstructor<any>>[] { + if (!engineConfig.get('enableContextMenu')) { + return children; + } + + const handleContextMenu = (event: React.MouseEvent) => { + event.preventDefault(); + event.stopPropagation(); + + const target = event.target; + const { top, left } = target?.getBoundingClientRect(); + let destroyFn: Function | undefined; + const destroy = () => { + destroyFn?.(); + }; + const children: React.ReactNode[] = parseContextMenuAsReactNode(parseContextMenuProperties(menus, { + destroy, + })); + + const menuInstance = Menu.create({ + target: event.target, + offset: [event.clientX - left, event.clientY - top], + children, + }); + + destroyFn = (menuInstance as any).destroy; + }; + + // 克隆 children 并添加 onContextMenu 事件处理器 + const childrenWithContextMenu = React.Children.map(children, (child) => + React.cloneElement( + child, + { onContextMenu: handleContextMenu }, + )); + + return childrenWithContextMenu; +} \ No newline at end of file diff --git a/packages/types/src/shell/api/commonUI.ts b/packages/types/src/shell/api/commonUI.ts index 3d7bb57bf3..dcc6fab0c3 100644 --- a/packages/types/src/shell/api/commonUI.ts +++ b/packages/types/src/shell/api/commonUI.ts @@ -1,4 +1,5 @@ -import { IPublicTypeTitleContent } from '../type'; +import { ReactElement } from 'react'; +import { IPublicTypeContextMenuAction, IPublicTypeTitleContent } from '../type'; import { Balloon, Breadcrumb, Button, Card, Checkbox, DatePicker, Dialog, Dropdown, Form, Icon, Input, Loading, Message, Overlay, Pagination, Radio, Search, Select, SplitButton, Step, Switch, Tab, Table, Tree, TreeSelect, Upload, Divider } from '@alifd/next'; export interface IPublicApiCommonUI { @@ -45,4 +46,9 @@ export interface IPublicApiCommonUI { match?: boolean; keywords?: string | null; }>; + + get ContextMenu(): (props: { + menus: IPublicTypeContextMenuAction[]; + children: React.ReactElement[]; + }) => ReactElement[]; } \ No newline at end of file diff --git a/packages/types/src/shell/api/material.ts b/packages/types/src/shell/api/material.ts index d64455eddd..6354c7fa0f 100644 --- a/packages/types/src/shell/api/material.ts +++ b/packages/types/src/shell/api/material.ts @@ -1,4 +1,4 @@ -import { IPublicTypeAssetsJson, IPublicTypeMetadataTransducer, IPublicTypeComponentAction, IPublicTypeNpmInfo, IPublicTypeDisposable } from '../type'; +import { IPublicTypeAssetsJson, IPublicTypeMetadataTransducer, IPublicTypeComponentAction, IPublicTypeNpmInfo, IPublicTypeDisposable, IPublicTypeContextMenuAction, IPublicTypeContextMenuItem } from '../type'; import { IPublicModelComponentMeta } from '../model'; import { ComponentType } from 'react'; @@ -128,4 +128,22 @@ export interface IPublicApiMaterial { * @since v1.1.7 */ refreshComponentMetasMap(): void; + + /** + * 添加右键菜单项 + * @param action + */ + addContextMenuOption(action: IPublicTypeContextMenuAction): void; + + /** + * 删除特定右键菜单项 + * @param name + */ + removeContextMenuOption(name: string): void; + + /** + * 调整右键菜单项布局 + * @param actions + */ + adjustContextMenuLayout(fn: (actions: IPublicTypeContextMenuItem[]) => IPublicTypeContextMenuItem[]): void; } diff --git a/packages/types/src/shell/enum/context-menu.ts b/packages/types/src/shell/enum/context-menu.ts new file mode 100644 index 0000000000..fd209b1974 --- /dev/null +++ b/packages/types/src/shell/enum/context-menu.ts @@ -0,0 +1,7 @@ +export enum IPublicEnumContextMenuType { + SEPARATOR = 'separator', + // 'menuItem' + MENU_ITEM = 'menuItem', + // 'nodeTree' + NODE_TREE = 'nodeTree', +} \ No newline at end of file diff --git a/packages/types/src/shell/enum/index.ts b/packages/types/src/shell/enum/index.ts index f3d5580119..13282d0f2b 100644 --- a/packages/types/src/shell/enum/index.ts +++ b/packages/types/src/shell/enum/index.ts @@ -3,4 +3,5 @@ export * from './transition-type'; export * from './transform-stage'; export * from './drag-object-type'; export * from './prop-value-changed-type'; -export * from './plugin-register-level'; \ No newline at end of file +export * from './plugin-register-level'; +export * from './context-menu'; \ No newline at end of file diff --git a/packages/types/src/shell/type/context-menu.ts b/packages/types/src/shell/type/context-menu.ts new file mode 100644 index 0000000000..595893d32c --- /dev/null +++ b/packages/types/src/shell/type/context-menu.ts @@ -0,0 +1,57 @@ +import { IPublicEnumContextMenuType } from '../enum'; +import { IPublicModelNode } from '../model'; +import { IPublicTypeI18nData } from './i8n-data'; + +export interface IPublicTypeContextMenuItem extends Omit<IPublicTypeContextMenuAction, 'condition' | 'disabled' | 'items'> { + disabled?: boolean; + + items?: Omit<IPublicTypeContextMenuItem, 'items'>[]; +} + +export interface IPublicTypeContextMenuAction { + + /** + * 动作的唯一标识符 + * Unique identifier for the action + */ + name: string; + + /** + * 显示的标题,可以是字符串或国际化数据 + * Display title, can be a string or internationalized data + */ + title?: string | IPublicTypeI18nData; + + /** + * 菜单项类型 + * Menu item type + * @see IPublicEnumContextMenuType + * @default IPublicEnumPContextMenuType.MENU_ITEM + */ + type?: IPublicEnumContextMenuType; + + /** + * 点击时执行的动作,可选 + * Action to execute on click, optional + */ + action?: (nodes: IPublicModelNode[]) => void; + + /** + * 子菜单项或生成子节点的函数,可选,仅支持两级 + * Sub-menu items or function to generate child node, optional + */ + items?: Omit<IPublicTypeContextMenuAction, 'items'>[] | ((nodes: IPublicModelNode[]) => Omit<IPublicTypeContextMenuAction, 'items'>[]); + + /** + * 显示条件函数 + * Function to determine display condition + */ + condition?: (nodes: IPublicModelNode[]) => boolean; + + /** + * 禁用条件函数,可选 + * Function to determine disabled condition, optional + */ + disabled?: (nodes: IPublicModelNode[]) => boolean; +} + diff --git a/packages/types/src/shell/type/engine-options.ts b/packages/types/src/shell/type/engine-options.ts index 72078c8107..8221c4089c 100644 --- a/packages/types/src/shell/type/engine-options.ts +++ b/packages/types/src/shell/type/engine-options.ts @@ -178,6 +178,12 @@ export interface IPublicTypeEngineOptions { */ enableAutoOpenFirstWindow?: boolean; + /** + * @default false + * 开启右键菜单能力 + */ + enableContextMenu?: boolean; + /** * @default false * 隐藏设计器辅助层 diff --git a/packages/types/src/shell/type/index.ts b/packages/types/src/shell/type/index.ts index b2fd3313f9..b1c7779d05 100644 --- a/packages/types/src/shell/type/index.ts +++ b/packages/types/src/shell/type/index.ts @@ -91,4 +91,5 @@ export * from './hotkey-callback-config'; export * from './hotkey-callbacks'; export * from './scrollable'; export * from './simulator-renderer'; -export * from './config-transducer'; \ No newline at end of file +export * from './config-transducer'; +export * from './context-menu'; \ No newline at end of file diff --git a/packages/utils/src/context-menu.scss b/packages/utils/src/context-menu.scss new file mode 100644 index 0000000000..744eede873 --- /dev/null +++ b/packages/utils/src/context-menu.scss @@ -0,0 +1,33 @@ +.context-menu-tree-wrap { + position: relative; + padding: 4px 10px 4px 24px; +} + +.context-menu-tree-children { + margin-left: 8px; + line-height: 24px; +} + +.context-menu-tree-bg { + position: absolute; + left: 0; + right: 0; + cursor: pointer; +} + +.context-menu-tree-bg-inner { + position: absolute; + height: 24px; + top: -24px; + width: 100%; + + &:hover { + background-color: var(--color-block-background-light); + } +} + +.context-menu-tree-selected-icon { + position: absolute; + left: 10px; + color: var(--color-icon-active); +} \ No newline at end of file diff --git a/packages/utils/src/context-menu.tsx b/packages/utils/src/context-menu.tsx new file mode 100644 index 0000000000..3c7bb5d134 --- /dev/null +++ b/packages/utils/src/context-menu.tsx @@ -0,0 +1,138 @@ +import { Menu, Icon } from '@alifd/next'; +import { IDesigner } from '@alilc/lowcode-designer'; +import { IPublicEnumContextMenuType, IPublicModelNode, IPublicTypeContextMenuAction, IPublicTypeContextMenuItem } from '@alilc/lowcode-types'; +import { Logger } from '@alilc/lowcode-utils'; +import React from 'react'; +import './context-menu.scss'; + +const logger = new Logger({ level: 'warn', bizName: 'designer' }); +const { Item, Divider, PopupItem } = Menu; + +const MAX_LEVEL = 2; + +const Tree = (props: { + node?: IPublicModelNode; + children?: React.ReactNode; + options: { + nodes?: IPublicModelNode[] | null; + destroy?: Function; + designer?: IDesigner; + }; +}) => { + const { node } = props; + + if (!node) { + return null; + } + + if (!node.parent) { + return ( + <div className="context-menu-tree-wrap"> + <div className="context-menu-tree-children"> + {props.children} + </div> + </div> + ); + } + + const commonUI = props.options.designer?.editor?.get('commonUI'); + + const Title = commonUI?.Title; + + return ( + <Tree {...props} node={node.parent} > + {props.options.nodes?.[0].id === node.id ? (<Icon className="context-menu-tree-selected-icon" size="small" type="success" />) : null} + <Title title={node.title} /> + <div + className="context-menu-tree-children" + > + <div + className="context-menu-tree-bg" + onClick={() => { + props.options.destroy?.(); + node.select(); + }} + > + <div className="context-menu-tree-bg-inner" /> + </div> + { props.children } + </div> + </Tree> + ); +}; + +export function parseContextMenuAsReactNode(menus: IPublicTypeContextMenuItem[], options: { + nodes?: IPublicModelNode[] | null; + destroy?: Function; + designer?: IDesigner; +} = {}): React.ReactNode[] { + const children: React.ReactNode[] = []; + menus.forEach((menu, index) => { + if (menu.type === IPublicEnumContextMenuType.SEPARATOR) { + children.push(<Divider key={menu.name || index} />); + return; + } + + if (menu.type === IPublicEnumContextMenuType.MENU_ITEM) { + if (menu.items && menu.items.length) { + children.push(( + <PopupItem key={menu.name} label={menu.title}> + <Menu className="next-context engine-context-menu"> + { parseContextMenuAsReactNode(menu.items, options) } + </Menu> + </PopupItem> + )); + } else { + children.push((<Item disabled={menu.disabled} onClick={menu.action} key={menu.name}>{menu.title}</Item>)); + } + } + + if (menu.type === IPublicEnumContextMenuType.NODE_TREE) { + children.push(( + <Tree node={options.nodes?.[0]} options={options} /> + )); + } + }); + + return children; +} + +export function parseContextMenuProperties(menus: (IPublicTypeContextMenuAction | Omit<IPublicTypeContextMenuAction, 'items'>)[], options: { + nodes?: IPublicModelNode[] | null; + destroy?: Function; +}, level = 1): IPublicTypeContextMenuItem[] { + const { nodes, destroy } = options; + if (level > MAX_LEVEL) { + logger.warn('context menu level is too deep, please check your context menu config'); + return []; + } + + return menus.filter(menu => !menu.condition || (menu.condition && menu.condition(nodes || []))).map((menu) => { + const { + name, + title, + type = IPublicEnumContextMenuType.MENU_ITEM, + } = menu; + + const result: IPublicTypeContextMenuItem = { + name, + title, + type, + action: () => { + destroy?.(); + menu.action?.(nodes || []); + }, + disabled: menu.disabled && menu.disabled(nodes || []) || false, + }; + + if ('items' in menu && menu.items) { + result.items = parseContextMenuProperties( + typeof menu.items === 'function' ? menu.items(nodes || []) : menu.items, + options, + level + 1, + ); + } + + return result; + }); +} \ No newline at end of file diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index 3e37f46ba6..b99ab02073 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -31,3 +31,4 @@ export * as css from './css-helper'; export { transactionManager } from './transaction-manager'; export * from './check-types'; export * from './workspace'; +export * from './context-menu'; From 3f369e446d2c16f6c2aa88ee1c9d5f336ad37b71 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Mon, 8 Jan 2024 06:56:19 +0000 Subject: [PATCH 161/219] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 6659eaf853..3ef05af3cb 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.19", + "version": "1.2.20", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 6288ab9d60fe4e91475b685c7926c1adb971a935 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Mon, 8 Jan 2024 15:06:00 +0800 Subject: [PATCH 162/219] fix(docs): fix invalid doc content --- docs/docs/api/commonUI.md | 70 +++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/docs/docs/api/commonUI.md b/docs/docs/api/commonUI.md index ef7af7f415..82b57c3893 100644 --- a/docs/docs/api/commonUI.md +++ b/docs/docs/api/commonUI.md @@ -40,99 +40,99 @@ CommonUI API 是一个专为低代码引擎设计的组件 UI 库,使用它开 | 参数 | 说明 | 类型 | 默认值 | |------------|--------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------|----------------------------------------| -| name | 动作的唯一标识符<br>Unique identifier for the action | string | | -| title | 显示的标题,可以是字符串或国际化数据<br>Display title, can be a string or internationalized data | string \| IPublicTypeI18nData (optional) | | -| type | 菜单项类型<br>Menu item type | IPublicEnumContextMenuType (optional) | IPublicEnumPContextMenuType.MENU_ITEM | -| action | 点击时执行的动作,可选<br>Action to execute on click, optional | (nodes: IPublicModelNode[]) => void (optional) | | -| items | 子菜单项或生成子节点的函数,可选,仅支持两级<br>Sub-menu items or function to generate child node, optional | Omit<IPublicTypeContextMenuAction, 'items'>[] \| ((nodes: IPublicModelNode[]) => Omit<IPublicTypeContextMenuAction, 'items'>[]) (optional) | | -| condition | 显示条件函数<br>Function to determine display condition | (nodes: IPublicModelNode[]) => boolean (optional) | | -| disabled | 禁用条件函数,可选<br>Function to determine disabled condition, optional | (nodes: IPublicModelNode[]) => boolean (optional) | | +| name | 动作的唯一标识符<br/>Unique identifier for the action | string | | +| title | 显示的标题,可以是字符串或国际化数据<br/>Display title, can be a string or internationalized data | string \| IPublicTypeI18nData (optional) | | +| type | 菜单项类型<br/>Menu item type | IPublicEnumContextMenuType (optional) | IPublicEnumPContextMenuType.MENU_ITEM | +| action | 点击时执行的动作,可选<br/>Action to execute on click, optional | (nodes: IPublicModelNode[]) => void (optional) | | +| items | 子菜单项或生成子节点的函数,可选,仅支持两级<br/>Sub-menu items or function to generate child node, optional | Omit<IPublicTypeContextMenuAction, 'items'>[] \| ((nodes: IPublicModelNode[]) => Omit<IPublicTypeContextMenuAction, 'items'>[]) (optional) | | +| condition | 显示条件函数<br/>Function to determine display condition | (nodes: IPublicModelNode[]) => boolean (optional) | | +| disabled | 禁用条件函数,可选<br/>Function to determine disabled condition, optional | (nodes: IPublicModelNode[]) => boolean (optional) | | ### Balloon -详细文档: [Balloon Documentation](https://fusion.design/pc/component/balloon) +详细文档: [Balloon Documentation](https://fusion.design/pc/component/balloon) ### Breadcrumb -详细文档: [Breadcrumb Documentation](https://fusion.design/pc/component/breadcrumb) +详细文档: [Breadcrumb Documentation](https://fusion.design/pc/component/breadcrumb) ### Button -详细文档: [Button Documentation](https://fusion.design/pc/component/button) +详细文档: [Button Documentation](https://fusion.design/pc/component/button) ### Card -详细文档: [Card Documentation](https://fusion.design/pc/component/card) +详细文档:[Card Documentation](https://fusion.design/pc/component/card) ### Checkbox -详细文档: [Checkbox Documentation](https://fusion.design/pc/component/checkbox) +详细文档:[Checkbox Documentation](https://fusion.design/pc/component/checkbox) ### DatePicker -详细文档: [DatePicker Documentation](https://fusion.design/pc/component/datepicker) +详细文档:[DatePicker Documentation](https://fusion.design/pc/component/datepicker) ### Dialog -详细文档: [Dialog Documentation](https://fusion.design/pc/component/dialog) +详细文档:[Dialog Documentation](https://fusion.design/pc/component/dialog) ### Dropdown -详细文档: [Dropdown Documentation](https://fusion.design/pc/component/dropdown) +详细文档:[Dropdown Documentation](https://fusion.design/pc/component/dropdown) ### Form -详细文档: [Form Documentation](https://fusion.design/pc/component/form) +详细文档:[Form Documentation](https://fusion.design/pc/component/form) ### Icon -详细文档: [Icon Documentation](https://fusion.design/pc/component/icon) +详细文档:[Icon Documentation](https://fusion.design/pc/component/icon) 引擎默认主题支持的 icon 列表:https://fusion.design/64063/component/icon?themeid=20133 ### Input -详细文档: [Input Documentation](https://fusion.design/pc/component/input) +详细文档:[Input Documentation](https://fusion.design/pc/component/input) ### Loading -详细文档: [Loading Documentation](https://fusion.design/pc/component/loading) +详细文档:[Loading Documentation](https://fusion.design/pc/component/loading) ### Message -详细文档: [Message Documentation](https://fusion.design/pc/component/message) +详细文档:[Message Documentation](https://fusion.design/pc/component/message) ### Overlay -详细文档: [Overlay Documentation](https://fusion.design/pc/component/overlay) +详细文档:[Overlay Documentation](https://fusion.design/pc/component/overlay) ### Pagination -详细文档: [Pagination Documentation](https://fusion.design/pc/component/pagination) +详细文档:[Pagination Documentation](https://fusion.design/pc/component/pagination) ### Radio -详细文档: [Radio Documentation](https://fusion.design/pc/component/radio) +详细文档:[Radio Documentation](https://fusion.design/pc/component/radio) ### Search -详细文档: [Search Documentation](https://fusion.design/pc/component/search) +详细文档:[Search Documentation](https://fusion.design/pc/component/search) ### Select -详细文档: [Select Documentation](https://fusion.design/pc/component/select) +详细文档:[Select Documentation](https://fusion.design/pc/component/select) ### SplitButton -详细文档: [SplitButton Documentation](https://fusion.design/pc/component/splitbutton) +详细文档:[SplitButton Documentation](https://fusion.design/pc/component/splitbutton) ### Step -详细文档: [Step Documentation](https://fusion.design/pc/component/step) +详细文档:[Step Documentation](https://fusion.design/pc/component/step) ### Switch -详细文档: [Switch Documentation](https://fusion.design/pc/component/switch) +详细文档:[Switch Documentation](https://fusion.design/pc/component/switch) ### Tab -详细文档: [Tab Documentation](https://fusion.design/pc/component/tab) +详细文档:[Tab Documentation](https://fusion.design/pc/component/tab) ### Table -详细文档: [Table Documentation](https://fusion.design/pc/component/table) +详细文档:[Table Documentation](https://fusion.design/pc/component/table) ### Tree -详细文档: [Tree Documentation](https://fusion.design/pc/component/tree) +详细文档:[Tree Documentation](https://fusion.design/pc/component/tree) ### TreeSelect -详细文档: [TreeSelect Documentation](https://fusion.design/pc/component/treeselect) +详细文档:[TreeSelect Documentation](https://fusion.design/pc/component/treeselect) ### Upload -详细文档: [Upload Documentation](https://fusion.design/pc/component/upload) +详细文档:[Upload Documentation](https://fusion.design/pc/component/upload) ### Divider -详细文档: [Divider Documentation](https://fusion.design/pc/component/divider) +详细文档:[Divider Documentation](https://fusion.design/pc/component/divider) ## 说明 -如果需要其他组件,可以提issue给我们 \ No newline at end of file +如果需要其他组件,可以提 issue 给我们。 From 6ce381f60aa1deb714d3fbe52f6240f8d352f759 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Mon, 8 Jan 2024 07:06:58 +0000 Subject: [PATCH 163/219] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 3ef05af3cb..1f49ab6247 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.20", + "version": "1.2.21", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 6ded1a6384174b10b0069d9129bbc14d1a9daeb6 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 8 Jan 2024 18:48:06 +0800 Subject: [PATCH 164/219] chore: update CODEOWNERS --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index c2e49b783f..1000fca053 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -5,4 +5,4 @@ * @liujuping @JackLian /modules/material-parser @akirakai -/modules/code-generator @leoyuan +/modules/code-generator @qingniaotonghua From 8f0291fc3e58eaec2d786ff8e1854657208d5bde Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 8 Jan 2024 18:46:30 +0800 Subject: [PATCH 165/219] fix(context-menu): fix context menu bugs --- packages/designer/src/context-menu-actions.ts | 4 +++- .../engine/src/inner-plugins/default-context-menu.ts | 6 ++++++ packages/utils/src/context-menu.scss | 2 +- packages/utils/src/context-menu.tsx | 10 +--------- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/designer/src/context-menu-actions.ts b/packages/designer/src/context-menu-actions.ts index 053e4f0313..55a83ef2ff 100644 --- a/packages/designer/src/context-menu-actions.ts +++ b/packages/designer/src/context-menu-actions.ts @@ -17,6 +17,8 @@ export interface IContextMenuActions { adjustMenuLayout: IPublicApiMaterial['adjustContextMenuLayout']; } +let destroyFn: Function | undefined; + export class ContextMenuActions implements IContextMenuActions { actions: IPublicTypeContextMenuAction[] = []; @@ -55,7 +57,7 @@ export class ContextMenuActions implements IContextMenuActions { const { bounds } = designer.project.simulator?.viewport || { bounds: { left: 0, top: 0 } }; const { left: simulatorLeft, top: simulatorTop } = bounds; - let destroyFn: Function | undefined; + destroyFn?.(); const destroy = () => { destroyFn?.(); diff --git a/packages/engine/src/inner-plugins/default-context-menu.ts b/packages/engine/src/inner-plugins/default-context-menu.ts index 86feb17d97..50a86fcec8 100644 --- a/packages/engine/src/inner-plugins/default-context-menu.ts +++ b/packages/engine/src/inner-plugins/default-context-menu.ts @@ -87,6 +87,9 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { material.addContextMenuOption({ name: 'copy', title: intl('Copy.1'), + condition(nodes) { + return nodes.length > 0; + }, action(nodes) { if (!nodes || nodes.length < 1) { return; @@ -159,6 +162,9 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { material.addContextMenuOption({ name: 'delete', title: intl('Delete'), + condition(nodes) { + return nodes.length > 0; + }, action(nodes) { nodes.forEach((node) => { node.remove(); diff --git a/packages/utils/src/context-menu.scss b/packages/utils/src/context-menu.scss index 744eede873..0bcf39d153 100644 --- a/packages/utils/src/context-menu.scss +++ b/packages/utils/src/context-menu.scss @@ -1,6 +1,6 @@ .context-menu-tree-wrap { position: relative; - padding: 4px 10px 4px 24px; + padding: 4px 10px 4px 32px; } .context-menu-tree-children { diff --git a/packages/utils/src/context-menu.tsx b/packages/utils/src/context-menu.tsx index 3c7bb5d134..f65bc312f6 100644 --- a/packages/utils/src/context-menu.tsx +++ b/packages/utils/src/context-menu.tsx @@ -22,16 +22,8 @@ const Tree = (props: { const { node } = props; if (!node) { - return null; - } - - if (!node.parent) { return ( - <div className="context-menu-tree-wrap"> - <div className="context-menu-tree-children"> - {props.children} - </div> - </div> + <div className="context-menu-tree-wrap">{ props.children }</div> ); } From c381b85f0a48b215414e72c76864aa8b435fd443 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 9 Jan 2024 16:37:42 +0800 Subject: [PATCH 166/219] fix(context-menu): fix context menu bugs --- docs/docs/api/commonUI.md | 2 +- packages/designer/src/context-menu-actions.ts | 121 +++++++++++++++--- .../src/inner-plugins/default-context-menu.ts | 4 +- packages/engine/src/locale/en-US.json | 2 +- packages/engine/src/locale/zh-CN.json | 4 +- .../shell/src/components/context-menu.tsx | 16 ++- packages/types/src/shell/api/commonUI.ts | 4 +- packages/types/src/shell/type/context-menu.ts | 4 +- packages/utils/src/context-menu.tsx | 73 +++++++---- 9 files changed, 171 insertions(+), 59 deletions(-) diff --git a/docs/docs/api/commonUI.md b/docs/docs/api/commonUI.md index 82b57c3893..f3afe1fc25 100644 --- a/docs/docs/api/commonUI.md +++ b/docs/docs/api/commonUI.md @@ -42,7 +42,7 @@ CommonUI API 是一个专为低代码引擎设计的组件 UI 库,使用它开 |------------|--------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------|----------------------------------------| | name | 动作的唯一标识符<br/>Unique identifier for the action | string | | | title | 显示的标题,可以是字符串或国际化数据<br/>Display title, can be a string or internationalized data | string \| IPublicTypeI18nData (optional) | | -| type | 菜单项类型<br/>Menu item type | IPublicEnumContextMenuType (optional) | IPublicEnumPContextMenuType.MENU_ITEM | +| type | 菜单项类型<br/>Menu item type | IPublicEnumContextMenuType (optional) | IPublicEnumContextMenuType.MENU_ITEM | | action | 点击时执行的动作,可选<br/>Action to execute on click, optional | (nodes: IPublicModelNode[]) => void (optional) | | | items | 子菜单项或生成子节点的函数,可选,仅支持两级<br/>Sub-menu items or function to generate child node, optional | Omit<IPublicTypeContextMenuAction, 'items'>[] \| ((nodes: IPublicModelNode[]) => Omit<IPublicTypeContextMenuAction, 'items'>[]) (optional) | | | condition | 显示条件函数<br/>Function to determine display condition | (nodes: IPublicModelNode[]) => boolean (optional) | | diff --git a/packages/designer/src/context-menu-actions.ts b/packages/designer/src/context-menu-actions.ts index 55a83ef2ff..8c210d89e0 100644 --- a/packages/designer/src/context-menu-actions.ts +++ b/packages/designer/src/context-menu-actions.ts @@ -1,6 +1,6 @@ import { IPublicTypeContextMenuAction, IPublicEnumContextMenuType, IPublicTypeContextMenuItem, IPublicApiMaterial } from '@alilc/lowcode-types'; import { IDesigner, INode } from './designer'; -import { parseContextMenuAsReactNode, parseContextMenuProperties } from '@alilc/lowcode-utils'; +import { parseContextMenuAsReactNode, parseContextMenuProperties, uniqueId } from '@alilc/lowcode-utils'; import { Menu } from '@alifd/next'; import { engineConfig } from '@alilc/lowcode-editor-core'; import './context-menu-actions.scss'; @@ -17,7 +17,100 @@ export interface IContextMenuActions { adjustMenuLayout: IPublicApiMaterial['adjustContextMenuLayout']; } -let destroyFn: Function | undefined; +let adjustMenuLayoutFn: Function = (actions: IPublicTypeContextMenuAction[]) => actions; + +export class GlobalContextMenuActions { + enableContextMenu: boolean; + + dispose: Function[]; + + contextMenuActionsMap: Map<string, ContextMenuActions> = new Map(); + + constructor() { + this.dispose = []; + + engineConfig.onGot('enableContextMenu', (enable) => { + if (this.enableContextMenu === enable) { + return; + } + this.enableContextMenu = enable; + this.dispose.forEach(d => d()); + if (enable) { + this.initEvent(); + } + }); + } + + handleContextMenu = ( + event: MouseEvent, + ) => { + event.stopPropagation(); + event.preventDefault(); + + const actions: IPublicTypeContextMenuAction[] = []; + this.contextMenuActionsMap.forEach((contextMenu) => { + actions.push(...contextMenu.actions); + }); + + let destroyFn: Function | undefined; + + const destroy = () => { + destroyFn?.(); + }; + + const menus: IPublicTypeContextMenuItem[] = parseContextMenuProperties(actions, { + nodes: [], + destroy, + event, + }); + + if (!menus.length) { + return; + } + + const layoutMenu = adjustMenuLayoutFn(menus); + + const menuNode = parseContextMenuAsReactNode(layoutMenu, { + destroy, + nodes: [], + }); + + const target = event.target; + + const { top, left } = target?.getBoundingClientRect(); + + const menuInstance = Menu.create({ + target: event.target, + offset: [event.clientX - left, event.clientY - top], + children: menuNode, + className: 'engine-context-menu', + }); + + destroyFn = (menuInstance as any).destroy; + }; + + initEvent() { + this.dispose.push( + (() => { + const handleContextMenu = (e: MouseEvent) => { + this.handleContextMenu(e); + }; + + document.addEventListener('contextmenu', handleContextMenu); + + return () => { + document.removeEventListener('contextmenu', handleContextMenu); + }; + })(), + ); + } + + registerContextMenuActions(contextMenu: ContextMenuActions) { + this.contextMenuActionsMap.set(contextMenu.id, contextMenu); + } +} + +const globalContextMenuActions = new GlobalContextMenuActions(); export class ContextMenuActions implements IContextMenuActions { actions: IPublicTypeContextMenuAction[] = []; @@ -28,6 +121,8 @@ export class ContextMenuActions implements IContextMenuActions { enableContextMenu: boolean; + id: string = uniqueId('contextMenu');; + constructor(designer: IDesigner) { this.designer = designer; this.dispose = []; @@ -42,6 +137,8 @@ export class ContextMenuActions implements IContextMenuActions { this.initEvent(); } }); + + globalContextMenuActions.registerContextMenuActions(this); } handleContextMenu = ( @@ -57,7 +154,7 @@ export class ContextMenuActions implements IContextMenuActions { const { bounds } = designer.project.simulator?.viewport || { bounds: { left: 0, top: 0 } }; const { left: simulatorLeft, top: simulatorTop } = bounds; - destroyFn?.(); + let destroyFn: Function | undefined; const destroy = () => { destroyFn?.(); @@ -66,13 +163,14 @@ export class ContextMenuActions implements IContextMenuActions { const menus: IPublicTypeContextMenuItem[] = parseContextMenuProperties(actions, { nodes: nodes.map(d => designer.shellModelFactory.createNode(d)!), destroy, + event, }); if (!menus.length) { return; } - const layoutMenu = designer.contextMenuActions.adjustMenuLayoutFn(menus); + const layoutMenu = adjustMenuLayoutFn(menus); const menuNode = parseContextMenuAsReactNode(layoutMenu, { destroy, @@ -111,22 +209,9 @@ export class ContextMenuActions implements IContextMenuActions { const nodes = designer.currentSelection.getNodes(); this.handleContextMenu(nodes, originalEvent); }), - (() => { - const handleContextMenu = (e: MouseEvent) => { - this.handleContextMenu([], e); - }; - - document.addEventListener('contextmenu', handleContextMenu); - - return () => { - document.removeEventListener('contextmenu', handleContextMenu); - }; - })(), ); } - adjustMenuLayoutFn: (actions: IPublicTypeContextMenuItem[]) => IPublicTypeContextMenuItem[] = (actions) => actions; - addMenuAction(action: IPublicTypeContextMenuAction) { this.actions.push({ type: IPublicEnumContextMenuType.MENU_ITEM, @@ -142,6 +227,6 @@ export class ContextMenuActions implements IContextMenuActions { } adjustMenuLayout(fn: (actions: IPublicTypeContextMenuItem[]) => IPublicTypeContextMenuItem[]) { - this.adjustMenuLayoutFn = fn; + adjustMenuLayoutFn = fn; } } \ No newline at end of file diff --git a/packages/engine/src/inner-plugins/default-context-menu.ts b/packages/engine/src/inner-plugins/default-context-menu.ts index 50a86fcec8..fc1da96b4a 100644 --- a/packages/engine/src/inner-plugins/default-context-menu.ts +++ b/packages/engine/src/inner-plugins/default-context-menu.ts @@ -70,7 +70,7 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { material.addContextMenuOption({ name: 'copyAndPaste', - title: intl('Copy'), + title: intl('CopyAndPaste'), condition: (nodes) => { return nodes.length === 1; }, @@ -86,7 +86,7 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { material.addContextMenuOption({ name: 'copy', - title: intl('Copy.1'), + title: intl('Copy'), condition(nodes) { return nodes.length > 0; }, diff --git a/packages/engine/src/locale/en-US.json b/packages/engine/src/locale/en-US.json index 1cdb06f28b..e931607073 100644 --- a/packages/engine/src/locale/en-US.json +++ b/packages/engine/src/locale/en-US.json @@ -1,8 +1,8 @@ { "NotValidNodeData": "Not valid node data", "SelectComponents": "Select components", + "CopyAndPaste": "Copy and Paste", "Copy": "Copy", - "Copy.1": "Copy", "PasteToTheBottom": "Paste to the bottom", "PasteToTheInside": "Paste to the inside", "Delete": "Delete" diff --git a/packages/engine/src/locale/zh-CN.json b/packages/engine/src/locale/zh-CN.json index ba0f87f8e6..9b68b71490 100644 --- a/packages/engine/src/locale/zh-CN.json +++ b/packages/engine/src/locale/zh-CN.json @@ -1,8 +1,8 @@ { "NotValidNodeData": "不是有效的节点数据", "SelectComponents": "选择组件", - "Copy": "复制", - "Copy.1": "拷贝", + "CopyAndPaste": "复制", + "Copy": "拷贝", "PasteToTheBottom": "粘贴至下方", "PasteToTheInside": "粘贴至内部", "Delete": "删除" diff --git a/packages/shell/src/components/context-menu.tsx b/packages/shell/src/components/context-menu.tsx index 0085e1c777..f12f6ca93d 100644 --- a/packages/shell/src/components/context-menu.tsx +++ b/packages/shell/src/components/context-menu.tsx @@ -6,10 +6,12 @@ import React from 'react'; export function ContextMenu({ children, menus }: { menus: IPublicTypeContextMenuAction[]; - children: React.ReactElement[]; -}): React.ReactElement<any, string | React.JSXElementConstructor<any>>[] { + children: React.ReactElement[] | React.ReactElement; +}): React.ReactElement<any, string | React.JSXElementConstructor<any>> { if (!engineConfig.get('enableContextMenu')) { - return children; + return ( + <>{ children }</> + ); } const handleContextMenu = (event: React.MouseEvent) => { @@ -26,6 +28,10 @@ export function ContextMenu({ children, menus }: { destroy, })); + if (!children?.length) { + return; + } + const menuInstance = Menu.create({ target: event.target, offset: [event.clientX - left, event.clientY - top], @@ -42,5 +48,7 @@ export function ContextMenu({ children, menus }: { { onContextMenu: handleContextMenu }, )); - return childrenWithContextMenu; + return ( + <>{childrenWithContextMenu}</> + ); } \ No newline at end of file diff --git a/packages/types/src/shell/api/commonUI.ts b/packages/types/src/shell/api/commonUI.ts index dcc6fab0c3..71e2bbe83f 100644 --- a/packages/types/src/shell/api/commonUI.ts +++ b/packages/types/src/shell/api/commonUI.ts @@ -49,6 +49,6 @@ export interface IPublicApiCommonUI { get ContextMenu(): (props: { menus: IPublicTypeContextMenuAction[]; - children: React.ReactElement[]; - }) => ReactElement[]; + children: React.ReactElement[] | React.ReactElement; + }) => ReactElement; } \ No newline at end of file diff --git a/packages/types/src/shell/type/context-menu.ts b/packages/types/src/shell/type/context-menu.ts index 595893d32c..1eeb93d696 100644 --- a/packages/types/src/shell/type/context-menu.ts +++ b/packages/types/src/shell/type/context-menu.ts @@ -26,7 +26,7 @@ export interface IPublicTypeContextMenuAction { * 菜单项类型 * Menu item type * @see IPublicEnumContextMenuType - * @default IPublicEnumPContextMenuType.MENU_ITEM + * @default IPublicEnumContextMenuType.MENU_ITEM */ type?: IPublicEnumContextMenuType; @@ -34,7 +34,7 @@ export interface IPublicTypeContextMenuAction { * 点击时执行的动作,可选 * Action to execute on click, optional */ - action?: (nodes: IPublicModelNode[]) => void; + action?: (nodes: IPublicModelNode[], event?: MouseEvent) => void; /** * 子菜单项或生成子节点的函数,可选,仅支持两级 diff --git a/packages/utils/src/context-menu.tsx b/packages/utils/src/context-menu.tsx index f65bc312f6..f28619df61 100644 --- a/packages/utils/src/context-menu.tsx +++ b/packages/utils/src/context-menu.tsx @@ -89,42 +89,61 @@ export function parseContextMenuAsReactNode(menus: IPublicTypeContextMenuItem[], return children; } +let destroyFn: Function | undefined; export function parseContextMenuProperties(menus: (IPublicTypeContextMenuAction | Omit<IPublicTypeContextMenuAction, 'items'>)[], options: { nodes?: IPublicModelNode[] | null; destroy?: Function; + event?: MouseEvent; }, level = 1): IPublicTypeContextMenuItem[] { + destroyFn?.(); + destroyFn = options.destroy; + const { nodes, destroy } = options; if (level > MAX_LEVEL) { logger.warn('context menu level is too deep, please check your context menu config'); return []; } - return menus.filter(menu => !menu.condition || (menu.condition && menu.condition(nodes || []))).map((menu) => { - const { - name, - title, - type = IPublicEnumContextMenuType.MENU_ITEM, - } = menu; - - const result: IPublicTypeContextMenuItem = { - name, - title, - type, - action: () => { - destroy?.(); - menu.action?.(nodes || []); - }, - disabled: menu.disabled && menu.disabled(nodes || []) || false, - }; - - if ('items' in menu && menu.items) { - result.items = parseContextMenuProperties( - typeof menu.items === 'function' ? menu.items(nodes || []) : menu.items, - options, - level + 1, - ); - } + return menus + .filter(menu => !menu.condition || (menu.condition && menu.condition(nodes || []))) + .map((menu) => { + const { + name, + title, + type = IPublicEnumContextMenuType.MENU_ITEM, + } = menu; + + const result: IPublicTypeContextMenuItem = { + name, + title, + type, + action: () => { + destroy?.(); + menu.action?.(nodes || [], options.event); + }, + disabled: menu.disabled && menu.disabled(nodes || []) || false, + }; + + if ('items' in menu && menu.items) { + result.items = parseContextMenuProperties( + typeof menu.items === 'function' ? menu.items(nodes || []) : menu.items, + options, + level + 1, + ); + } - return result; - }); + return result; + }) + .reduce((menus: IPublicTypeContextMenuItem[], currentMenu: IPublicTypeContextMenuItem) => { + if (!currentMenu.name) { + return menus.concat([currentMenu]); + } + + const index = menus.find(item => item.name === currentMenu.name); + if (!index) { + return menus.concat([currentMenu]); + } else { + return menus; + } + }, []); } \ No newline at end of file From 14728476b65d5bdeaa7624df1b4a74850516d049 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Tue, 9 Jan 2024 08:43:50 +0000 Subject: [PATCH 167/219] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 1f49ab6247..e0fea44a14 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.21", + "version": "1.2.22", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 3627ae326a5b46e669d921e5b98e237a44e9bdea Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 10 Jan 2024 15:13:44 +0800 Subject: [PATCH 168/219] feat: optimize context menu details --- docs/docs/api/material.md | 37 ++++++++ packages/designer/src/context-menu-actions.ts | 16 +--- .../src/inner-plugins/default-context-menu.ts | 90 +++++++++++++++---- packages/engine/src/locale/index.ts | 4 +- .../shell/src/components/context-menu.tsx | 13 +-- packages/utils/src/context-menu.tsx | 55 +++++++++++- 6 files changed, 174 insertions(+), 41 deletions(-) diff --git a/docs/docs/api/material.md b/docs/docs/api/material.md index 51ed4e3054..c83935b971 100644 --- a/docs/docs/api/material.md +++ b/docs/docs/api/material.md @@ -237,6 +237,43 @@ material.modifyBuiltinComponentAction('remove', (action) => { }); ``` +### 右键菜单项 +#### addContextMenuOption + +添加右键菜单项 + +```typescript +/** + * 添加右键菜单项 + * @param action + */ +addContextMenuOption(action: IPublicTypeContextMenuAction): void; +``` + +#### removeContextMenuOption + +删除特定右键菜单项 + +```typescript +/** + * 删除特定右键菜单项 + * @param name + */ +removeContextMenuOption(name: string): void; +``` + +#### adjustContextMenuLayout + +调整右键菜单项布局,每次调用都会覆盖之前注册的调整函数,只有最后注册的函数会被应用。 + +```typescript +/** + * 调整右键菜单项布局 + * @param actions + */ +adjustContextMenuLayout(fn: (actions: IPublicTypeContextMenuItem[]) => IPublicTypeContextMenuItem[]): void; +``` + ### 物料元数据 #### getComponentMeta 获取指定名称的物料元数据 diff --git a/packages/designer/src/context-menu-actions.ts b/packages/designer/src/context-menu-actions.ts index 8c210d89e0..5b44055b42 100644 --- a/packages/designer/src/context-menu-actions.ts +++ b/packages/designer/src/context-menu-actions.ts @@ -1,6 +1,6 @@ import { IPublicTypeContextMenuAction, IPublicEnumContextMenuType, IPublicTypeContextMenuItem, IPublicApiMaterial } from '@alilc/lowcode-types'; import { IDesigner, INode } from './designer'; -import { parseContextMenuAsReactNode, parseContextMenuProperties, uniqueId } from '@alilc/lowcode-utils'; +import { createContextMenu, parseContextMenuAsReactNode, parseContextMenuProperties, uniqueId } from '@alilc/lowcode-utils'; import { Menu } from '@alifd/next'; import { engineConfig } from '@alilc/lowcode-editor-core'; import './context-menu-actions.scss'; @@ -178,18 +178,10 @@ export class ContextMenuActions implements IContextMenuActions { designer, }); - const target = event.target; - - const { top, left } = target?.getBoundingClientRect(); - - const menuInstance = Menu.create({ - target: event.target, - offset: [event.clientX - left + simulatorLeft, event.clientY - top + simulatorTop], - children: menuNode, - className: 'engine-context-menu', + destroyFn = createContextMenu(menuNode, { + event, + offset: [simulatorLeft, simulatorTop], }); - - destroyFn = (menuInstance as any).destroy; }; initEvent() { diff --git a/packages/engine/src/inner-plugins/default-context-menu.ts b/packages/engine/src/inner-plugins/default-context-menu.ts index fc1da96b4a..9d1336b34e 100644 --- a/packages/engine/src/inner-plugins/default-context-menu.ts +++ b/packages/engine/src/inner-plugins/default-context-menu.ts @@ -1,13 +1,16 @@ import { IPublicEnumContextMenuType, + IPublicEnumDragObjectType, IPublicEnumTransformStage, IPublicModelNode, IPublicModelPluginContext, + IPublicTypeDragNodeDataObject, + IPublicTypeI18nData, IPublicTypeNodeSchema, } from '@alilc/lowcode-types'; -import { isProjectSchema } from '@alilc/lowcode-utils'; +import { isI18nData, isProjectSchema } from '@alilc/lowcode-utils'; import { Notification } from '@alifd/next'; -import { intl } from '../locale'; +import { intl, getLocale } from '../locale'; function getNodesSchema(nodes: IPublicModelNode[]) { const componentsTree = nodes.map((node) => node?.exportSchema(IPublicEnumTransformStage.Clone)); @@ -15,6 +18,15 @@ function getNodesSchema(nodes: IPublicModelNode[]) { return data; } +function getIntlStr(data: string | IPublicTypeI18nData) { + if (!isI18nData(data)) { + return data; + } + + const locale = getLocale(); + return data[locale] || data['zh-CN'] || data['zh_CN'] || data['en-US'] || data['en_US'] || ''; +} + async function getClipboardText(): Promise<IPublicTypeNodeSchema[]> { return new Promise((resolve, reject) => { // 使用 Clipboard API 读取剪贴板内容 @@ -71,12 +83,18 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { material.addContextMenuOption({ name: 'copyAndPaste', title: intl('CopyAndPaste'), + disabled: (nodes) => { + return nodes?.filter((node) => !node?.canPerformAction('copy')).length > 0; + }, condition: (nodes) => { return nodes.length === 1; }, action(nodes) { const node = nodes[0]; const { document: doc, parent, index } = node; + const data = getNodesSchema(nodes); + clipboard.setData(data); + if (parent) { const newNode = doc?.insertNode(parent, node, (index ?? 0) + 1, true); newNode?.select(); @@ -87,6 +105,9 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { material.addContextMenuOption({ name: 'copy', title: intl('Copy'), + disabled: (nodes) => { + return nodes?.filter((node) => !node?.canPerformAction('copy')).length > 0; + }, condition(nodes) { return nodes.length > 0; }, @@ -101,7 +122,7 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { }); material.addContextMenuOption({ - name: 'zhantieToBottom', + name: 'pasteToBottom', title: intl('PasteToTheBottom'), condition: (nodes) => { return nodes.length === 1; @@ -116,10 +137,30 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { try { const nodeSchema = await getClipboardText(); + if (nodeSchema.length === 0) { + return; + } if (parent) { - nodeSchema.forEach((schema, schemaIndex) => { - doc?.insertNode(parent, schema, (index ?? 0) + 1 + schemaIndex, true); + let canAddNodes = nodeSchema.filter((nodeSchema: IPublicTypeNodeSchema) => { + const dragNodeObject: IPublicTypeDragNodeDataObject = { + type: IPublicEnumDragObjectType.NodeData, + data: nodeSchema, + }; + return doc?.checkNesting(parent, dragNodeObject); + }); + if (canAddNodes.length === 0) { + Notification.open({ + content: `${nodeSchema.map(d => getIntlStr(d.title || d.componentName)).join(',')}等组件无法放置到${getIntlStr(parent.title || parent.componentName as any)}内`, + type: 'error', + }); + return; + } + const nodes: IPublicModelNode[] = []; + canAddNodes.forEach((schema, schemaIndex) => { + const node = doc?.insertNode(parent, schema, (index ?? 0) + 1 + schemaIndex, true); + node && nodes.push(node); }); + doc?.selection.selectAll(nodes.map((node) => node?.id)); } } catch (error) { console.error(error); @@ -128,7 +169,7 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { }); material.addContextMenuOption({ - name: 'zhantieToInner', + name: 'pasteToInner', title: intl('PasteToTheInside'), condition: (nodes) => { return nodes.length === 1; @@ -140,19 +181,35 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { }, async action(nodes) { const node = nodes[0]; - const { document: doc, parent } = node; + const { document: doc } = node; try { const nodeSchema = await getClipboardText(); - if (parent) { - const index = node.children?.size || 0; - - if (parent) { - nodeSchema.forEach((schema, schemaIndex) => { - doc?.insertNode(node, schema, (index ?? 0) + 1 + schemaIndex, true); - }); - } + const index = node.children?.size || 0; + if (nodeSchema.length === 0) { + return; } + let canAddNodes = nodeSchema.filter((nodeSchema: IPublicTypeNodeSchema) => { + const dragNodeObject: IPublicTypeDragNodeDataObject = { + type: IPublicEnumDragObjectType.NodeData, + data: nodeSchema, + }; + return doc?.checkNesting(node, dragNodeObject); + }); + if (canAddNodes.length === 0) { + Notification.open({ + content: `${nodeSchema.map(d => getIntlStr(d.title || d.componentName)).join(',')}等组件无法放置到${getIntlStr(node.title || node.componentName as any)}内`, + type: 'error', + }); + return; + } + + const nodes: IPublicModelNode[] = []; + nodeSchema.forEach((schema, schemaIndex) => { + const newNode = doc?.insertNode(node, schema, (index ?? 0) + 1 + schemaIndex, true); + newNode && nodes.push(newNode); + }); + doc?.selection.selectAll(nodes.map((node) => node?.id)); } catch (error) { console.error(error); } @@ -162,6 +219,9 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { material.addContextMenuOption({ name: 'delete', title: intl('Delete'), + disabled(nodes) { + return nodes?.filter((node) => !node?.canPerformAction('remove')).length > 0; + }, condition(nodes) { return nodes.length > 0; }, diff --git a/packages/engine/src/locale/index.ts b/packages/engine/src/locale/index.ts index 510fcf056a..ca89840b05 100644 --- a/packages/engine/src/locale/index.ts +++ b/packages/engine/src/locale/index.ts @@ -2,7 +2,7 @@ import { createIntl } from '@alilc/lowcode-editor-core'; import enUS from './en-US.json'; import zhCN from './zh-CN.json'; -const { intl } = createIntl?.({ +const { intl, getLocale } = createIntl?.({ 'en-US': enUS, 'zh-CN': zhCN, }) || { @@ -11,4 +11,4 @@ const { intl } = createIntl?.({ }, }; -export { intl, enUS, zhCN }; +export { intl, enUS, zhCN, getLocale }; diff --git a/packages/shell/src/components/context-menu.tsx b/packages/shell/src/components/context-menu.tsx index f12f6ca93d..acefbebd28 100644 --- a/packages/shell/src/components/context-menu.tsx +++ b/packages/shell/src/components/context-menu.tsx @@ -1,5 +1,4 @@ -import { Menu } from '@alifd/next'; -import { parseContextMenuAsReactNode, parseContextMenuProperties } from '@alilc/lowcode-utils'; +import { createContextMenu, parseContextMenuAsReactNode, parseContextMenuProperties } from '@alilc/lowcode-utils'; import { engineConfig } from '@alilc/lowcode-editor-core'; import { IPublicTypeContextMenuAction } from '@alilc/lowcode-types'; import React from 'react'; @@ -18,8 +17,6 @@ export function ContextMenu({ children, menus }: { event.preventDefault(); event.stopPropagation(); - const target = event.target; - const { top, left } = target?.getBoundingClientRect(); let destroyFn: Function | undefined; const destroy = () => { destroyFn?.(); @@ -32,13 +29,9 @@ export function ContextMenu({ children, menus }: { return; } - const menuInstance = Menu.create({ - target: event.target, - offset: [event.clientX - left, event.clientY - top], - children, + destroyFn = createContextMenu(children, { + event, }); - - destroyFn = (menuInstance as any).destroy; }; // 克隆 children 并添加 onContextMenu 事件处理器 diff --git a/packages/utils/src/context-menu.tsx b/packages/utils/src/context-menu.tsx index f28619df61..1816f5b526 100644 --- a/packages/utils/src/context-menu.tsx +++ b/packages/utils/src/context-menu.tsx @@ -53,6 +53,8 @@ const Tree = (props: { ); }; +let destroyFn: Function | undefined; + export function parseContextMenuAsReactNode(menus: IPublicTypeContextMenuItem[], options: { nodes?: IPublicModelNode[] | null; destroy?: Function; @@ -89,14 +91,12 @@ export function parseContextMenuAsReactNode(menus: IPublicTypeContextMenuItem[], return children; } -let destroyFn: Function | undefined; export function parseContextMenuProperties(menus: (IPublicTypeContextMenuAction | Omit<IPublicTypeContextMenuAction, 'items'>)[], options: { nodes?: IPublicModelNode[] | null; destroy?: Function; event?: MouseEvent; }, level = 1): IPublicTypeContextMenuItem[] { destroyFn?.(); - destroyFn = options.destroy; const { nodes, destroy } = options; if (level > MAX_LEVEL) { @@ -146,4 +146,55 @@ export function parseContextMenuProperties(menus: (IPublicTypeContextMenuAction return menus; } }, []); +} + +let cachedMenuItemHeight: string | undefined; + +function getMenuItemHeight() { + if (cachedMenuItemHeight) { + return cachedMenuItemHeight; + } + const root = document.documentElement; + const styles = getComputedStyle(root); + // Access the value of the CSS variable + const menuItemHeight = styles.getPropertyValue('--context-menu-item-height').trim(); + cachedMenuItemHeight = menuItemHeight; + + return menuItemHeight; +} + +export function createContextMenu(children: React.ReactNode[], { + event, + offset = [0, 0], +}: { + event: MouseEvent | React.MouseEvent; + offset?: [number, number]; +}) { + const viewportWidth = window.innerWidth; + const viewportHeight = window.innerHeight; + const dividerCount = React.Children.count(children.filter(child => React.isValidElement(child) && child.type === Divider)); + const popupItemCount = React.Children.count(children.filter(child => React.isValidElement(child) && (child.type === PopupItem || child.type === Item))); + const menuHeight = popupItemCount * parseInt(getMenuItemHeight(), 10) + dividerCount * 8 + 16; + const menuWidthLimit = 200; + const target = event.target; + const { top, left } = (target as any)?.getBoundingClientRect(); + let x = event.clientX - left + offset[0]; + let y = event.clientY - top + offset[1]; + if (x + menuWidthLimit + left > viewportWidth) { + x = x - menuWidthLimit; + } + if (y + menuHeight + top > viewportHeight) { + y = y - menuHeight; + } + + const menuInstance = Menu.create({ + target, + offset: [x, y, 0, 0], + children, + className: 'engine-context-menu', + }); + + destroyFn = (menuInstance as any).destroy; + + return destroyFn; } \ No newline at end of file From a00c5c9b607f1e1597c1ed3b985b6f4249b11a68 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Wed, 10 Jan 2024 07:21:10 +0000 Subject: [PATCH 169/219] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index e0fea44a14..d1c3cd9f90 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.22", + "version": "1.2.23", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From a7d3996fa2eaccd883eb554677d6c15af6134978 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 11 Jan 2024 10:37:12 +0800 Subject: [PATCH 170/219] feat(common): add common.utils.intl API --- docs/docs/api/common.md | 16 ++++++++++++++++ packages/editor-core/src/intl/index.ts | 12 ++---------- packages/shell/src/api/common.tsx | 5 +++++ packages/types/src/shell/api/common.ts | 7 ++++++- 4 files changed, 29 insertions(+), 11 deletions(-) diff --git a/docs/docs/api/common.md b/docs/docs/api/common.md index 966e2277f2..6613547ea9 100644 --- a/docs/docs/api/common.md +++ b/docs/docs/api/common.md @@ -145,6 +145,22 @@ const { intl, getLocale, setLocale } = common.utils.createIntl({ ``` +#### intl + +i18n 转换方法 + +```typescript +/** + * i18n 转换方法 + */ +intl(data: IPublicTypeI18nData | string, params?: object): string; +``` + +##### 示例 +``` +const title = common.utils.intl(node.title) +``` + ### skeletonCabin #### Workbench 编辑器框架 View diff --git a/packages/editor-core/src/intl/index.ts b/packages/editor-core/src/intl/index.ts index 6d9d840c3c..99e99a4fb9 100644 --- a/packages/editor-core/src/intl/index.ts +++ b/packages/editor-core/src/intl/index.ts @@ -3,6 +3,7 @@ import { IntlMessageFormat } from 'intl-messageformat'; import { globalLocale } from './global-locale'; import { isI18nData } from '@alilc/lowcode-utils'; import { observer } from '../utils'; +import { IPublicTypeI18nData } from '@alilc/lowcode-types'; function generateTryLocales(locale: string) { const tries = [locale, locale.replace('-', '_')]; @@ -26,18 +27,9 @@ function injectVars(msg: string, params: any, locale: string): string { } const formater = new IntlMessageFormat(msg, locale); return formater.format(params as any) as string; - /* - - return template.replace(/({\w+})/g, (_, $1) => { - const key = (/\d+/.exec($1) || [])[0] as any; - if (key && params[key] != null) { - return params[key]; - } - return $1; - }); */ } -export function intl(data: any, params?: object): ReactNode { +export function intl(data: IPublicTypeI18nData | string, params?: object): ReactNode { if (!isI18nData(data)) { return data; } diff --git a/packages/shell/src/api/common.tsx b/packages/shell/src/api/common.tsx index a2e4d8c4fa..8ce07153ad 100644 --- a/packages/shell/src/api/common.tsx +++ b/packages/shell/src/api/common.tsx @@ -26,6 +26,7 @@ import { IPublicApiCommonEditorCabin, IPublicModelDragon, IPublicModelSettingField, + IPublicTypeI18nData, } from '@alilc/lowcode-types'; import { SettingField as InnerSettingField, @@ -261,6 +262,10 @@ class Utils implements IPublicApiCommonUtils { } { return innerCreateIntl(instance); } + + intl(data: IPublicTypeI18nData | string, params?: object): any { + return innerIntl(data, params); + } } class EditorCabin implements IPublicApiCommonEditorCabin { diff --git a/packages/types/src/shell/api/common.ts b/packages/types/src/shell/api/common.ts index 60fac1606d..05ef0da17f 100644 --- a/packages/types/src/shell/api/common.ts +++ b/packages/types/src/shell/api/common.ts @@ -1,6 +1,6 @@ import { Component, ReactNode } from 'react'; -import { IPublicTypeNodeSchema, IPublicTypeTitleContent } from '../type'; +import { IPublicTypeI18nData, IPublicTypeNodeSchema, IPublicTypeTitleContent } from '../type'; import { IPublicEnumTransitionType } from '../enum'; export interface IPublicApiCommonUtils { @@ -69,6 +69,11 @@ export interface IPublicApiCommonUtils { getLocale(): string; setLocale(locale: string): void; }; + + /** + * i18n 转换方法 + */ + intl(data: IPublicTypeI18nData | string, params?: object): string; } export interface IPublicApiCommonSkeletonCabin { From 3e7d199a7c3f1df2d813cafcb8109f24125ab4c7 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Thu, 11 Jan 2024 02:50:04 +0000 Subject: [PATCH 171/219] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index d1c3cd9f90..80396a0146 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.23", + "version": "1.2.24", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From bb5d7ddf827be5e72707cd1e5ccdf09f6ae16cc1 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 11 Jan 2024 10:59:44 +0800 Subject: [PATCH 172/219] feat(context-menu): update context-menu docs, details, styles --- docs/docs/api/commonUI.md | 62 +++++++++++++ docs/docs/api/material.md | 46 +++++++++ packages/designer/src/context-menu-actions.ts | 11 ++- packages/engine/src/engine-core.ts | 4 +- .../src/inner-plugins/default-context-menu.ts | 21 ++--- .../src/api/{commonUI.ts => commonUI.tsx} | 24 ++++- .../shell/src/components/context-menu.tsx | 28 +++++- packages/utils/src/context-menu.scss | 36 ++++--- packages/utils/src/context-menu.tsx | 93 ++++++++++++------- .../workspace/src/context/base-context.ts | 4 +- 10 files changed, 254 insertions(+), 75 deletions(-) rename packages/shell/src/api/{commonUI.ts => commonUI.tsx} (56%) diff --git a/docs/docs/api/commonUI.md b/docs/docs/api/commonUI.md index f3afe1fc25..350d60dd7a 100644 --- a/docs/docs/api/commonUI.md +++ b/docs/docs/api/commonUI.md @@ -48,8 +48,70 @@ CommonUI API 是一个专为低代码引擎设计的组件 UI 库,使用它开 | condition | 显示条件函数<br/>Function to determine display condition | (nodes: IPublicModelNode[]) => boolean (optional) | | | disabled | 禁用条件函数,可选<br/>Function to determine disabled condition, optional | (nodes: IPublicModelNode[]) => boolean (optional) | | +**ContextMenu 示例** + +```typescript +const App = () => { + const menuItems: IPublicTypeContextMenuAction[] = [ + { + name: 'a', + title: '选项 1', + action: () => console.log('选项 1 被点击'), + }, + { + name: 'b', + title: '选项 2', + action: () => console.log('选项 2 被点击'), + }, + ]; + + const ContextMenu = ctx.commonUI.ContextMenu; + + return ( + <div> + <ContextMenu menus={menuItems}> + <div>右键点击这里</div> + </ContextMenu> + </div> + ); +}; + +export default App; +``` + +**ContextMenu.create 示例** + +```typescript +const App = () => { + const menuItems: IPublicTypeContextMenuAction[] = [ + { + name: 'a', + title: '选项 1', + action: () => console.log('选项 1 被点击'), + }, + { + name: 'b', + title: '选项 2', + action: () => console.log('选项 2 被点击'), + }, + ]; + + const ContextMenu = ctx.commonUI.ContextMenu; + + return ( + <div> + <div onClick={(e) => { + ContextMenu.create(menuItems, e); + }}>点击这里</div> + </div> + ); +}; + +export default App; +``` ### Balloon + 详细文档: [Balloon Documentation](https://fusion.design/pc/component/balloon) ### Breadcrumb diff --git a/docs/docs/api/material.md b/docs/docs/api/material.md index c83935b971..d237180ca9 100644 --- a/docs/docs/api/material.md +++ b/docs/docs/api/material.md @@ -250,6 +250,33 @@ material.modifyBuiltinComponentAction('remove', (action) => { addContextMenuOption(action: IPublicTypeContextMenuAction): void; ``` +示例 + +```typescript +import { IPublicEnumContextMenuType } from '@alilc/lowcode-types'; + +material.addContextMenuOption({ + name: 'parentItem', + title: 'Parent Item', + condition: (nodes) => true, + items: [ + { + name: 'childItem1', + title: 'Child Item 1', + action: (nodes) => console.log('Child Item 1 clicked', nodes), + condition: (nodes) => true + }, + // 分割线 + { + type: IPublicEnumContextMenuType.SEPARATOR + name: 'separator.1' + } + // 更多子菜单项... + ] +}); + +``` + #### removeContextMenuOption 删除特定右键菜单项 @@ -274,7 +301,26 @@ removeContextMenuOption(name: string): void; adjustContextMenuLayout(fn: (actions: IPublicTypeContextMenuItem[]) => IPublicTypeContextMenuItem[]): void; ``` +**示例** + +通过 adjustContextMenuLayout 补充分割线 + +```typescript +material.adjustContextMenuLayout((actions: IPublicTypeContextMenuAction) => { + const names = ['a', 'b']; + const newActions = []; + actions.forEach(d => { + newActions.push(d); + if (names.include(d.name)) { + newActions.push({ type: 'separator' }) + } + }); + return newActions +}) +``` + ### 物料元数据 + #### getComponentMeta 获取指定名称的物料元数据 diff --git a/packages/designer/src/context-menu-actions.ts b/packages/designer/src/context-menu-actions.ts index 5b44055b42..c3bad37da5 100644 --- a/packages/designer/src/context-menu-actions.ts +++ b/packages/designer/src/context-menu-actions.ts @@ -1,4 +1,4 @@ -import { IPublicTypeContextMenuAction, IPublicEnumContextMenuType, IPublicTypeContextMenuItem, IPublicApiMaterial } from '@alilc/lowcode-types'; +import { IPublicTypeContextMenuAction, IPublicEnumContextMenuType, IPublicTypeContextMenuItem, IPublicApiMaterial, IPublicModelPluginContext } from '@alilc/lowcode-types'; import { IDesigner, INode } from './designer'; import { createContextMenu, parseContextMenuAsReactNode, parseContextMenuProperties, uniqueId } from '@alilc/lowcode-utils'; import { Menu } from '@alifd/next'; @@ -48,6 +48,7 @@ export class GlobalContextMenuActions { event.preventDefault(); const actions: IPublicTypeContextMenuAction[] = []; + let contextMenu: ContextMenuActions = this.contextMenuActionsMap.values().next().value; this.contextMenuActionsMap.forEach((contextMenu) => { actions.push(...contextMenu.actions); }); @@ -57,11 +58,13 @@ export class GlobalContextMenuActions { const destroy = () => { destroyFn?.(); }; + const pluginContext: IPublicModelPluginContext = contextMenu.designer.editor.get('pluginContext') as IPublicModelPluginContext; const menus: IPublicTypeContextMenuItem[] = parseContextMenuProperties(actions, { nodes: [], destroy, event, + pluginContext, }); if (!menus.length) { @@ -73,6 +76,7 @@ export class GlobalContextMenuActions { const menuNode = parseContextMenuAsReactNode(layoutMenu, { destroy, nodes: [], + pluginContext, }); const target = event.target; @@ -160,10 +164,13 @@ export class ContextMenuActions implements IContextMenuActions { destroyFn?.(); }; + const pluginContext: IPublicModelPluginContext = this.designer.editor.get('pluginContext') as IPublicModelPluginContext; + const menus: IPublicTypeContextMenuItem[] = parseContextMenuProperties(actions, { nodes: nodes.map(d => designer.shellModelFactory.createNode(d)!), destroy, event, + pluginContext, }); if (!menus.length) { @@ -175,7 +182,7 @@ export class ContextMenuActions implements IContextMenuActions { const menuNode = parseContextMenuAsReactNode(layoutMenu, { destroy, nodes: nodes.map(d => designer.shellModelFactory.createNode(d)!), - designer, + pluginContext, }); destroyFn = createContextMenu(menuNode, { diff --git a/packages/engine/src/engine-core.ts b/packages/engine/src/engine-core.ts index 29b4a7f038..3ccfdf51d1 100644 --- a/packages/engine/src/engine-core.ts +++ b/packages/engine/src/engine-core.ts @@ -115,12 +115,11 @@ const innerSetters = new InnerSetters(); const setters = new Setters(innerSetters); const material = new Material(editor); -const commonUI = new CommonUI(); +const commonUI = new CommonUI(editor); editor.set('project', project); editor.set('setters' as any, setters); editor.set('material', material); editor.set('innerHotkey', innerHotkey); -editor.set('commonUI' as any, commonUI); const config = new Config(engineConfig); const event = new Event(commonEvent, { prefix: 'common' }); const logger = new Logger({ level: 'warn', bizName: 'common' }); @@ -147,6 +146,7 @@ const pluginContextApiAssembler: ILowCodePluginContextApiAssembler = { context.commonUI = commonUI; context.registerLevel = IPublicEnumPluginRegisterLevel.Default; context.isPluginRegisteredInWorkspace = false; + editor.set('pluginContext', context); }, }; diff --git a/packages/engine/src/inner-plugins/default-context-menu.ts b/packages/engine/src/inner-plugins/default-context-menu.ts index 9d1336b34e..db3d54a0c8 100644 --- a/packages/engine/src/inner-plugins/default-context-menu.ts +++ b/packages/engine/src/inner-plugins/default-context-menu.ts @@ -5,12 +5,11 @@ import { IPublicModelNode, IPublicModelPluginContext, IPublicTypeDragNodeDataObject, - IPublicTypeI18nData, IPublicTypeNodeSchema, } from '@alilc/lowcode-types'; -import { isI18nData, isProjectSchema } from '@alilc/lowcode-utils'; +import { isProjectSchema } from '@alilc/lowcode-utils'; import { Notification } from '@alifd/next'; -import { intl, getLocale } from '../locale'; +import { intl } from '../locale'; function getNodesSchema(nodes: IPublicModelNode[]) { const componentsTree = nodes.map((node) => node?.exportSchema(IPublicEnumTransformStage.Clone)); @@ -18,15 +17,6 @@ function getNodesSchema(nodes: IPublicModelNode[]) { return data; } -function getIntlStr(data: string | IPublicTypeI18nData) { - if (!isI18nData(data)) { - return data; - } - - const locale = getLocale(); - return data[locale] || data['zh-CN'] || data['zh_CN'] || data['en-US'] || data['en_US'] || ''; -} - async function getClipboardText(): Promise<IPublicTypeNodeSchema[]> { return new Promise((resolve, reject) => { // 使用 Clipboard API 读取剪贴板内容 @@ -61,8 +51,9 @@ async function getClipboardText(): Promise<IPublicTypeNodeSchema[]> { } export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { - const { material, canvas } = ctx; + const { material, canvas, common } = ctx; const { clipboard } = canvas; + const { intl: utilsIntl } = common.utils; return { init() { @@ -150,7 +141,7 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { }); if (canAddNodes.length === 0) { Notification.open({ - content: `${nodeSchema.map(d => getIntlStr(d.title || d.componentName)).join(',')}等组件无法放置到${getIntlStr(parent.title || parent.componentName as any)}内`, + content: `${nodeSchema.map(d => utilsIntl(d.title || d.componentName)).join(',')}等组件无法放置到${utilsIntl(parent.title || parent.componentName as any)}内`, type: 'error', }); return; @@ -198,7 +189,7 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { }); if (canAddNodes.length === 0) { Notification.open({ - content: `${nodeSchema.map(d => getIntlStr(d.title || d.componentName)).join(',')}等组件无法放置到${getIntlStr(node.title || node.componentName as any)}内`, + content: `${nodeSchema.map(d => utilsIntl(d.title || d.componentName)).join(',')}等组件无法放置到${utilsIntl(node.title || node.componentName as any)}内`, type: 'error', }); return; diff --git a/packages/shell/src/api/commonUI.ts b/packages/shell/src/api/commonUI.tsx similarity index 56% rename from packages/shell/src/api/commonUI.ts rename to packages/shell/src/api/commonUI.tsx index 9f40afa119..cb4b7ae38e 100644 --- a/packages/shell/src/api/commonUI.ts +++ b/packages/shell/src/api/commonUI.tsx @@ -1,12 +1,16 @@ -import { IPublicApiCommonUI } from '@alilc/lowcode-types'; +import { IPublicApiCommonUI, IPublicModelPluginContext, IPublicTypeContextMenuAction } from '@alilc/lowcode-types'; import { + IEditor, Tip as InnerTip, Title as InnerTitle, } from '@alilc/lowcode-editor-core'; import { Balloon, Breadcrumb, Button, Card, Checkbox, DatePicker, Dialog, Dropdown, Form, Icon, Input, Loading, Message, Overlay, Pagination, Radio, Search, Select, SplitButton, Step, Switch, Tab, Table, Tree, TreeSelect, Upload, Divider } from '@alifd/next'; import { ContextMenu } from '../components/context-menu'; +import { editorSymbol } from '../symbols'; export class CommonUI implements IPublicApiCommonUI { + [editorSymbol]: IEditor; + Balloon = Balloon; Breadcrumb = Breadcrumb; Button = Button; @@ -35,13 +39,29 @@ export class CommonUI implements IPublicApiCommonUI { Upload = Upload; Divider = Divider; + constructor(editor: IEditor) { + this[editorSymbol] = editor; + } + get Tip() { return InnerTip; } get Title() { return InnerTitle; } + get ContextMenu() { - return ContextMenu; + const editor = this[editorSymbol]; + const innerContextMenu = (props: any) => { + const pluginContext: IPublicModelPluginContext = editor.get('pluginContext') as IPublicModelPluginContext; + return <ContextMenu {...props} pluginContext={pluginContext} />; + }; + + innerContextMenu.create = (menus: IPublicTypeContextMenuAction[], event: MouseEvent) => { + const pluginContext: IPublicModelPluginContext = editor.get('pluginContext') as IPublicModelPluginContext; + return ContextMenu.create(pluginContext, menus, event); + }; + + return innerContextMenu; } } diff --git a/packages/shell/src/components/context-menu.tsx b/packages/shell/src/components/context-menu.tsx index acefbebd28..d2e10abbfe 100644 --- a/packages/shell/src/components/context-menu.tsx +++ b/packages/shell/src/components/context-menu.tsx @@ -1,11 +1,12 @@ import { createContextMenu, parseContextMenuAsReactNode, parseContextMenuProperties } from '@alilc/lowcode-utils'; import { engineConfig } from '@alilc/lowcode-editor-core'; -import { IPublicTypeContextMenuAction } from '@alilc/lowcode-types'; +import { IPublicModelPluginContext, IPublicTypeContextMenuAction } from '@alilc/lowcode-types'; import React from 'react'; -export function ContextMenu({ children, menus }: { +export function ContextMenu({ children, menus, pluginContext }: { menus: IPublicTypeContextMenuAction[]; children: React.ReactElement[] | React.ReactElement; + pluginContext: IPublicModelPluginContext; }): React.ReactElement<any, string | React.JSXElementConstructor<any>> { if (!engineConfig.get('enableContextMenu')) { return ( @@ -23,7 +24,10 @@ export function ContextMenu({ children, menus }: { }; const children: React.ReactNode[] = parseContextMenuAsReactNode(parseContextMenuProperties(menus, { destroy, - })); + pluginContext, + }), { + pluginContext, + }); if (!children?.length) { return; @@ -44,4 +48,20 @@ export function ContextMenu({ children, menus }: { return ( <>{childrenWithContextMenu}</> ); -} \ No newline at end of file +} + +ContextMenu.create = (pluginContext: IPublicModelPluginContext, menus: IPublicTypeContextMenuAction[], event: MouseEvent) => { + const children: React.ReactNode[] = parseContextMenuAsReactNode(parseContextMenuProperties(menus, { + pluginContext, + }), { + pluginContext, + }); + + if (!children?.length) { + return; + } + + return createContextMenu(children, { + event, + }); +}; \ No newline at end of file diff --git a/packages/utils/src/context-menu.scss b/packages/utils/src/context-menu.scss index 0bcf39d153..366d03e45a 100644 --- a/packages/utils/src/context-menu.scss +++ b/packages/utils/src/context-menu.scss @@ -1,32 +1,42 @@ -.context-menu-tree-wrap { +.engine-context-menu-tree-wrap { position: relative; padding: 4px 10px 4px 32px; } -.context-menu-tree-children { +.engine-context-menu-tree-children { margin-left: 8px; line-height: 24px; } -.context-menu-tree-bg { - position: absolute; - left: 0; - right: 0; - cursor: pointer; +.engine-context-menu-item { + .engine-context-menu-text { + color: var(--color-text); + } + + &:hover { + .engine-context-menu-text { + color: var(--color-title); + } + } + + &.disbale { + .engine-context-menu-text { + color: var(--color-text-disabled); + } + } } -.context-menu-tree-bg-inner { - position: absolute; - height: 24px; - top: -24px; - width: 100%; +.engine-context-menu-title { + color: var(--color-text); + cursor: pointer; &:hover { background-color: var(--color-block-background-light); + color: var(--color-title); } } -.context-menu-tree-selected-icon { +.engine-context-menu-tree-selecte-icon { position: absolute; left: 10px; color: var(--color-icon-active); diff --git a/packages/utils/src/context-menu.tsx b/packages/utils/src/context-menu.tsx index 1816f5b526..0f157e4383 100644 --- a/packages/utils/src/context-menu.tsx +++ b/packages/utils/src/context-menu.tsx @@ -1,7 +1,7 @@ import { Menu, Icon } from '@alifd/next'; -import { IDesigner } from '@alilc/lowcode-designer'; -import { IPublicEnumContextMenuType, IPublicModelNode, IPublicTypeContextMenuAction, IPublicTypeContextMenuItem } from '@alilc/lowcode-types'; +import { IPublicEnumContextMenuType, IPublicModelNode, IPublicModelPluginContext, IPublicTypeContextMenuAction, IPublicTypeContextMenuItem } from '@alilc/lowcode-types'; import { Logger } from '@alilc/lowcode-utils'; +import classNames from 'classnames'; import React from 'react'; import './context-menu.scss'; @@ -10,43 +10,51 @@ const { Item, Divider, PopupItem } = Menu; const MAX_LEVEL = 2; +interface IOptions { + nodes?: IPublicModelNode[] | null; + destroy?: Function; + pluginContext: IPublicModelPluginContext; +} + const Tree = (props: { - node?: IPublicModelNode; + node?: IPublicModelNode | null; children?: React.ReactNode; - options: { - nodes?: IPublicModelNode[] | null; - destroy?: Function; - designer?: IDesigner; - }; + options: IOptions; }) => { const { node } = props; if (!node) { return ( - <div className="context-menu-tree-wrap">{ props.children }</div> + <div className="engine-context-menu-tree-wrap">{ props.children }</div> ); } - const commonUI = props.options.designer?.editor?.get('commonUI'); - - const Title = commonUI?.Title; + const { common } = props.options.pluginContext || {}; + const { intl } = common?.utils || {}; + const indent = node.zLevel * 8 + 32; + const style = { + paddingLeft: indent, + marginLeft: -indent, + marginRight: -10, + paddingRight: 10, + }; return ( <Tree {...props} node={node.parent} > - {props.options.nodes?.[0].id === node.id ? (<Icon className="context-menu-tree-selected-icon" size="small" type="success" />) : null} - <Title title={node.title} /> <div - className="context-menu-tree-children" + className="engine-context-menu-title" + onClick={() => { + props.options.destroy?.(); + node.select(); + }} + style={style} + > + {props.options.nodes?.[0].id === node.id ? (<Icon className="engine-context-menu-tree-selecte-icon" size="small" type="success" />) : null} + {intl(node.title)} + </div> + <div + className="engine-context-menu-tree-children" > - <div - className="context-menu-tree-bg" - onClick={() => { - props.options.destroy?.(); - node.select(); - }} - > - <div className="context-menu-tree-bg-inner" /> - </div> { props.children } </div> </Tree> @@ -55,11 +63,10 @@ const Tree = (props: { let destroyFn: Function | undefined; -export function parseContextMenuAsReactNode(menus: IPublicTypeContextMenuItem[], options: { - nodes?: IPublicModelNode[] | null; - destroy?: Function; - designer?: IDesigner; -} = {}): React.ReactNode[] { +export function parseContextMenuAsReactNode(menus: IPublicTypeContextMenuItem[], options: IOptions): React.ReactNode[] { + const { common } = options.pluginContext || {}; + const { intl = (title: any) => title } = common?.utils || {}; + const children: React.ReactNode[] = []; menus.forEach((menu, index) => { if (menu.type === IPublicEnumContextMenuType.SEPARATOR) { @@ -70,14 +77,33 @@ export function parseContextMenuAsReactNode(menus: IPublicTypeContextMenuItem[], if (menu.type === IPublicEnumContextMenuType.MENU_ITEM) { if (menu.items && menu.items.length) { children.push(( - <PopupItem key={menu.name} label={menu.title}> + <PopupItem + className={classNames('engine-context-menu-item', { + disbale: menu.disabled, + })} + key={menu.name} + label={<div className="engine-context-menu-text">{intl(menu.title)}</div>} + > <Menu className="next-context engine-context-menu"> { parseContextMenuAsReactNode(menu.items, options) } </Menu> </PopupItem> )); } else { - children.push((<Item disabled={menu.disabled} onClick={menu.action} key={menu.name}>{menu.title}</Item>)); + children.push(( + <Item + className={classNames('engine-context-menu-item', { + disbale: menu.disabled, + })} + disabled={menu.disabled} + onClick={menu.action} + key={menu.name} + > + <div className="engine-context-menu-text"> + {intl(menu.title)} + </div> + </Item> + )); } } @@ -91,9 +117,7 @@ export function parseContextMenuAsReactNode(menus: IPublicTypeContextMenuItem[], return children; } -export function parseContextMenuProperties(menus: (IPublicTypeContextMenuAction | Omit<IPublicTypeContextMenuAction, 'items'>)[], options: { - nodes?: IPublicModelNode[] | null; - destroy?: Function; +export function parseContextMenuProperties(menus: (IPublicTypeContextMenuAction | Omit<IPublicTypeContextMenuAction, 'items'>)[], options: IOptions & { event?: MouseEvent; }, level = 1): IPublicTypeContextMenuItem[] { destroyFn?.(); @@ -156,7 +180,6 @@ function getMenuItemHeight() { } const root = document.documentElement; const styles = getComputedStyle(root); - // Access the value of the CSS variable const menuItemHeight = styles.getPropertyValue('--context-menu-item-height').trim(); cachedMenuItemHeight = menuItemHeight; diff --git a/packages/workspace/src/context/base-context.ts b/packages/workspace/src/context/base-context.ts index e090d1e374..2f6154788f 100644 --- a/packages/workspace/src/context/base-context.ts +++ b/packages/workspace/src/context/base-context.ts @@ -128,13 +128,12 @@ export class BasicContext implements IBasicContext { const logger = getLogger({ level: 'warn', bizName: 'common' }); const skeleton = new Skeleton(innerSkeleton, 'any', true); const canvas = new Canvas(editor, true); - const commonUI = new CommonUI(); + const commonUI = new CommonUI(editor); editor.set('setters', setters); editor.set('project', project); editor.set('material', material); editor.set('hotkey', hotkey); editor.set('innerHotkey', innerHotkey); - editor.set('commonUI' as any, commonUI); this.innerSetters = innerSetters; this.innerSkeleton = innerSkeleton; this.skeleton = skeleton; @@ -175,6 +174,7 @@ export class BasicContext implements IBasicContext { } context.registerLevel = registerLevel; context.isPluginRegisteredInWorkspace = registerLevel === IPublicEnumPluginRegisterLevel.Workspace; + editor.set('pluginContext', context); }, }; From 18642ee92312fd335cb8d793bfc0136ccad7ad58 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Thu, 11 Jan 2024 03:17:25 +0000 Subject: [PATCH 173/219] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 80396a0146..1626d99578 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.24", + "version": "1.2.25", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From ce72fc1b16912312ab9fb2a38bba811dbea7ef13 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 11 Jan 2024 18:03:22 +0800 Subject: [PATCH 174/219] feat(common-ui): add HelpTip --- docs/docs/api/commonUI.md | 10 +++++ .../editor-core/src/widgets/tip/help-tips.tsx | 40 +++++++++++++++++++ packages/editor-core/src/widgets/tip/index.ts | 1 + .../src/components/widget-views/index.tsx | 24 +---------- packages/shell/src/api/commonUI.tsx | 6 +++ packages/types/src/shell/api/commonUI.ts | 36 +++++++++++++---- 6 files changed, 87 insertions(+), 30 deletions(-) create mode 100644 packages/editor-core/src/widgets/tip/help-tips.tsx diff --git a/docs/docs/api/commonUI.md b/docs/docs/api/commonUI.md index 350d60dd7a..c0bbda588e 100644 --- a/docs/docs/api/commonUI.md +++ b/docs/docs/api/commonUI.md @@ -19,6 +19,16 @@ CommonUI API 是一个专为低代码引擎设计的组件 UI 库,使用它开 | direction | tip 的方向 | 'top' \| 'bottom' \| 'left' \| 'right' | | +### HelpTip + +带 help icon 的提示组件 + +| 参数 | 说明 | 类型 | 默认值 | +|-----------|--------|-----------------------------------|--------| +| help | 描述 | IPublicTypeHelpTipConfig | | +| direction | 方向 | IPublicTypeTipConfig['direction'] | 'top' | +| size | 方向 | IconProps['size'] | 'small'| + ### Title 标题组件 diff --git a/packages/editor-core/src/widgets/tip/help-tips.tsx b/packages/editor-core/src/widgets/tip/help-tips.tsx new file mode 100644 index 0000000000..ab5f65050e --- /dev/null +++ b/packages/editor-core/src/widgets/tip/help-tips.tsx @@ -0,0 +1,40 @@ +import { IPublicTypeHelpTipConfig, IPublicTypeTipConfig } from '@alilc/lowcode-types'; +import { Tip } from './tip'; +import { Icon } from '@alifd/next'; +import { IconProps } from '@alifd/next/types/icon'; + +export function HelpTip({ + help, + direction = 'top', + size = 'small', +}: { + help: IPublicTypeHelpTipConfig; + direction?: IPublicTypeTipConfig['direction']; + size?: IconProps['size']; +}) { + if (typeof help === 'string') { + return ( + <div> + <Icon type="help" size={size} className="lc-help-tip" /> + <Tip direction={direction}>{help}</Tip> + </div> + ); + } + + if (typeof help === 'object' && help.url) { + return ( + <div> + <a href={help.url} target="_blank" rel="noopener noreferrer"> + <Icon type="help" size={size} className="lc-help-tip" /> + </a> + <Tip direction={direction}>{help.content}</Tip> + </div> + ); + } + return ( + <div> + <Icon type="help" size="small" className="lc-help-tip" /> + <Tip direction={direction}>{help.content}</Tip> + </div> + ); +} \ No newline at end of file diff --git a/packages/editor-core/src/widgets/tip/index.ts b/packages/editor-core/src/widgets/tip/index.ts index dba4412c7f..d2b3768003 100644 --- a/packages/editor-core/src/widgets/tip/index.ts +++ b/packages/editor-core/src/widgets/tip/index.ts @@ -2,3 +2,4 @@ import './style.less'; export * from './tip'; export * from './tip-container'; +export * from './help-tips'; diff --git a/packages/editor-skeleton/src/components/widget-views/index.tsx b/packages/editor-skeleton/src/components/widget-views/index.tsx index 2b2f6931cb..7cdff4c014 100644 --- a/packages/editor-skeleton/src/components/widget-views/index.tsx +++ b/packages/editor-skeleton/src/components/widget-views/index.tsx @@ -1,7 +1,6 @@ import { Component, ReactElement } from 'react'; -import { Icon } from '@alifd/next'; import classNames from 'classnames'; -import { Title, observer, Tip } from '@alilc/lowcode-editor-core'; +import { Title, observer, HelpTip } from '@alilc/lowcode-editor-core'; import { DockProps } from '../../types'; import { PanelDock } from '../../widget/panel-dock'; import { composeTitle } from '../../widget/utils'; @@ -26,25 +25,6 @@ export function DockView({ title, icon, description, size, className, onClick }: ); } -function HelpTip({ tip }: any) { - if (tip && tip.url) { - return ( - <div> - <a href={tip.url} target="_blank" rel="noopener noreferrer"> - <Icon type="help" size="small" className="lc-help-tip" /> - </a> - <Tip>{tip.content}</Tip> - </div> - ); - } - return ( - <div> - <Icon type="help" size="small" className="lc-help-tip" /> - <Tip>{tip.content}</Tip> - </div> - ); -} - @observer export class PanelDockView extends Component<DockProps & { dock: PanelDock }> { private lastActived = false; @@ -328,7 +308,7 @@ class PanelTitle extends Component<{ panel: Panel; className?: string }> { data-name={panel.name} > <Title title={panel.title || panel.name} /> - {panel.help ? <HelpTip tip={panel.help} /> : null} + {panel.help ? <HelpTip help={panel.help} /> : null} </div> ); } diff --git a/packages/shell/src/api/commonUI.tsx b/packages/shell/src/api/commonUI.tsx index cb4b7ae38e..0a9021fe6a 100644 --- a/packages/shell/src/api/commonUI.tsx +++ b/packages/shell/src/api/commonUI.tsx @@ -1,5 +1,6 @@ import { IPublicApiCommonUI, IPublicModelPluginContext, IPublicTypeContextMenuAction } from '@alilc/lowcode-types'; import { + HelpTip, IEditor, Tip as InnerTip, Title as InnerTitle, @@ -46,6 +47,11 @@ export class CommonUI implements IPublicApiCommonUI { get Tip() { return InnerTip; } + + get HelpTip() { + return HelpTip; + } + get Title() { return InnerTitle; } diff --git a/packages/types/src/shell/api/commonUI.ts b/packages/types/src/shell/api/commonUI.ts index 71e2bbe83f..5ac025fcde 100644 --- a/packages/types/src/shell/api/commonUI.ts +++ b/packages/types/src/shell/api/commonUI.ts @@ -1,6 +1,7 @@ -import { ReactElement } from 'react'; -import { IPublicTypeContextMenuAction, IPublicTypeTitleContent } from '../type'; +import React, { ReactElement } from 'react'; +import { IPublicTypeContextMenuAction, IPublicTypeHelpTipConfig, IPublicTypeTipConfig, IPublicTypeTitleContent } from '../type'; import { Balloon, Breadcrumb, Button, Card, Checkbox, DatePicker, Dialog, Dropdown, Form, Icon, Input, Loading, Message, Overlay, Pagination, Radio, Search, Select, SplitButton, Step, Switch, Tab, Table, Tree, TreeSelect, Upload, Divider } from '@alifd/next'; +import { IconProps } from '@alifd/next/types/icon'; export interface IPublicApiCommonUI { Balloon: typeof Balloon; @@ -33,13 +34,30 @@ export interface IPublicApiCommonUI { /** * Title 组件 - * @experimental unstable API, pay extra caution when trying to use this */ - get Tip(): React.ComponentClass<{}>; + get Tip(): React.ComponentClass<IPublicTypeTipConfig>; + + /** + * HelpTip 组件 + */ + get HelpTip(): React.VFC<{ + help: IPublicTypeHelpTipConfig; + + /** + * 方向 + * @default 'top' + */ + direction: IPublicTypeTipConfig['direction']; + + /** + * 大小 + * @default 'small' + */ + size: IconProps['size']; + }>; /** * Tip 组件 - * @experimental unstable API, pay extra caution when trying to use this */ get Title(): React.ComponentClass<{ title: IPublicTypeTitleContent | undefined; @@ -47,8 +65,10 @@ export interface IPublicApiCommonUI { keywords?: string | null; }>; - get ContextMenu(): (props: { + get ContextMenu(): ((props: { menus: IPublicTypeContextMenuAction[]; children: React.ReactElement[] | React.ReactElement; - }) => ReactElement; -} \ No newline at end of file + }) => ReactElement) & { + create(menus: IPublicTypeContextMenuAction[], event: MouseEvent | React.MouseEvent): void; + }; +} From 6f9359e042191d488a7bf9687a1e5a45d46dfcfa Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Thu, 11 Jan 2024 10:13:55 +0000 Subject: [PATCH 175/219] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 1626d99578..6a029b851b 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.25", + "version": "1.2.26", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 844ca783d720e5d8829a8e8e54314c97997ec275 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 11 Jan 2024 18:49:21 +0800 Subject: [PATCH 176/219] feat(context-menu): add context-menu css theme, help config, ts define --- docs/docs/guide/expand/editor/theme.md | 5 +++ .../designer/src/builtin-simulator/host.ts | 8 ++++- packages/designer/src/context-menu-actions.ts | 2 ++ .../src/inner-plugins/default-context-menu.ts | 36 +++++++++++-------- .../shell/src/components/context-menu.tsx | 8 ++--- packages/types/src/shell/type/context-menu.ts | 14 +++++--- packages/utils/src/context-menu.scss | 21 +++++++---- packages/utils/src/context-menu.tsx | 33 ++++++++++------- 8 files changed, 81 insertions(+), 46 deletions(-) diff --git a/docs/docs/guide/expand/editor/theme.md b/docs/docs/guide/expand/editor/theme.md index 1c442c5132..897b6b360b 100644 --- a/docs/docs/guide/expand/editor/theme.md +++ b/docs/docs/guide/expand/editor/theme.md @@ -53,6 +53,11 @@ sidebar_position: 9 - `--color-text-reverse`: 反色情况下,文字颜色 - `--color-text-disabled`: 禁用态文字颜色 +#### 菜单颜色 +- `--color-context-menu-text`: 菜单项颜色 +- `--color-context-menu-text-hover`: 菜单项 hover 颜色 +- `--color-context-menu-text-disabled`: 菜单项 disabled 颜色 + #### 字段和边框颜色 - `--color-field-label`: field 标签颜色 diff --git a/packages/designer/src/builtin-simulator/host.ts b/packages/designer/src/builtin-simulator/host.ts index 6efe6a68b5..57f8569326 100644 --- a/packages/designer/src/builtin-simulator/host.ts +++ b/packages/designer/src/builtin-simulator/host.ts @@ -832,16 +832,22 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp doc.addEventListener('contextmenu', (e: MouseEvent) => { const targetElement = e.target as HTMLElement; const nodeInst = this.getNodeInstanceFromElement(targetElement); + const editor = this.designer?.editor; if (!nodeInst) { + editor?.eventBus.emit('designer.builtinSimulator.contextmenu', { + originalEvent: e, + }); return; } const node = nodeInst.node || this.project.currentDocument?.focusNode; if (!node) { + editor?.eventBus.emit('designer.builtinSimulator.contextmenu', { + originalEvent: e, + }); return; } // dirty code should refector - const editor = this.designer?.editor; const npm = node?.componentMeta?.npm; const selected = [npm?.package, npm?.componentName].filter((item) => !!item).join('-') || diff --git a/packages/designer/src/context-menu-actions.ts b/packages/designer/src/context-menu-actions.ts index c3bad37da5..c88e03ac65 100644 --- a/packages/designer/src/context-menu-actions.ts +++ b/packages/designer/src/context-menu-actions.ts @@ -201,6 +201,8 @@ export class ContextMenuActions implements IContextMenuActions { node: INode; originalEvent: MouseEvent; }) => { + originalEvent.stopPropagation(); + originalEvent.preventDefault(); // 如果右键的节点不在 当前选中的节点中,选中该节点 if (!designer.currentSelection.has(node.id)) { designer.currentSelection.select(node.id); diff --git a/packages/engine/src/inner-plugins/default-context-menu.ts b/packages/engine/src/inner-plugins/default-context-menu.ts index db3d54a0c8..c8997aa7ed 100644 --- a/packages/engine/src/inner-plugins/default-context-menu.ts +++ b/packages/engine/src/inner-plugins/default-context-menu.ts @@ -60,7 +60,7 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { material.addContextMenuOption({ name: 'selectComponent', title: intl('SelectComponents'), - condition: (nodes) => { + condition: (nodes = []) => { return nodes.length === 1; }, items: [ @@ -74,14 +74,17 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { material.addContextMenuOption({ name: 'copyAndPaste', title: intl('CopyAndPaste'), - disabled: (nodes) => { + disabled: (nodes = []) => { return nodes?.filter((node) => !node?.canPerformAction('copy')).length > 0; }, condition: (nodes) => { - return nodes.length === 1; + return nodes?.length === 1; }, action(nodes) { - const node = nodes[0]; + const node = nodes?.[0]; + if (!node) { + return; + } const { document: doc, parent, index } = node; const data = getNodesSchema(nodes); clipboard.setData(data); @@ -96,11 +99,11 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { material.addContextMenuOption({ name: 'copy', title: intl('Copy'), - disabled: (nodes) => { + disabled: (nodes = []) => { return nodes?.filter((node) => !node?.canPerformAction('copy')).length > 0; }, - condition(nodes) { - return nodes.length > 0; + condition(nodes = []) { + return nodes?.length > 0; }, action(nodes) { if (!nodes || nodes.length < 1) { @@ -116,7 +119,7 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { name: 'pasteToBottom', title: intl('PasteToTheBottom'), condition: (nodes) => { - return nodes.length === 1; + return nodes?.length === 1; }, async action(nodes) { if (!nodes || nodes.length < 1) { @@ -163,15 +166,18 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { name: 'pasteToInner', title: intl('PasteToTheInside'), condition: (nodes) => { - return nodes.length === 1; + return nodes?.length === 1; }, - disabled: (nodes) => { + disabled: (nodes = []) => { // 获取粘贴数据 - const node = nodes[0]; + const node = nodes?.[0]; return !node.isContainerNode; }, async action(nodes) { - const node = nodes[0]; + const node = nodes?.[0]; + if (!node) { + return; + } const { document: doc } = node; try { @@ -210,14 +216,14 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { material.addContextMenuOption({ name: 'delete', title: intl('Delete'), - disabled(nodes) { + disabled(nodes = []) { return nodes?.filter((node) => !node?.canPerformAction('remove')).length > 0; }, - condition(nodes) { + condition(nodes = []) { return nodes.length > 0; }, action(nodes) { - nodes.forEach((node) => { + nodes?.forEach((node) => { node.remove(); }); }, diff --git a/packages/shell/src/components/context-menu.tsx b/packages/shell/src/components/context-menu.tsx index d2e10abbfe..c752e79903 100644 --- a/packages/shell/src/components/context-menu.tsx +++ b/packages/shell/src/components/context-menu.tsx @@ -25,17 +25,13 @@ export function ContextMenu({ children, menus, pluginContext }: { const children: React.ReactNode[] = parseContextMenuAsReactNode(parseContextMenuProperties(menus, { destroy, pluginContext, - }), { - pluginContext, - }); + }), { pluginContext }); if (!children?.length) { return; } - destroyFn = createContextMenu(children, { - event, - }); + destroyFn = createContextMenu(children, { event }); }; // 克隆 children 并添加 onContextMenu 事件处理器 diff --git a/packages/types/src/shell/type/context-menu.ts b/packages/types/src/shell/type/context-menu.ts index 1eeb93d696..dd6d583c25 100644 --- a/packages/types/src/shell/type/context-menu.ts +++ b/packages/types/src/shell/type/context-menu.ts @@ -1,6 +1,7 @@ import { IPublicEnumContextMenuType } from '../enum'; import { IPublicModelNode } from '../model'; import { IPublicTypeI18nData } from './i8n-data'; +import { IPublicTypeHelpTipConfig } from './widget-base-config'; export interface IPublicTypeContextMenuItem extends Omit<IPublicTypeContextMenuAction, 'condition' | 'disabled' | 'items'> { disabled?: boolean; @@ -34,24 +35,29 @@ export interface IPublicTypeContextMenuAction { * 点击时执行的动作,可选 * Action to execute on click, optional */ - action?: (nodes: IPublicModelNode[], event?: MouseEvent) => void; + action?: (nodes?: IPublicModelNode[], event?: MouseEvent) => void; /** * 子菜单项或生成子节点的函数,可选,仅支持两级 * Sub-menu items or function to generate child node, optional */ - items?: Omit<IPublicTypeContextMenuAction, 'items'>[] | ((nodes: IPublicModelNode[]) => Omit<IPublicTypeContextMenuAction, 'items'>[]); + items?: Omit<IPublicTypeContextMenuAction, 'items'>[] | ((nodes?: IPublicModelNode[]) => Omit<IPublicTypeContextMenuAction, 'items'>[]); /** * 显示条件函数 * Function to determine display condition */ - condition?: (nodes: IPublicModelNode[]) => boolean; + condition?: (nodes?: IPublicModelNode[]) => boolean; /** * 禁用条件函数,可选 * Function to determine disabled condition, optional */ - disabled?: (nodes: IPublicModelNode[]) => boolean; + disabled?: (nodes?: IPublicModelNode[]) => boolean; + + /** + * 帮助提示,可选 + */ + help?: IPublicTypeHelpTipConfig; } diff --git a/packages/utils/src/context-menu.scss b/packages/utils/src/context-menu.scss index 366d03e45a..0b75ca3ec1 100644 --- a/packages/utils/src/context-menu.scss +++ b/packages/utils/src/context-menu.scss @@ -10,24 +10,31 @@ .engine-context-menu-item { .engine-context-menu-text { - color: var(--color-text); + color: var(--color-context-menu-text, var(--color-text)); + display: flex; + align-items: center; + + .lc-help-tip { + margin-left: 4px; + opacity: 0.8; + } } - &:hover { - .engine-context-menu-text { - color: var(--color-title); + &.disabled { + &:hover .engine-context-menu-text, .engine-context-menu-text { + color: var(--color-context-menu-text-disabled, var(--color-text-disabled)); } } - &.disbale { + &:hover { .engine-context-menu-text { - color: var(--color-text-disabled); + color: var(--color-context-menu-text-hover, var(--color-title)); } } } .engine-context-menu-title { - color: var(--color-text); + color: var(--color-context-menu-text, var(--color-text)); cursor: pointer; &:hover { diff --git a/packages/utils/src/context-menu.tsx b/packages/utils/src/context-menu.tsx index 0f157e4383..d783a96434 100644 --- a/packages/utils/src/context-menu.tsx +++ b/packages/utils/src/context-menu.tsx @@ -64,8 +64,9 @@ const Tree = (props: { let destroyFn: Function | undefined; export function parseContextMenuAsReactNode(menus: IPublicTypeContextMenuItem[], options: IOptions): React.ReactNode[] { - const { common } = options.pluginContext || {}; + const { common, commonUI } = options.pluginContext || {}; const { intl = (title: any) => title } = common?.utils || {}; + const { HelpTip } = commonUI || {}; const children: React.ReactNode[] = []; menus.forEach((menu, index) => { @@ -79,7 +80,7 @@ export function parseContextMenuAsReactNode(menus: IPublicTypeContextMenuItem[], children.push(( <PopupItem className={classNames('engine-context-menu-item', { - disbale: menu.disabled, + disabled: menu.disabled, })} key={menu.name} label={<div className="engine-context-menu-text">{intl(menu.title)}</div>} @@ -93,14 +94,17 @@ export function parseContextMenuAsReactNode(menus: IPublicTypeContextMenuItem[], children.push(( <Item className={classNames('engine-context-menu-item', { - disbale: menu.disabled, + disabled: menu.disabled, })} disabled={menu.disabled} - onClick={menu.action} + onClick={() => { + menu.action?.(); + }} key={menu.name} > <div className="engine-context-menu-text"> - {intl(menu.title)} + { menu.title ? intl(menu.title) : null } + { menu.help ? <HelpTip size="xs" help={menu.help} direction="right" /> : null } </div> </Item> )); @@ -135,12 +139,14 @@ export function parseContextMenuProperties(menus: (IPublicTypeContextMenuAction name, title, type = IPublicEnumContextMenuType.MENU_ITEM, + help, } = menu; const result: IPublicTypeContextMenuItem = { name, title, type, + help, action: () => { destroy?.(); menu.action?.(nodes || [], options.event); @@ -193,26 +199,27 @@ export function createContextMenu(children: React.ReactNode[], { event: MouseEvent | React.MouseEvent; offset?: [number, number]; }) { + event.preventDefault(); + event.stopPropagation(); + const viewportWidth = window.innerWidth; const viewportHeight = window.innerHeight; const dividerCount = React.Children.count(children.filter(child => React.isValidElement(child) && child.type === Divider)); const popupItemCount = React.Children.count(children.filter(child => React.isValidElement(child) && (child.type === PopupItem || child.type === Item))); const menuHeight = popupItemCount * parseInt(getMenuItemHeight(), 10) + dividerCount * 8 + 16; const menuWidthLimit = 200; - const target = event.target; - const { top, left } = (target as any)?.getBoundingClientRect(); - let x = event.clientX - left + offset[0]; - let y = event.clientY - top + offset[1]; - if (x + menuWidthLimit + left > viewportWidth) { + let x = event.clientX + offset[0]; + let y = event.clientY + offset[1]; + if (x + menuWidthLimit > viewportWidth) { x = x - menuWidthLimit; } - if (y + menuHeight + top > viewportHeight) { + if (y + menuHeight > viewportHeight) { y = y - menuHeight; } const menuInstance = Menu.create({ - target, - offset: [x, y, 0, 0], + target: document.body, + offset: [x, y], children, className: 'engine-context-menu', }); From 8931d8393d74133fe0f3201d1826fffc7d2849d1 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Fri, 12 Jan 2024 01:17:52 +0000 Subject: [PATCH 177/219] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 6a029b851b..643bdace2b 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.26", + "version": "1.2.27", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 34a5a11b49cac4eddd0a4871cf0bb7e16543a493 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 12 Jan 2024 15:51:18 +0800 Subject: [PATCH 178/219] fix: fix clipboard.setData fial in workspace mode --- packages/designer/src/designer/clipboard.ts | 4 ++++ packages/designer/src/designer/designer-view.tsx | 2 -- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/designer/src/designer/clipboard.ts b/packages/designer/src/designer/clipboard.ts index 941f914428..26f57f8112 100644 --- a/packages/designer/src/designer/clipboard.ts +++ b/packages/designer/src/designer/clipboard.ts @@ -36,6 +36,10 @@ class Clipboard implements IClipboard { private waitFn?: (data: any, e: ClipboardEvent) => void; + constructor() { + this.injectCopyPaster(document); + } + isCopyPasteEvent(e: Event) { this.isCopyPaster(e.target); } diff --git a/packages/designer/src/designer/designer-view.tsx b/packages/designer/src/designer/designer-view.tsx index 0db2a3fa3e..aaf0c9583e 100644 --- a/packages/designer/src/designer/designer-view.tsx +++ b/packages/designer/src/designer/designer-view.tsx @@ -4,7 +4,6 @@ import BuiltinDragGhostComponent from './drag-ghost'; import { Designer, DesignerProps } from './designer'; import { ProjectView } from '../project'; import './designer.less'; -import { clipboard } from './clipboard'; type IProps = DesignerProps & { designer?: Designer; @@ -44,7 +43,6 @@ export class DesignerView extends Component<IProps> { if (onMount) { onMount(this.designer); } - clipboard.injectCopyPaster(document); this.designer.postEvent('mount', this.designer); } From 1132a30483e31d82e33d8aa036f6733bfad67483 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 12 Jan 2024 15:52:36 +0800 Subject: [PATCH 179/219] feat: update context-menu message --- .../src/inner-plugins/default-context-menu.ts | 22 +++++-------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/packages/engine/src/inner-plugins/default-context-menu.ts b/packages/engine/src/inner-plugins/default-context-menu.ts index c8997aa7ed..81978d9209 100644 --- a/packages/engine/src/inner-plugins/default-context-menu.ts +++ b/packages/engine/src/inner-plugins/default-context-menu.ts @@ -8,7 +8,7 @@ import { IPublicTypeNodeSchema, } from '@alilc/lowcode-types'; import { isProjectSchema } from '@alilc/lowcode-utils'; -import { Notification } from '@alifd/next'; +import { Message } from '@alifd/next'; import { intl } from '../locale'; function getNodesSchema(nodes: IPublicModelNode[]) { @@ -27,19 +27,13 @@ async function getClipboardText(): Promise<IPublicTypeNodeSchema[]> { if (isProjectSchema(data)) { resolve(data.componentsTree); } else { - Notification.open({ - content: intl('NotValidNodeData'), - type: 'error', - }); + Message.error(intl('NotValidNodeData')); reject( new Error(intl('NotValidNodeData')), ); } } catch (error) { - Notification.open({ - content: intl('NotValidNodeData'), - type: 'error', - }); + Message.error(intl('NotValidNodeData')); reject(error); } }, @@ -143,10 +137,7 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { return doc?.checkNesting(parent, dragNodeObject); }); if (canAddNodes.length === 0) { - Notification.open({ - content: `${nodeSchema.map(d => utilsIntl(d.title || d.componentName)).join(',')}等组件无法放置到${utilsIntl(parent.title || parent.componentName as any)}内`, - type: 'error', - }); + Message.error(`${nodeSchema.map(d => utilsIntl(d.title || d.componentName)).join(',')}等组件无法放置到${utilsIntl(parent.title || parent.componentName as any)}内`); return; } const nodes: IPublicModelNode[] = []; @@ -194,10 +185,7 @@ export const defaultContextMenu = (ctx: IPublicModelPluginContext) => { return doc?.checkNesting(node, dragNodeObject); }); if (canAddNodes.length === 0) { - Notification.open({ - content: `${nodeSchema.map(d => utilsIntl(d.title || d.componentName)).join(',')}等组件无法放置到${utilsIntl(node.title || node.componentName as any)}内`, - type: 'error', - }); + Message.error(`${nodeSchema.map(d => utilsIntl(d.title || d.componentName)).join(',')}等组件无法放置到${utilsIntl(node.title || node.componentName as any)}内`); return; } From adb9f6b090a71052ece0b10d3b6e48125c8799e8 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Mon, 15 Jan 2024 10:02:26 +0800 Subject: [PATCH 180/219] fix(canvas): clipboard init error --- packages/designer/src/designer/clipboard.ts | 8 +++++++- packages/types/src/shell/api/material.ts | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/designer/src/designer/clipboard.ts b/packages/designer/src/designer/clipboard.ts index 26f57f8112..34ce2b5b53 100644 --- a/packages/designer/src/designer/clipboard.ts +++ b/packages/designer/src/designer/clipboard.ts @@ -73,7 +73,13 @@ class Clipboard implements IClipboard { } const copyPaster = document.createElement<'textarea'>('textarea'); copyPaster.style.cssText = 'position: absolute;left: -9999px;top:-100px'; - document.body.appendChild(copyPaster); + if (document.body) { + document.body.appendChild(copyPaster); + } else { + document.addEventListener('DOMContentLoaded', () => { + document.body.appendChild(copyPaster); + }); + } const dispose = this.initCopyPaster(copyPaster); return () => { dispose(); diff --git a/packages/types/src/shell/api/material.ts b/packages/types/src/shell/api/material.ts index 6354c7fa0f..89b2b39ad1 100644 --- a/packages/types/src/shell/api/material.ts +++ b/packages/types/src/shell/api/material.ts @@ -15,7 +15,7 @@ export interface IPublicApiMaterial { * set data for Assets * @returns void */ - setAssets(assets: IPublicTypeAssetsJson): void; + setAssets(assets: IPublicTypeAssetsJson): Promise<void>; /** * 获取「资产包」结构 From d1a8bacd75df198ca0f97ebaf985bd3438049114 Mon Sep 17 00:00:00 2001 From: eightHundreds <mingoing@outlook.com> Date: Mon, 15 Jan 2024 12:10:52 +0800 Subject: [PATCH 181/219] fix(designer): node.ts cannot generate declaration file --- packages/designer/src/document/node/node.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts index 4071fb9138..c8363d0586 100644 --- a/packages/designer/src/document/node/node.ts +++ b/packages/designer/src/document/node/node.ts @@ -392,7 +392,7 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema> this.isInited = true; this.emitter = createModuleEventBus('Node'); - const editor = this.document.designer.editor; + const { editor } = this.document.designer; this.onVisibleChange((visible: boolean) => { editor?.eventBus.emit(EDITOR_EVENT.NODE_VISIBLE_CHANGE, this, visible); }); @@ -1219,11 +1219,18 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema> /** * 获取磁贴相关信息 */ - getRGL() { + getRGL(): { + isContainerNode: boolean; + isEmptyNode: boolean; + isRGLContainerNode: boolean; + isRGLNode: boolean; + isRGL: boolean; + rglNode: Node | null; + } { const isContainerNode = this.isContainer(); const isEmptyNode = this.isEmpty(); const isRGLContainerNode = this.isRGLContainer; - const isRGLNode = this.getParent()?.isRGLContainer; + const isRGLNode = (this.getParent()?.isRGLContainer) as boolean; const isRGL = isRGLContainerNode || (isRGLNode && (!isContainerNode || !isEmptyNode)); let rglNode = isRGLContainerNode ? this : isRGL ? this?.getParent() : null; return { isContainerNode, isEmptyNode, isRGLContainerNode, isRGLNode, isRGL, rglNode }; From e77063636cd053a2ca7730298520bef56e246651 Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Mon, 15 Jan 2024 14:02:38 +0800 Subject: [PATCH 182/219] chore: add pub:minor and pub:major commands --- .github/workflows/publish engine.yml | 6 +++++- package.json | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish engine.yml b/.github/workflows/publish engine.yml index 6825c66fca..ab63eec52e 100644 --- a/.github/workflows/publish engine.yml +++ b/.github/workflows/publish engine.yml @@ -2,6 +2,10 @@ name: Publish Engine on: workflow_dispatch: + inputs: + publishCommand: + description: 'publish command' + required: true jobs: publish-engine: @@ -21,7 +25,7 @@ jobs: npm run build git config --local user.email "action@github.com" git config --local user.name "GitHub Action" - - run: npm run pub + - run: npm run ${{ github.event.inputs.publishCommand }} env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Get version diff --git a/package.json b/package.json index caabbeeb13..6562cec3b5 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,8 @@ "lint:modules": "f2elint scan -q -i ./modules/*/src", "lint:modules:fix": "f2elint fix -i ./modules/*/src", "pub": "npm run watchdog:build && lerna publish patch --yes --force-publish --exact --no-changelog", + "pub:minor": "npm run watchdog:build && lerna publish minor --yes --force-publish --exact --no-changelog", + "pub:major": "npm run watchdog:build && lerna publish major --yes --force-publish --exact --no-changelog", "pub:premajor": "npm run watchdog:build && lerna publish premajor --force-publish --exact --dist-tag beta --preid beta --no-changelog", "pub:preminor": "npm run watchdog:build && lerna publish preminor --force-publish --exact --dist-tag beta --preid beta --no-changelog", "pub:prepatch": "npm run watchdog:build && lerna publish prepatch --force-publish --exact --dist-tag beta --preid beta --no-changelog", From d957be8072a7d9004c5b5875a39861386ac8e52b Mon Sep 17 00:00:00 2001 From: JackLian <jack.lianjie@gmail.com> Date: Mon, 15 Jan 2024 14:02:38 +0800 Subject: [PATCH 183/219] chore: add pub:minor and pub:major commands --- .github/workflows/publish engine.yml | 6 +++++- package.json | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish engine.yml b/.github/workflows/publish engine.yml index ad4c3963b2..dcbf0547e7 100644 --- a/.github/workflows/publish engine.yml +++ b/.github/workflows/publish engine.yml @@ -2,6 +2,10 @@ name: Publish Engine on: workflow_dispatch: + inputs: + publishCommand: + description: 'publish command' + required: true jobs: publish-engine: @@ -21,7 +25,7 @@ jobs: npm run build git config --local user.email "action@github.com" git config --local user.name "GitHub Action" - - run: npm run pub + - run: npm run ${{ github.event.inputs.publishCommand }} env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Get version diff --git a/package.json b/package.json index 047b287b98..8b566e0f0c 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,8 @@ "lint:modules": "f2elint scan -q -i ./modules/*/src", "lint:modules:fix": "f2elint fix -i ./modules/*/src", "pub": "npm run watchdog:build && lerna publish patch --yes --force-publish --exact --no-changelog", + "pub:minor": "npm run watchdog:build && lerna publish minor --yes --force-publish --exact --no-changelog", + "pub:major": "npm run watchdog:build && lerna publish major --yes --force-publish --exact --no-changelog", "pub:premajor": "npm run watchdog:build && lerna publish premajor --force-publish --exact --dist-tag beta --preid beta --no-changelog", "pub:preminor": "npm run watchdog:build && lerna publish preminor --force-publish --exact --dist-tag beta --preid beta --no-changelog", "pub:prepatch": "npm run watchdog:build && lerna publish prepatch --force-publish --exact --dist-tag beta --preid beta --no-changelog", From 1943172d65ece0608e7fef760bd35a4c93c9b2a2 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Mon, 15 Jan 2024 06:12:28 +0000 Subject: [PATCH 184/219] chore(release): publish 1.3.0 --- lerna.json | 2 +- packages/designer/package.json | 8 ++++---- packages/editor-core/package.json | 6 +++--- packages/editor-skeleton/package.json | 10 +++++----- packages/engine/package.json | 18 +++++++++--------- packages/ignitor/package.json | 2 +- packages/plugin-designer/package.json | 8 ++++---- packages/plugin-outline-pane/package.json | 6 +++--- packages/react-renderer/package.json | 4 ++-- packages/react-simulator-renderer/package.json | 10 +++++----- packages/renderer-core/package.json | 8 ++++---- packages/shell/package.json | 14 +++++++------- packages/types/package.json | 2 +- packages/utils/package.json | 4 ++-- packages/workspace/package.json | 12 ++++++------ 15 files changed, 57 insertions(+), 57 deletions(-) diff --git a/lerna.json b/lerna.json index 1170309170..33d4899d0c 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "lerna": "4.0.0", - "version": "1.2.5", + "version": "1.3.0", "npmClient": "yarn", "useWorkspaces": true, "packages": [ diff --git a/packages/designer/package.json b/packages/designer/package.json index 0e6e67e882..5ecf6c1390 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-designer", - "version": "1.2.5", + "version": "1.3.0", "description": "Designer for Ali LowCode Engine", "main": "lib/index.js", "module": "es/index.js", @@ -15,9 +15,9 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-editor-core": "1.2.5", - "@alilc/lowcode-types": "1.2.5", - "@alilc/lowcode-utils": "1.2.5", + "@alilc/lowcode-editor-core": "1.3.0", + "@alilc/lowcode-types": "1.3.0", + "@alilc/lowcode-utils": "1.3.0", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/editor-core/package.json b/packages/editor-core/package.json index 0875584501..888642adf5 100644 --- a/packages/editor-core/package.json +++ b/packages/editor-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-core", - "version": "1.2.5", + "version": "1.3.0", "description": "Core Api for Ali lowCode engine", "license": "MIT", "main": "lib/index.js", @@ -14,8 +14,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.2.5", - "@alilc/lowcode-utils": "1.2.5", + "@alilc/lowcode-types": "1.3.0", + "@alilc/lowcode-utils": "1.3.0", "classnames": "^2.2.6", "debug": "^4.1.1", "intl-messageformat": "^9.3.1", diff --git a/packages/editor-skeleton/package.json b/packages/editor-skeleton/package.json index 648ed5be1f..58c5f2e18a 100644 --- a/packages/editor-skeleton/package.json +++ b/packages/editor-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-skeleton", - "version": "1.2.5", + "version": "1.3.0", "description": "alibaba lowcode editor skeleton", "main": "lib/index.js", "module": "es/index.js", @@ -19,10 +19,10 @@ ], "dependencies": { "@alifd/next": "^1.20.12", - "@alilc/lowcode-designer": "1.2.5", - "@alilc/lowcode-editor-core": "1.2.5", - "@alilc/lowcode-types": "1.2.5", - "@alilc/lowcode-utils": "1.2.5", + "@alilc/lowcode-designer": "1.3.0", + "@alilc/lowcode-editor-core": "1.3.0", + "@alilc/lowcode-types": "1.3.0", + "@alilc/lowcode-utils": "1.3.0", "classnames": "^2.2.6", "react": "^16.8.1", "react-dom": "^16.8.1" diff --git a/packages/engine/package.json b/packages/engine/package.json index 4caf32c009..7eef6514b3 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine", - "version": "1.2.5", + "version": "1.3.0", "description": "An enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系", "main": "lib/engine-core.js", "module": "es/engine-core.js", @@ -19,15 +19,15 @@ "license": "MIT", "dependencies": { "@alifd/next": "^1.19.12", - "@alilc/lowcode-designer": "1.2.5", - "@alilc/lowcode-editor-core": "1.2.5", - "@alilc/lowcode-editor-skeleton": "1.2.5", + "@alilc/lowcode-designer": "1.3.0", + "@alilc/lowcode-editor-core": "1.3.0", + "@alilc/lowcode-editor-skeleton": "1.3.0", "@alilc/lowcode-engine-ext": "^1.0.0", - "@alilc/lowcode-plugin-designer": "1.2.5", - "@alilc/lowcode-plugin-outline-pane": "1.2.5", - "@alilc/lowcode-shell": "1.2.5", - "@alilc/lowcode-utils": "1.2.5", - "@alilc/lowcode-workspace": "1.2.5", + "@alilc/lowcode-plugin-designer": "1.3.0", + "@alilc/lowcode-plugin-outline-pane": "1.3.0", + "@alilc/lowcode-shell": "1.3.0", + "@alilc/lowcode-utils": "1.3.0", + "@alilc/lowcode-workspace": "1.3.0", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/ignitor/package.json b/packages/ignitor/package.json index f131dc14c3..cb87c297f8 100644 --- a/packages/ignitor/package.json +++ b/packages/ignitor/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-ignitor", - "version": "1.2.5", + "version": "1.3.0", "description": "点火器,bootstrap lce project", "main": "lib/index.js", "private": true, diff --git a/packages/plugin-designer/package.json b/packages/plugin-designer/package.json index d764f7d9ed..a2c0fcf191 100644 --- a/packages/plugin-designer/package.json +++ b/packages/plugin-designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-designer", - "version": "1.2.5", + "version": "1.3.0", "description": "alibaba lowcode editor designer plugin", "files": [ "es", @@ -18,9 +18,9 @@ ], "author": "xiayang.xy", "dependencies": { - "@alilc/lowcode-designer": "1.2.5", - "@alilc/lowcode-editor-core": "1.2.5", - "@alilc/lowcode-utils": "1.2.5", + "@alilc/lowcode-designer": "1.3.0", + "@alilc/lowcode-editor-core": "1.3.0", + "@alilc/lowcode-utils": "1.3.0", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/plugin-outline-pane/package.json b/packages/plugin-outline-pane/package.json index f864356fc8..073830381f 100644 --- a/packages/plugin-outline-pane/package.json +++ b/packages/plugin-outline-pane/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-outline-pane", - "version": "1.2.5", + "version": "1.3.0", "description": "Outline pane for Ali lowCode engine", "files": [ "es", @@ -13,8 +13,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.2.5", - "@alilc/lowcode-utils": "1.2.5", + "@alilc/lowcode-types": "1.3.0", + "@alilc/lowcode-utils": "1.3.0", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/react-renderer/package.json b/packages/react-renderer/package.json index 2970e93410..b1b22f8f4e 100644 --- a/packages/react-renderer/package.json +++ b/packages/react-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-renderer", - "version": "1.2.5", + "version": "1.3.0", "description": "react renderer for ali lowcode engine", "main": "lib/index.js", "module": "es/index.js", @@ -22,7 +22,7 @@ ], "dependencies": { "@alifd/next": "^1.21.16", - "@alilc/lowcode-renderer-core": "1.2.5" + "@alilc/lowcode-renderer-core": "1.3.0" }, "devDependencies": { "@alib/build-scripts": "^0.1.18", diff --git a/packages/react-simulator-renderer/package.json b/packages/react-simulator-renderer/package.json index 030a197082..49778b5df9 100644 --- a/packages/react-simulator-renderer/package.json +++ b/packages/react-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-simulator-renderer", - "version": "1.2.5", + "version": "1.3.0", "description": "react simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -17,10 +17,10 @@ "test:cov": "build-scripts test --config build.test.json --jest-coverage" }, "dependencies": { - "@alilc/lowcode-designer": "1.2.5", - "@alilc/lowcode-react-renderer": "1.2.5", - "@alilc/lowcode-types": "1.2.5", - "@alilc/lowcode-utils": "1.2.5", + "@alilc/lowcode-designer": "1.3.0", + "@alilc/lowcode-react-renderer": "1.3.0", + "@alilc/lowcode-types": "1.3.0", + "@alilc/lowcode-utils": "1.3.0", "classnames": "^2.2.6", "mobx": "^6.3.0", "mobx-react": "^7.2.0", diff --git a/packages/renderer-core/package.json b/packages/renderer-core/package.json index fab0d3f133..bf2afdea1f 100644 --- a/packages/renderer-core/package.json +++ b/packages/renderer-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-renderer-core", - "version": "1.2.5", + "version": "1.3.0", "description": "renderer core", "license": "MIT", "main": "lib/index.js", @@ -16,8 +16,8 @@ }, "dependencies": { "@alilc/lowcode-datasource-engine": "^1.0.0", - "@alilc/lowcode-types": "1.2.5", - "@alilc/lowcode-utils": "1.2.5", + "@alilc/lowcode-types": "1.3.0", + "@alilc/lowcode-utils": "1.3.0", "classnames": "^2.2.6", "debug": "^4.1.1", "fetch-jsonp": "^1.1.3", @@ -32,7 +32,7 @@ "devDependencies": { "@alib/build-scripts": "^0.1.18", "@alifd/next": "^1.26.0", - "@alilc/lowcode-designer": "1.2.5", + "@alilc/lowcode-designer": "1.3.0", "@babel/plugin-transform-typescript": "^7.16.8", "@testing-library/react": "^11.2.2", "@types/classnames": "^2.2.11", diff --git a/packages/shell/package.json b/packages/shell/package.json index 86c4c7d11e..fba14598eb 100644 --- a/packages/shell/package.json +++ b/packages/shell/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-shell", - "version": "1.2.5", + "version": "1.3.0", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -13,12 +13,12 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.2.5", - "@alilc/lowcode-editor-core": "1.2.5", - "@alilc/lowcode-editor-skeleton": "1.2.5", - "@alilc/lowcode-types": "1.2.5", - "@alilc/lowcode-utils": "1.2.5", - "@alilc/lowcode-workspace": "1.2.5", + "@alilc/lowcode-designer": "1.3.0", + "@alilc/lowcode-editor-core": "1.3.0", + "@alilc/lowcode-editor-skeleton": "1.3.0", + "@alilc/lowcode-types": "1.3.0", + "@alilc/lowcode-utils": "1.3.0", + "@alilc/lowcode-workspace": "1.3.0", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", diff --git a/packages/types/package.json b/packages/types/package.json index 52a5e03ae0..8d056e4eed 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-types", - "version": "1.2.5", + "version": "1.3.0", "description": "Types for Ali lowCode engine", "files": [ "es", diff --git a/packages/utils/package.json b/packages/utils/package.json index 976b76341b..2172041323 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-utils", - "version": "1.2.5", + "version": "1.3.0", "description": "Utils for Ali lowCode engine", "files": [ "lib", @@ -14,7 +14,7 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.2.5", + "@alilc/lowcode-types": "1.3.0", "lodash": "^4.17.21", "mobx": "^6.3.0", "react": "^16" diff --git a/packages/workspace/package.json b/packages/workspace/package.json index cbc31f3797..3c58c040e6 100644 --- a/packages/workspace/package.json +++ b/packages/workspace/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-workspace", - "version": "1.2.5", + "version": "1.3.0", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -15,11 +15,11 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.2.5", - "@alilc/lowcode-editor-core": "1.2.5", - "@alilc/lowcode-editor-skeleton": "1.2.5", - "@alilc/lowcode-types": "1.2.5", - "@alilc/lowcode-utils": "1.2.5", + "@alilc/lowcode-designer": "1.3.0", + "@alilc/lowcode-editor-core": "1.3.0", + "@alilc/lowcode-editor-skeleton": "1.3.0", + "@alilc/lowcode-types": "1.3.0", + "@alilc/lowcode-utils": "1.3.0", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", From d8406c5bab142641f7ffc559794e2d5159b0c1f7 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 16 Jan 2024 10:32:47 +0800 Subject: [PATCH 185/219] docs: update resource docs --- docs/docs/api/model/resource.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/docs/api/model/resource.md b/docs/docs/api/model/resource.md index 3977234545..a5fdeaf782 100644 --- a/docs/docs/api/model/resource.md +++ b/docs/docs/api/model/resource.md @@ -15,6 +15,12 @@ sidebar_position: 13 `@type {string}` +### id + +资源 id + +`@type {string}` + ### name 资源名字 @@ -44,3 +50,9 @@ sidebar_position: 13 资源配置信息 `@type {Object}` + +### config + +资源配置信息 + +`@type {Object}` \ No newline at end of file From 7f2b2870aa8d4402069258932a00f8566b7f290a Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Tue, 16 Jan 2024 02:35:43 +0000 Subject: [PATCH 186/219] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 643bdace2b..3b7f1e95c2 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.27", + "version": "1.2.28", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 4dd6f7a352f7ba1cea0774114142abe663b6cc31 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 16 Jan 2024 10:34:26 +0800 Subject: [PATCH 187/219] feat: update comtext menu component --- .../shell/src/components/context-menu.tsx | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/packages/shell/src/components/context-menu.tsx b/packages/shell/src/components/context-menu.tsx index c752e79903..ccd910efc4 100644 --- a/packages/shell/src/components/context-menu.tsx +++ b/packages/shell/src/components/context-menu.tsx @@ -1,20 +1,14 @@ import { createContextMenu, parseContextMenuAsReactNode, parseContextMenuProperties } from '@alilc/lowcode-utils'; import { engineConfig } from '@alilc/lowcode-editor-core'; import { IPublicModelPluginContext, IPublicTypeContextMenuAction } from '@alilc/lowcode-types'; -import React from 'react'; +import React, { useCallback } from 'react'; export function ContextMenu({ children, menus, pluginContext }: { menus: IPublicTypeContextMenuAction[]; children: React.ReactElement[] | React.ReactElement; pluginContext: IPublicModelPluginContext; }): React.ReactElement<any, string | React.JSXElementConstructor<any>> { - if (!engineConfig.get('enableContextMenu')) { - return ( - <>{ children }</> - ); - } - - const handleContextMenu = (event: React.MouseEvent) => { + const handleContextMenu = useCallback((event: React.MouseEvent) => { event.preventDefault(); event.stopPropagation(); @@ -32,7 +26,19 @@ export function ContextMenu({ children, menus, pluginContext }: { } destroyFn = createContextMenu(children, { event }); - }; + }, [menus]); + + if (!engineConfig.get('enableContextMenu')) { + return ( + <>{ children }</> + ); + } + + if (!menus || !menus.length) { + return ( + <>{ children }</> + ); + } // 克隆 children 并添加 onContextMenu 事件处理器 const childrenWithContextMenu = React.Children.map(children, (child) => From 84b4c76db250fb8b644998fcd22e4df88f10b2a6 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 16 Jan 2024 17:16:05 +0800 Subject: [PATCH 188/219] chore: update build-plugin-lce version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8b566e0f0c..213bbc1c45 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "yarn": "^1.22.17", "rimraf": "^3.0.2", "@types/react-router": "5.1.18", - "@alilc/build-plugin-lce": "^0.0.4", + "@alilc/build-plugin-lce": "^0.0.5", "babel-jest": "^26.5.2", "@alilc/lowcode-test-mate": "^1.0.1" }, From a8b9b2b5e13c10dea802bfe1d85f78217e7186a8 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 16 Jan 2024 18:00:18 +0800 Subject: [PATCH 189/219] chore: add "set -e" in build.sh --- .github/workflows/pre build.yml | 34 +++++++++++++++++++++++++++++ packages/shell/src/api/commonUI.tsx | 2 +- scripts/build.sh | 2 ++ 3 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/pre build.yml diff --git a/.github/workflows/pre build.yml b/.github/workflows/pre build.yml new file mode 100644 index 0000000000..e6f7d6479d --- /dev/null +++ b/.github/workflows/pre build.yml @@ -0,0 +1,34 @@ +name: Pre Build + +on: + push: + paths: + - 'packages/**' + - '!packages/**.md' + pull_request: + paths: + - 'packages/**' + - '!packages/**.md' + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Install dependencies and setup + run: npm install && npm run setup + + - name: Build + run: npm run build + + - name: Check build status + run: | + if [ $? -eq 0 ]; then + echo "Build succeeded!" + else + echo "Build failed!" + exit 1 + fi diff --git a/packages/shell/src/api/commonUI.tsx b/packages/shell/src/api/commonUI.tsx index 0a9021fe6a..f25cd232c4 100644 --- a/packages/shell/src/api/commonUI.tsx +++ b/packages/shell/src/api/commonUI.tsx @@ -23,7 +23,7 @@ export class CommonUI implements IPublicApiCommonUI { Form = Form; Icon = Icon; Input = Input; - Loading = Loading; + Loading = Loading as any; Message = Message; Overlay = Overlay; Pagination = Pagination; diff --git a/scripts/build.sh b/scripts/build.sh index 0d96598e62..828bb16d99 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -1,5 +1,7 @@ #!/usr/bin/env bash +set -e + lerna run build \ --scope @alilc/lowcode-types \ --scope @alilc/lowcode-utils \ From 8f8908c83242b6c418cb7486195b3b13d1516782 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 17 Jan 2024 11:08:28 +0800 Subject: [PATCH 190/219] fix(context-menu): fix context menu component instance changed --- packages/shell/src/api/commonUI.tsx | 35 ++++++++++++++++------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/packages/shell/src/api/commonUI.tsx b/packages/shell/src/api/commonUI.tsx index f25cd232c4..69dd104b2a 100644 --- a/packages/shell/src/api/commonUI.tsx +++ b/packages/shell/src/api/commonUI.tsx @@ -8,6 +8,7 @@ import { import { Balloon, Breadcrumb, Button, Card, Checkbox, DatePicker, Dialog, Dropdown, Form, Icon, Input, Loading, Message, Overlay, Pagination, Radio, Search, Select, SplitButton, Step, Switch, Tab, Table, Tree, TreeSelect, Upload, Divider } from '@alifd/next'; import { ContextMenu } from '../components/context-menu'; import { editorSymbol } from '../symbols'; +import { ReactElement } from 'react'; export class CommonUI implements IPublicApiCommonUI { [editorSymbol]: IEditor; @@ -40,8 +41,27 @@ export class CommonUI implements IPublicApiCommonUI { Upload = Upload; Divider = Divider; + ContextMenu: ((props: { + menus: IPublicTypeContextMenuAction[]; + children: React.ReactElement[] | React.ReactElement; + }) => ReactElement) & { + create(menus: IPublicTypeContextMenuAction[], event: MouseEvent | React.MouseEvent): void; + }; + constructor(editor: IEditor) { this[editorSymbol] = editor; + + const innerContextMenu = (props: any) => { + const pluginContext: IPublicModelPluginContext = editor.get('pluginContext') as IPublicModelPluginContext; + return <ContextMenu {...props} pluginContext={pluginContext} />; + }; + + innerContextMenu.create = (menus: IPublicTypeContextMenuAction[], event: MouseEvent) => { + const pluginContext: IPublicModelPluginContext = editor.get('pluginContext') as IPublicModelPluginContext; + return ContextMenu.create(pluginContext, menus, event); + }; + + this.ContextMenu = innerContextMenu; } get Tip() { @@ -55,19 +75,4 @@ export class CommonUI implements IPublicApiCommonUI { get Title() { return InnerTitle; } - - get ContextMenu() { - const editor = this[editorSymbol]; - const innerContextMenu = (props: any) => { - const pluginContext: IPublicModelPluginContext = editor.get('pluginContext') as IPublicModelPluginContext; - return <ContextMenu {...props} pluginContext={pluginContext} />; - }; - - innerContextMenu.create = (menus: IPublicTypeContextMenuAction[], event: MouseEvent) => { - const pluginContext: IPublicModelPluginContext = editor.get('pluginContext') as IPublicModelPluginContext; - return ContextMenu.create(pluginContext, menus, event); - }; - - return innerContextMenu; - } } From 4025a7d2e00f06501121485dcbce7ecdefb7b9ce Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Wed, 17 Jan 2024 06:01:02 +0000 Subject: [PATCH 191/219] chore(release): publish 1.3.1 --- lerna.json | 2 +- packages/designer/package.json | 8 ++++---- packages/editor-core/package.json | 6 +++--- packages/editor-skeleton/package.json | 10 +++++----- packages/engine/package.json | 18 +++++++++--------- packages/ignitor/package.json | 2 +- packages/plugin-designer/package.json | 8 ++++---- packages/plugin-outline-pane/package.json | 6 +++--- packages/react-renderer/package.json | 4 ++-- packages/react-simulator-renderer/package.json | 10 +++++----- packages/renderer-core/package.json | 8 ++++---- packages/shell/package.json | 14 +++++++------- packages/types/package.json | 2 +- packages/utils/package.json | 4 ++-- packages/workspace/package.json | 12 ++++++------ 15 files changed, 57 insertions(+), 57 deletions(-) diff --git a/lerna.json b/lerna.json index 33d4899d0c..7de339c6cd 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "lerna": "4.0.0", - "version": "1.3.0", + "version": "1.3.1", "npmClient": "yarn", "useWorkspaces": true, "packages": [ diff --git a/packages/designer/package.json b/packages/designer/package.json index 5ecf6c1390..ec7c153c80 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-designer", - "version": "1.3.0", + "version": "1.3.1", "description": "Designer for Ali LowCode Engine", "main": "lib/index.js", "module": "es/index.js", @@ -15,9 +15,9 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-editor-core": "1.3.0", - "@alilc/lowcode-types": "1.3.0", - "@alilc/lowcode-utils": "1.3.0", + "@alilc/lowcode-editor-core": "1.3.1", + "@alilc/lowcode-types": "1.3.1", + "@alilc/lowcode-utils": "1.3.1", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/editor-core/package.json b/packages/editor-core/package.json index 888642adf5..f807ef5155 100644 --- a/packages/editor-core/package.json +++ b/packages/editor-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-core", - "version": "1.3.0", + "version": "1.3.1", "description": "Core Api for Ali lowCode engine", "license": "MIT", "main": "lib/index.js", @@ -14,8 +14,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.3.0", - "@alilc/lowcode-utils": "1.3.0", + "@alilc/lowcode-types": "1.3.1", + "@alilc/lowcode-utils": "1.3.1", "classnames": "^2.2.6", "debug": "^4.1.1", "intl-messageformat": "^9.3.1", diff --git a/packages/editor-skeleton/package.json b/packages/editor-skeleton/package.json index 58c5f2e18a..7c14943552 100644 --- a/packages/editor-skeleton/package.json +++ b/packages/editor-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-skeleton", - "version": "1.3.0", + "version": "1.3.1", "description": "alibaba lowcode editor skeleton", "main": "lib/index.js", "module": "es/index.js", @@ -19,10 +19,10 @@ ], "dependencies": { "@alifd/next": "^1.20.12", - "@alilc/lowcode-designer": "1.3.0", - "@alilc/lowcode-editor-core": "1.3.0", - "@alilc/lowcode-types": "1.3.0", - "@alilc/lowcode-utils": "1.3.0", + "@alilc/lowcode-designer": "1.3.1", + "@alilc/lowcode-editor-core": "1.3.1", + "@alilc/lowcode-types": "1.3.1", + "@alilc/lowcode-utils": "1.3.1", "classnames": "^2.2.6", "react": "^16.8.1", "react-dom": "^16.8.1" diff --git a/packages/engine/package.json b/packages/engine/package.json index 7eef6514b3..4b622eaa4b 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine", - "version": "1.3.0", + "version": "1.3.1", "description": "An enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系", "main": "lib/engine-core.js", "module": "es/engine-core.js", @@ -19,15 +19,15 @@ "license": "MIT", "dependencies": { "@alifd/next": "^1.19.12", - "@alilc/lowcode-designer": "1.3.0", - "@alilc/lowcode-editor-core": "1.3.0", - "@alilc/lowcode-editor-skeleton": "1.3.0", + "@alilc/lowcode-designer": "1.3.1", + "@alilc/lowcode-editor-core": "1.3.1", + "@alilc/lowcode-editor-skeleton": "1.3.1", "@alilc/lowcode-engine-ext": "^1.0.0", - "@alilc/lowcode-plugin-designer": "1.3.0", - "@alilc/lowcode-plugin-outline-pane": "1.3.0", - "@alilc/lowcode-shell": "1.3.0", - "@alilc/lowcode-utils": "1.3.0", - "@alilc/lowcode-workspace": "1.3.0", + "@alilc/lowcode-plugin-designer": "1.3.1", + "@alilc/lowcode-plugin-outline-pane": "1.3.1", + "@alilc/lowcode-shell": "1.3.1", + "@alilc/lowcode-utils": "1.3.1", + "@alilc/lowcode-workspace": "1.3.1", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/ignitor/package.json b/packages/ignitor/package.json index cb87c297f8..a32e30783f 100644 --- a/packages/ignitor/package.json +++ b/packages/ignitor/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-ignitor", - "version": "1.3.0", + "version": "1.3.1", "description": "点火器,bootstrap lce project", "main": "lib/index.js", "private": true, diff --git a/packages/plugin-designer/package.json b/packages/plugin-designer/package.json index a2c0fcf191..9fb9a75655 100644 --- a/packages/plugin-designer/package.json +++ b/packages/plugin-designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-designer", - "version": "1.3.0", + "version": "1.3.1", "description": "alibaba lowcode editor designer plugin", "files": [ "es", @@ -18,9 +18,9 @@ ], "author": "xiayang.xy", "dependencies": { - "@alilc/lowcode-designer": "1.3.0", - "@alilc/lowcode-editor-core": "1.3.0", - "@alilc/lowcode-utils": "1.3.0", + "@alilc/lowcode-designer": "1.3.1", + "@alilc/lowcode-editor-core": "1.3.1", + "@alilc/lowcode-utils": "1.3.1", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/plugin-outline-pane/package.json b/packages/plugin-outline-pane/package.json index 073830381f..1539ac6ae3 100644 --- a/packages/plugin-outline-pane/package.json +++ b/packages/plugin-outline-pane/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-outline-pane", - "version": "1.3.0", + "version": "1.3.1", "description": "Outline pane for Ali lowCode engine", "files": [ "es", @@ -13,8 +13,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.3.0", - "@alilc/lowcode-utils": "1.3.0", + "@alilc/lowcode-types": "1.3.1", + "@alilc/lowcode-utils": "1.3.1", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/react-renderer/package.json b/packages/react-renderer/package.json index b1b22f8f4e..b041823e85 100644 --- a/packages/react-renderer/package.json +++ b/packages/react-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-renderer", - "version": "1.3.0", + "version": "1.3.1", "description": "react renderer for ali lowcode engine", "main": "lib/index.js", "module": "es/index.js", @@ -22,7 +22,7 @@ ], "dependencies": { "@alifd/next": "^1.21.16", - "@alilc/lowcode-renderer-core": "1.3.0" + "@alilc/lowcode-renderer-core": "1.3.1" }, "devDependencies": { "@alib/build-scripts": "^0.1.18", diff --git a/packages/react-simulator-renderer/package.json b/packages/react-simulator-renderer/package.json index 49778b5df9..1361535099 100644 --- a/packages/react-simulator-renderer/package.json +++ b/packages/react-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-simulator-renderer", - "version": "1.3.0", + "version": "1.3.1", "description": "react simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -17,10 +17,10 @@ "test:cov": "build-scripts test --config build.test.json --jest-coverage" }, "dependencies": { - "@alilc/lowcode-designer": "1.3.0", - "@alilc/lowcode-react-renderer": "1.3.0", - "@alilc/lowcode-types": "1.3.0", - "@alilc/lowcode-utils": "1.3.0", + "@alilc/lowcode-designer": "1.3.1", + "@alilc/lowcode-react-renderer": "1.3.1", + "@alilc/lowcode-types": "1.3.1", + "@alilc/lowcode-utils": "1.3.1", "classnames": "^2.2.6", "mobx": "^6.3.0", "mobx-react": "^7.2.0", diff --git a/packages/renderer-core/package.json b/packages/renderer-core/package.json index bf2afdea1f..dd48d361f1 100644 --- a/packages/renderer-core/package.json +++ b/packages/renderer-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-renderer-core", - "version": "1.3.0", + "version": "1.3.1", "description": "renderer core", "license": "MIT", "main": "lib/index.js", @@ -16,8 +16,8 @@ }, "dependencies": { "@alilc/lowcode-datasource-engine": "^1.0.0", - "@alilc/lowcode-types": "1.3.0", - "@alilc/lowcode-utils": "1.3.0", + "@alilc/lowcode-types": "1.3.1", + "@alilc/lowcode-utils": "1.3.1", "classnames": "^2.2.6", "debug": "^4.1.1", "fetch-jsonp": "^1.1.3", @@ -32,7 +32,7 @@ "devDependencies": { "@alib/build-scripts": "^0.1.18", "@alifd/next": "^1.26.0", - "@alilc/lowcode-designer": "1.3.0", + "@alilc/lowcode-designer": "1.3.1", "@babel/plugin-transform-typescript": "^7.16.8", "@testing-library/react": "^11.2.2", "@types/classnames": "^2.2.11", diff --git a/packages/shell/package.json b/packages/shell/package.json index fba14598eb..87f71a5ee6 100644 --- a/packages/shell/package.json +++ b/packages/shell/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-shell", - "version": "1.3.0", + "version": "1.3.1", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -13,12 +13,12 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.3.0", - "@alilc/lowcode-editor-core": "1.3.0", - "@alilc/lowcode-editor-skeleton": "1.3.0", - "@alilc/lowcode-types": "1.3.0", - "@alilc/lowcode-utils": "1.3.0", - "@alilc/lowcode-workspace": "1.3.0", + "@alilc/lowcode-designer": "1.3.1", + "@alilc/lowcode-editor-core": "1.3.1", + "@alilc/lowcode-editor-skeleton": "1.3.1", + "@alilc/lowcode-types": "1.3.1", + "@alilc/lowcode-utils": "1.3.1", + "@alilc/lowcode-workspace": "1.3.1", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", diff --git a/packages/types/package.json b/packages/types/package.json index 8d056e4eed..31dadb5ea0 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-types", - "version": "1.3.0", + "version": "1.3.1", "description": "Types for Ali lowCode engine", "files": [ "es", diff --git a/packages/utils/package.json b/packages/utils/package.json index 2172041323..12e3ebc1b3 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-utils", - "version": "1.3.0", + "version": "1.3.1", "description": "Utils for Ali lowCode engine", "files": [ "lib", @@ -14,7 +14,7 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.3.0", + "@alilc/lowcode-types": "1.3.1", "lodash": "^4.17.21", "mobx": "^6.3.0", "react": "^16" diff --git a/packages/workspace/package.json b/packages/workspace/package.json index 3c58c040e6..7af4a7159c 100644 --- a/packages/workspace/package.json +++ b/packages/workspace/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-workspace", - "version": "1.3.0", + "version": "1.3.1", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -15,11 +15,11 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.3.0", - "@alilc/lowcode-editor-core": "1.3.0", - "@alilc/lowcode-editor-skeleton": "1.3.0", - "@alilc/lowcode-types": "1.3.0", - "@alilc/lowcode-utils": "1.3.0", + "@alilc/lowcode-designer": "1.3.1", + "@alilc/lowcode-editor-core": "1.3.1", + "@alilc/lowcode-editor-skeleton": "1.3.1", + "@alilc/lowcode-types": "1.3.1", + "@alilc/lowcode-utils": "1.3.1", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", From 9b19d8f8895415335ffb862051f0ac6e5873ecfe Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 18 Jan 2024 08:00:41 +0800 Subject: [PATCH 192/219] =?UTF-8?q?docs:=20remove=20title=20level=20from?= =?UTF-8?q?=20=E7=A4=BA=E4=BE=8B=20sections=20in=20documentation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/docs/api/common.md | 7 ++++--- docs/docs/api/config.md | 12 ++++++------ docs/docs/api/material.md | 22 +++++++++++----------- docs/docs/api/project.md | 2 +- docs/docs/api/simulatorHost.md | 2 +- 5 files changed, 23 insertions(+), 22 deletions(-) diff --git a/docs/docs/api/common.md b/docs/docs/api/common.md index 6613547ea9..1a70436adf 100644 --- a/docs/docs/api/common.md +++ b/docs/docs/api/common.md @@ -82,7 +82,7 @@ executeTransaction(fn: () => void, type: IPublicEnumTransitionType): void; ``` **@since v1.0.16** -##### 示例 +**示例** ```typescript import { common } from '@alilc/lowcode-engine'; import { IPublicEnumTransitionType } from '@alilc/lowcode-types'; @@ -132,7 +132,8 @@ createIntl(instance: string | object): { **@since v1.0.17** -##### 示例 +**示例** + ```typescript import { common } from '@alilc/lowcode-engine'; import enUS from './en-US.json'; @@ -156,7 +157,7 @@ i18n 转换方法 intl(data: IPublicTypeI18nData | string, params?: object): string; ``` -##### 示例 +**示例** ``` const title = common.utils.intl(node.title) ``` diff --git a/docs/docs/api/config.md b/docs/docs/api/config.md index 9294b9d289..fb631a945f 100644 --- a/docs/docs/api/config.md +++ b/docs/docs/api/config.md @@ -24,7 +24,7 @@ sidebar_position: 8 */ get(key: string, defaultValue?: any): any; ``` -#### 示例 +**示例** ```typescript import { config } from '@alilc/lowcode-engine'; @@ -43,7 +43,7 @@ config.get('keyB', { a: 1 }); */ set(key: string, value: any): void; ``` -#### 示例 +**示例** ```typescript import { config } from '@alilc/lowcode-engine'; @@ -63,7 +63,7 @@ config.set('keyC', 1); has(key: string): boolean; ``` -#### 示例 +**示例** ```typescript import { config } from '@alilc/lowcode-engine'; @@ -81,7 +81,7 @@ config.has('keyD'); */ setConfig(config: { [key: string]: any }): void; ``` -#### 示例 +**示例** ```typescript import { config } from '@alilc/lowcode-engine'; @@ -134,7 +134,7 @@ config.getPreference().set(`${panelName}-pinned-status-isFloat`, false, 'skeleto */ onceGot(key: string): Promise<any>; ``` -#### 示例 +**示例** ```typescript import { config } from '@alilc/lowcode-engine'; @@ -160,7 +160,7 @@ const value = await config.onceGot('keyA'); */ onGot(key: string, fn: (data: any) => void): () => void; ``` -#### 示例 +**示例** ```typescript import { config } from '@alilc/lowcode-engine'; diff --git a/docs/docs/api/material.md b/docs/docs/api/material.md index d237180ca9..b6ef070b2c 100644 --- a/docs/docs/api/material.md +++ b/docs/docs/api/material.md @@ -39,7 +39,7 @@ setAssets(assets: IPublicTypeAssetsJson): void; 相关类型:[IPublicTypeAssetsJson](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/assets-json.ts) -##### 示例 +**示例** 直接在项目中引用 npm 包 ```javascript import { material } from '@alilc/lowcode-engine'; @@ -85,7 +85,7 @@ getAssets(): IPublicTypeAssetsJson; 相关类型:[IPublicTypeAssetsJson](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/assets-json.ts) -##### 示例 +**示例** ```typescript import { material } from '@alilc/lowcode-engine'; @@ -106,7 +106,7 @@ loadIncrementalAssets(incrementalAssets: IPublicTypeAssetsJson): Promise<void>; ``` 相关类型:[IPublicTypeAssetsJson](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/assets-json.ts) -##### 示例 +**示例** ```typescript import { material } from '@alilc/lowcode-engine'; import assets1 from '@alilc/mc-assets-<siteId>/assets.json'; @@ -146,7 +146,7 @@ addBuiltinComponentAction(action: IPublicTypeComponentAction): void; 相关类型:[IPublicTypeComponentAction](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/component-action.ts) -##### 示例 +**示例** 新增设计扩展位,并绑定事件 ```typescript import { material } from '@alilc/lowcode-engine'; @@ -186,7 +186,7 @@ removeBuiltinComponentAction(name: string): void; - lock:锁定,不可编辑 - unlock:解锁,可编辑 -##### 示例 +**示例** ```typescript import { material } from '@alilc/lowcode-engine'; @@ -222,7 +222,7 @@ modifyBuiltinComponentAction( -##### 示例 +**示例** 给原始的 remove 扩展时间添加执行前后的日志 ```typescript import { material } from '@alilc/lowcode-engine'; @@ -335,7 +335,7 @@ getComponentMeta(componentName: string): IPublicModelComponentMeta | null; ``` 相关类型:[IPublicModelComponentMeta](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/component-meta.ts) -##### 示例 +**示例** ```typescript import { material } from '@alilc/lowcode-engine'; @@ -356,7 +356,7 @@ material.getComponentMeta('Input'); ``` 相关类型:[IPublicModelComponentMeta](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/component-meta.ts) -##### 示例 +**示例** ```typescript import { material } from '@alilc/lowcode-engine'; @@ -393,7 +393,7 @@ registerMetadataTransducer( ): void; ``` -##### 示例 +**示例** 给每一个组件的配置添加高级配置面板,其中有一个是否渲染配置项 ```typescript import { material } from '@alilc/lowcode-engine' @@ -475,7 +475,7 @@ material.registerMetadataTransducer((transducer) => { getRegisteredMetadataTransducers(): IPublicTypeMetadataTransducer[]; ``` -##### 示例 +**示例** ```typescript import { material } from '@alilc/lowcode-engine' @@ -496,7 +496,7 @@ onChangeAssets(fn: () => void): IPublicTypeDisposable; 相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts) -##### 示例 +**示例** ```typescript import { material } from '@alilc/lowcode-engine'; diff --git a/docs/docs/api/project.md b/docs/docs/api/project.md index 7998228e2b..49d3193858 100644 --- a/docs/docs/api/project.md +++ b/docs/docs/api/project.md @@ -201,7 +201,7 @@ addPropsTransducer( - [IPublicTypePropsTransducer](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/props-transducer.ts) - [IPublicEnumTransformStage](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/enum/transform-stage.ts) -#### 示例 +**示例** 在保存的时候删除每一个组件的 props.hidden ```typescript import { project } from '@alilc/lowcode-engine'; diff --git a/docs/docs/api/simulatorHost.md b/docs/docs/api/simulatorHost.md index ee8f038fc3..c7f739f6b4 100644 --- a/docs/docs/api/simulatorHost.md +++ b/docs/docs/api/simulatorHost.md @@ -20,7 +20,7 @@ sidebar_position: 3 */ set(key: string, value: any): void; ``` -#### 示例 +**示例** 设置若干用于画布渲染的变量,比如画布大小、locale 等。 以设置画布大小为例: From de738b5d7cfd2eaa4afcbc9583675c8c1095b054 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Thu, 18 Jan 2024 01:06:41 +0000 Subject: [PATCH 193/219] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 3b7f1e95c2..69dddfce2c 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.28", + "version": "1.2.29", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From e6ba79b4d7eab23962c5aae29fca633a9862d173 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 24 Jan 2024 17:02:28 +0800 Subject: [PATCH 194/219] feat(utils): checkPropTypes suport IPublicTypePropType as rule for check --- packages/renderer-core/src/utils/common.ts | 48 ++++- .../renderer-core/tests/utils/common.test.ts | 184 +++++++++++++++++- 2 files changed, 229 insertions(+), 3 deletions(-) diff --git a/packages/renderer-core/src/utils/common.ts b/packages/renderer-core/src/utils/common.ts index 495744acd9..894d2d8ca8 100644 --- a/packages/renderer-core/src/utils/common.ts +++ b/packages/renderer-core/src/utils/common.ts @@ -1,7 +1,7 @@ /* eslint-disable no-console */ /* eslint-disable no-new-func */ import logger from './logger'; -import { IPublicTypeRootSchema, IPublicTypeNodeSchema, IPublicTypeJSSlot } from '@alilc/lowcode-types'; +import { IPublicTypeRootSchema, IPublicTypeNodeSchema, IPublicTypeJSSlot, IPublicTypePropType, IPublicTypeRequiredType, IPublicTypeBasicType } from '@alilc/lowcode-types'; import { isI18nData, isJSExpression } from '@alilc/lowcode-utils'; import { isEmpty } from 'lodash'; import IntlMessageFormat from 'intl-messageformat'; @@ -183,8 +183,54 @@ export function transformArrayToMap(arr: any[], key: string, overwrite = true) { return res; } +export function isBasicType(propType: IPublicTypePropType): propType is IPublicTypeBasicType { + if (!propType) { + return false; + } + return typeof propType === 'string'; +} + +export function isRequiredType(propType: IPublicTypePropType): propType is IPublicTypeRequiredType { + if (!propType) { + return false; + } + return typeof propType === 'object' && propType.type && ['array', 'bool', 'func', 'number', 'object', 'string', 'node', 'element', 'any'].includes(propType.type); +} + +export function transformPropTypesRuleToString(rule: IPublicTypePropType): string { + if (!rule) { + return 'PropTypes.any'; + } + + if (typeof rule === 'string') { + return `PropTypes.${rule}`; + } + + if (isRequiredType(rule)) { + const { type, isRequired } = rule; + return `PropTypes.${type}${isRequired ? '.isRequired' : ''}`; + } + + const { type, value } = rule; + switch (type) { + case 'oneOf': + return `PropTypes.oneOf([${value.map((item: any) => `"${item}"`).join(',')}])`; + case 'oneOfType': + return `PropTypes.oneOfType([${value.map((item: any) => transformPropTypesRuleToString(item)).join(', ')}])`; + case 'arrayOf': + case 'objectOf': + return `PropTypes.${type}(${transformPropTypesRuleToString(value)})`; + case 'shape': + case 'exact': + return `PropTypes.${type}({${value.map((item: any) => `${item.name}: ${transformPropTypesRuleToString(item.propType)}`).join(',')}})`; + } +} + export function checkPropTypes(value: any, name: string, rule: any, componentName: string): boolean { let ruleFunction = rule; + if (typeof rule === 'object') { + ruleFunction = new Function(`"use strict"; const PropTypes = arguments[0]; return ${transformPropTypesRuleToString(rule)}`)(PropTypes2); + } if (typeof rule === 'string') { ruleFunction = new Function(`"use strict"; const PropTypes = arguments[0]; return ${rule}`)(PropTypes2); } diff --git a/packages/renderer-core/tests/utils/common.test.ts b/packages/renderer-core/tests/utils/common.test.ts index 2ee3ed4dcc..45a8e33d7e 100644 --- a/packages/renderer-core/tests/utils/common.test.ts +++ b/packages/renderer-core/tests/utils/common.test.ts @@ -19,6 +19,9 @@ import { parseI18n, parseData, checkPropTypes, + transformPropTypesRuleToString, + isRequiredType, + isBasicType, } from '../../src/utils/common'; import logger from '../../src/utils/logger'; @@ -283,7 +286,7 @@ describe('test capitalizeFirstLetter ', () => { describe('test forEach ', () => { it('should work', () => { const mockFn = jest.fn(); - + forEach(null, mockFn); expect(mockFn).toBeCalledTimes(0); @@ -298,7 +301,7 @@ describe('test forEach ', () => { forEach({ a: 1, b: 2, c: 3 }, mockFn); expect(mockFn).toBeCalledTimes(3); - + const mockFn2 = jest.fn(); forEach({ a: 1 }, mockFn2, { b: 'bbb' }); expect(mockFn2).toHaveBeenCalledWith(1, 'a'); @@ -468,6 +471,28 @@ describe('test parseData ', () => { }); }); +describe('test isBasicType ', () => { + it('should work', () => { + expect(isBasicType(null)).toBeFalsy(); + expect(isBasicType(undefined)).toBeFalsy(); + expect(isBasicType({})).toBeFalsy(); + expect(isBasicType({ type: 'any other type' })).toBeFalsy(); + expect(isBasicType('string')).toBeTruthy(); + }); +}); + +describe('test isRequiredType', () => { + it('should work', () => { + expect(isRequiredType(null)).toBeFalsy(); + expect(isRequiredType(undefined)).toBeFalsy(); + expect(isRequiredType({})).toBeFalsy(); + expect(isRequiredType({ type: 'any other type' })).toBeFalsy(); + expect(isRequiredType('string')).toBeFalsy(); + expect(isRequiredType({ type: 'string' })).toBeTruthy(); + expect(isRequiredType({ type: 'string', isRequired: true })).toBeTruthy(); + }); +}) + describe('checkPropTypes', () => { it('should validate correctly with valid prop type', () => { expect(checkPropTypes(123, 'age', PropTypes.number, 'TestComponent')).toBe(true); @@ -499,4 +524,159 @@ describe('checkPropTypes', () => { const result = checkPropTypes(123, 'age', 123, 'TestComponent'); expect(result).toBe(true); }); + + // oneOf + it('should validate correctly with valid oneOf prop type', () => { + const rule = { + type: 'oneOf', + value: ['News', 'Photos'], + } + expect(transformPropTypesRuleToString(rule)).toBe(`PropTypes.oneOf(["News","Photos"])`); + expect(checkPropTypes('News', 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes('Others', 'type', rule, 'TestComponent')).toBe(false); + }); + + // oneOfType + it('should validate correctly with valid oneOfType prop type', () => { + const rule = { + type: 'oneOfType', + value: ['string', 'number', { + type: 'array', + isRequired: true, + }], + }; + expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.array.isRequired])'); + expect(checkPropTypes(['News', 'Photos'], 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes('News', 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes(123, 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes({}, 'type', rule, 'TestComponent')).toBe(false); + }); + + // arrayOf + it('should validate correctly with valid arrayOf prop type', () => { + const rule = { + type: 'arrayOf', + value: { + type: 'string', + isRequired: true, + }, + }; + expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.arrayOf(PropTypes.string.isRequired)'); + expect(checkPropTypes(['News', 'Photos'], 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes(['News', 123], 'type', rule, 'TestComponent')).toBe(false); + }); + + // objectOf + it('should validate correctly with valid objectOf prop type', () => { + const rule = { + type: 'objectOf', + value: { + type: 'string', + isRequired: true, + }, + }; + expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.objectOf(PropTypes.string.isRequired)'); + expect(checkPropTypes({ a: 'News', b: 'Photos' }, 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes({ a: 'News', b: 123 }, 'type', rule, 'TestComponent')).toBe(false); + }); + + // shape + it('should validate correctly with valid shape prop type', () => { + const rule = { + type: 'shape', + value: [ + { + name: 'a', + propType: { + type: 'string', + isRequired: true, + }, + }, + { + name: 'b', + propType: { + type: 'number', + isRequired: true, + }, + }, + ], + }; + expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.shape({a: PropTypes.string.isRequired,b: PropTypes.number.isRequired})'); + expect(checkPropTypes({ a: 'News', b: 123 }, 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes({ a: 'News', b: 'Photos' }, 'type', rule, 'TestComponent')).toBe(false); + + // isRequired + const rule2 = { + type: 'shape', + value: [ + { + name: 'a', + propType: { + type: 'string', + isRequired: true, + }, + }, + { + name: 'b', + propType: { + type: 'number', + isRequired: false, + }, + }, + ], + }; + expect(transformPropTypesRuleToString(rule2)).toBe('PropTypes.shape({a: PropTypes.string.isRequired,b: PropTypes.number})'); + expect(checkPropTypes({ a: 'News', b: 123 }, 'type', rule2, 'TestComponent')).toBe(true); + expect(checkPropTypes({ b: 123 }, 'type', rule2, 'TestComponent')).toBe(false); + }); + + // exact + it('should validate correctly with valid exact prop type', () => { + const rule = { + type: 'exact', + value: [ + { + name: 'a', + propType: { + type: 'string', + isRequired: true, + }, + }, + { + name: 'b', + propType: { + type: 'number', + isRequired: true, + }, + }, + ], + }; + expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.exact({a: PropTypes.string.isRequired,b: PropTypes.number.isRequired})'); + expect(checkPropTypes({ a: 'News', b: 123 }, 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes({ a: 'News', b: 'Photos' }, 'type', rule, 'TestComponent')).toBe(false); + + // isRequired + const rule2 = { + type: 'exact', + value: [ + { + name: 'a', + propType: { + type: 'string', + isRequired: true, + }, + }, + { + name: 'b', + propType: { + type: 'number', + isRequired: false, + }, + }, + ], + }; + expect(transformPropTypesRuleToString(rule2)).toBe('PropTypes.exact({a: PropTypes.string.isRequired,b: PropTypes.number})'); + expect(checkPropTypes({ a: 'News', b: 123 }, 'type', rule2, 'TestComponent')).toBe(true); + expect(checkPropTypes({ b: 123 }, 'type', rule2, 'TestComponent')).toBe(false); + }); }); \ No newline at end of file From cd67a8cea37af8b801b765b2a4b648fcf6d957c2 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 24 Jan 2024 14:58:56 +0800 Subject: [PATCH 195/219] test(designer): add parse-metadata test --- packages/designer/jest.config.js | 1 + .../builtin-simulator/utils/parse-metadata.ts | 12 +- .../utils/parse-metadata.test.ts | 166 +++++++++++++++++- 3 files changed, 176 insertions(+), 3 deletions(-) diff --git a/packages/designer/jest.config.js b/packages/designer/jest.config.js index f0ad2e861e..3684a48acb 100644 --- a/packages/designer/jest.config.js +++ b/packages/designer/jest.config.js @@ -21,6 +21,7 @@ const jestConfig = { // testMatch: ['**/builtin-hotkey.test.ts'], // testMatch: ['**/selection.test.ts'], // testMatch: ['**/plugin/sequencify.test.ts'], + // testMatch: ['**/builtin-simulator/utils/parse-metadata.test.ts'], transformIgnorePatterns: [ `/node_modules/(?!${esModules})/`, ], diff --git a/packages/designer/src/builtin-simulator/utils/parse-metadata.ts b/packages/designer/src/builtin-simulator/utils/parse-metadata.ts index 5c81340a14..6969a47db5 100644 --- a/packages/designer/src/builtin-simulator/utils/parse-metadata.ts +++ b/packages/designer/src/builtin-simulator/utils/parse-metadata.ts @@ -16,8 +16,16 @@ export const primitiveTypes = [ 'any', ]; +interface LowcodeCheckType { + // isRequired, props, propName, componentName, location, propFullName, secret + (props: any, propName: string, componentName: string, ...rest: any[]): Error | null; + // (...reset: any[]): Error | null; + isRequired?: LowcodeCheckType; + type?: string | object; +} + // eslint-disable-next-line @typescript-eslint/ban-types -function makeRequired(propType: any, lowcodeType: string | object) { +function makeRequired(propType: any, lowcodeType: string | object): LowcodeCheckType { function lowcodeCheckTypeIsRequired(...rest: any[]) { return propType.isRequired(...rest); } @@ -34,7 +42,7 @@ function makeRequired(propType: any, lowcodeType: string | object) { } // eslint-disable-next-line @typescript-eslint/ban-types -function define(propType: any = PropTypes.any, lowcodeType: string | object = {}) { +function define(propType: any = PropTypes.any, lowcodeType: string | object = {}): LowcodeCheckType { if (!propType._inner && propType.name !== 'lowcodeCheckType') { propType.lowcodeType = lowcodeType; } diff --git a/packages/designer/tests/builtin-simulator/utils/parse-metadata.test.ts b/packages/designer/tests/builtin-simulator/utils/parse-metadata.test.ts index 1843a24429..64e19376e2 100644 --- a/packages/designer/tests/builtin-simulator/utils/parse-metadata.test.ts +++ b/packages/designer/tests/builtin-simulator/utils/parse-metadata.test.ts @@ -1,5 +1,7 @@ import '../../fixtures/window'; -import { parseMetadata } from '../../../src/builtin-simulator/utils/parse-metadata'; +import PropTypes from 'prop-types'; +import { LowcodeTypes, parseMetadata, parseProps } from '../../../src/builtin-simulator/utils/parse-metadata'; +import { default as ReactPropTypesSecret } from 'prop-types/lib/ReactPropTypesSecret'; describe('parseMetadata', () => { it('parseMetadata', async () => { @@ -11,3 +13,165 @@ describe('parseMetadata', () => { expect(result).toBeDefined(); }); }); + +describe('LowcodeTypes basic type validators', () => { + it('should validate string types', () => { + const stringValidator = LowcodeTypes.string; + // 对 stringValidator 进行测试 + const props = { testProp: 'This is a string' }; + const propName = 'testProp'; + const componentName = 'TestComponent'; + + const result = stringValidator(props, propName, componentName, 'prop', null, ReactPropTypesSecret); + expect(result).toBeNull(); // No error for valid string + }); + + it('should fail with a non-string type', () => { + const stringValidator = LowcodeTypes.string; + const props = { testProp: 42 }; + const propName = 'testProp'; + const componentName = 'TestComponent'; + + const result = stringValidator(props, propName, componentName, 'prop', null, ReactPropTypesSecret); + expect(result).toBeInstanceOf(Error); // Error for non-string type + expect(result.message).toContain('Invalid prop `testProp` of type `number` supplied to `TestComponent`, expected `string`.'); + }); + + it('should pass with a valid number', () => { + const numberValidator = LowcodeTypes.number; + const props = { testProp: 42 }; + const propName = 'testProp'; + const componentName = 'TestComponent'; + + const result = numberValidator(props, propName, componentName, 'prop', null, ReactPropTypesSecret); + expect(result).toBeNull(); // No error for valid number + }); + + it('should fail with a non-number type', () => { + const numberValidator = LowcodeTypes.number; + const props = { testProp: 'Not a number' }; + const propName = 'testProp'; + const componentName = 'TestComponent'; + + const result = numberValidator(props, propName, componentName, 'prop', null, ReactPropTypesSecret); + expect(result).toBeInstanceOf(Error); // Error for non-number type + expect(result.message).toContain('Invalid prop `testProp` of type `string` supplied to `TestComponent`, expected `number`.'); + }); +}); + +describe('Custom type constructors', () => { + it('should create a custom type validator using define', () => { + const customType = LowcodeTypes.define(PropTypes.string, 'customType'); + const props = { testProp: 'This is a string' }; + const propName = 'testProp'; + const componentName = 'TestComponent'; + + // 测试有效值 + const validResult = customType(props, propName, componentName, 'prop', null, ReactPropTypesSecret); + expect(validResult).toBeNull(); // No error for valid string + + // 测试无效值 + const invalidProps = { testProp: 42 }; + const invalidResult = customType(invalidProps, propName, componentName, 'prop', null, ReactPropTypesSecret); + expect(invalidResult).toBeInstanceOf(Error); // Error for non-string type + + // 验证 lowcodeType 属性 + expect(customType.lowcodeType).toEqual('customType'); + + // 验证 isRequired 属性 + const requiredResult = customType.isRequired(invalidProps, propName, componentName, 'prop', null, ReactPropTypesSecret); + expect(requiredResult).toBeInstanceOf(Error); // Error for non-string type + }); +}); + + +describe('Advanced type constructors', () => { + describe('oneOf Type Validator', () => { + const oneOfValidator = LowcodeTypes.oneOf(['red', 'green', 'blue']); + const propName = 'color'; + const componentName = 'ColorPicker'; + + it('should pass with a valid value', () => { + const props = { color: 'red' }; + const result = oneOfValidator(props, propName, componentName, 'prop', null, ReactPropTypesSecret); + expect(result).toBeNull(); // No error for valid value + }); + + it('should fail with an invalid value', () => { + const props = { color: 'yellow' }; + const result = oneOfValidator(props, propName, componentName, 'prop', null, ReactPropTypesSecret); + expect(result).toBeInstanceOf(Error); // Error for invalid value + expect(result.message).toContain(`Invalid prop \`${propName}\` of value \`yellow\` supplied to \`${componentName}\`, expected one of ["red","green","blue"].`); + }); + + it('should fail with a non-existing value', () => { + const props = { color: 'others' }; + const result = oneOfValidator(props, propName, componentName, 'prop', null, ReactPropTypesSecret); + expect(result).toBeInstanceOf(Error); // Error for non-existing value + expect(result.message).toContain(`Invalid prop \`${propName}\` of value \`others\` supplied to \`${componentName}\`, expected one of ["red","green","blue"].`); + }); + }); +}); + + +describe('parseProps function', () => { + it('should correctly parse propTypes and defaultProps', () => { + const component = { + propTypes: { + name: LowcodeTypes.string, + age: LowcodeTypes.number, + }, + defaultProps: { + name: 'John Doe', + age: 30, + }, + }; + const parsedProps = parseProps(component); + + // 测试结果长度 + expect(parsedProps.length).toBe(2); + + // 测试 name 属性 + const nameProp: any = parsedProps.find(prop => prop.name === 'name'); + expect(nameProp).toBeDefined(); + expect(nameProp.propType).toEqual('string'); + expect(nameProp.defaultValue).toEqual('John Doe'); + + // 测试 age 属性 + const ageProp: any = parsedProps.find(prop => prop.name === 'age'); + expect(ageProp).toBeDefined(); + expect(ageProp.propType).toEqual('number'); + expect(ageProp.defaultValue).toEqual(30); + }); +}); + +describe('parseProps function', () => { + it('should correctly parse propTypes and defaultProps', () => { + const component = { + propTypes: { + name: LowcodeTypes.string, + age: LowcodeTypes.number, + }, + defaultProps: { + name: 'John Doe', + age: 30, + }, + }; + const parsedProps = parseProps(component); + + // 测试结果长度 + expect(parsedProps.length).toBe(2); + + // 测试 name 属性 + const nameProp: any = parsedProps.find(prop => prop.name === 'name'); + expect(nameProp).toBeDefined(); + expect(nameProp.propType).toEqual('string'); + expect(nameProp.defaultValue).toEqual('John Doe'); + + // 测试 age 属性 + const ageProp: any = parsedProps.find(prop => prop.name === 'age'); + expect(ageProp).toBeDefined(); + expect(ageProp.propType).toEqual('number'); + expect(ageProp.defaultValue).toEqual(30); + }); +}); From 0e65f021169aa9ddc9016cfa2929bcfd15fd605e Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 25 Jan 2024 10:38:52 +0800 Subject: [PATCH 196/219] feat(utils): move checkPropTypes to utils module --- packages/renderer-core/src/renderer/base.tsx | 3 +- packages/renderer-core/src/utils/common.ts | 76 ------ .../renderer-core/tests/utils/common.test.ts | 219 ------------------ packages/utils/package.json | 1 + packages/utils/src/check-prop-types.ts | 68 ++++++ packages/utils/src/check-types/index.ts | 4 +- .../src/check-types/is-basic-prop-type.ts | 8 + .../src/check-types/is-required-prop-type.ts | 8 + packages/utils/src/context-menu.tsx | 2 +- packages/utils/src/index.ts | 1 + .../utils/test/src/check-prop-types.test.ts | 190 +++++++++++++++ .../check-types/is-basic-prop-type.test.ts | 11 + .../check-types/is-required-prop-type.test.ts | 13 ++ 13 files changed, 305 insertions(+), 299 deletions(-) create mode 100644 packages/utils/src/check-prop-types.ts create mode 100644 packages/utils/src/check-types/is-basic-prop-type.ts create mode 100644 packages/utils/src/check-types/is-required-prop-type.ts create mode 100644 packages/utils/test/src/check-prop-types.test.ts create mode 100644 packages/utils/test/src/check-types/is-basic-prop-type.test.ts create mode 100644 packages/utils/test/src/check-types/is-required-prop-type.test.ts diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx index 9d9e88ab59..d240095604 100644 --- a/packages/renderer-core/src/renderer/base.tsx +++ b/packages/renderer-core/src/renderer/base.tsx @@ -4,7 +4,7 @@ import classnames from 'classnames'; import { create as createDataSourceEngine } from '@alilc/lowcode-datasource-engine/interpret'; import { IPublicTypeNodeSchema, IPublicTypeNodeData, IPublicTypeJSONValue, IPublicTypeCompositeValue } from '@alilc/lowcode-types'; -import { isI18nData, isJSExpression, isJSFunction } from '@alilc/lowcode-utils'; +import { checkPropTypes, isI18nData, isJSExpression, isJSFunction } from '@alilc/lowcode-utils'; import adapter from '../adapter'; import divFactory from '../components/Div'; import visualDomFactory from '../components/VisualDom'; @@ -21,7 +21,6 @@ import { isFileSchema, transformArrayToMap, transformStringToFunction, - checkPropTypes, getI18n, getFileCssName, capitalizeFirstLetter, diff --git a/packages/renderer-core/src/utils/common.ts b/packages/renderer-core/src/utils/common.ts index 894d2d8ca8..80150f379f 100644 --- a/packages/renderer-core/src/utils/common.ts +++ b/packages/renderer-core/src/utils/common.ts @@ -6,16 +6,11 @@ import { isI18nData, isJSExpression } from '@alilc/lowcode-utils'; import { isEmpty } from 'lodash'; import IntlMessageFormat from 'intl-messageformat'; import pkg from '../../package.json'; -import * as ReactIs from 'react-is'; -import { default as ReactPropTypesSecret } from 'prop-types/lib/ReactPropTypesSecret'; -import { default as factoryWithTypeCheckers } from 'prop-types/factoryWithTypeCheckers'; (window as any).sdkVersion = pkg.version; export { pick, isEqualWith as deepEqual, cloneDeep as clone, isEmpty, throttle, debounce } from 'lodash'; -const PropTypes2 = factoryWithTypeCheckers(ReactIs.isElement, true); - const EXPRESSION_TYPE = { JSEXPRESSION: 'JSExpression', JSFUNCTION: 'JSFunction', @@ -183,77 +178,6 @@ export function transformArrayToMap(arr: any[], key: string, overwrite = true) { return res; } -export function isBasicType(propType: IPublicTypePropType): propType is IPublicTypeBasicType { - if (!propType) { - return false; - } - return typeof propType === 'string'; -} - -export function isRequiredType(propType: IPublicTypePropType): propType is IPublicTypeRequiredType { - if (!propType) { - return false; - } - return typeof propType === 'object' && propType.type && ['array', 'bool', 'func', 'number', 'object', 'string', 'node', 'element', 'any'].includes(propType.type); -} - -export function transformPropTypesRuleToString(rule: IPublicTypePropType): string { - if (!rule) { - return 'PropTypes.any'; - } - - if (typeof rule === 'string') { - return `PropTypes.${rule}`; - } - - if (isRequiredType(rule)) { - const { type, isRequired } = rule; - return `PropTypes.${type}${isRequired ? '.isRequired' : ''}`; - } - - const { type, value } = rule; - switch (type) { - case 'oneOf': - return `PropTypes.oneOf([${value.map((item: any) => `"${item}"`).join(',')}])`; - case 'oneOfType': - return `PropTypes.oneOfType([${value.map((item: any) => transformPropTypesRuleToString(item)).join(', ')}])`; - case 'arrayOf': - case 'objectOf': - return `PropTypes.${type}(${transformPropTypesRuleToString(value)})`; - case 'shape': - case 'exact': - return `PropTypes.${type}({${value.map((item: any) => `${item.name}: ${transformPropTypesRuleToString(item.propType)}`).join(',')}})`; - } -} - -export function checkPropTypes(value: any, name: string, rule: any, componentName: string): boolean { - let ruleFunction = rule; - if (typeof rule === 'object') { - ruleFunction = new Function(`"use strict"; const PropTypes = arguments[0]; return ${transformPropTypesRuleToString(rule)}`)(PropTypes2); - } - if (typeof rule === 'string') { - ruleFunction = new Function(`"use strict"; const PropTypes = arguments[0]; return ${rule}`)(PropTypes2); - } - if (!ruleFunction || typeof ruleFunction !== 'function') { - logger.warn('checkPropTypes should have a function type rule argument'); - return true; - } - const err = ruleFunction( - { - [name]: value, - }, - name, - componentName, - 'prop', - null, - ReactPropTypesSecret, - ); - if (err) { - logger.warn(err); - } - return !err; -} - /** * transform string to a function * @param str function in string form diff --git a/packages/renderer-core/tests/utils/common.test.ts b/packages/renderer-core/tests/utils/common.test.ts index 45a8e33d7e..13b6908d50 100644 --- a/packages/renderer-core/tests/utils/common.test.ts +++ b/packages/renderer-core/tests/utils/common.test.ts @@ -1,4 +1,3 @@ -import factoryWithTypeCheckers from 'prop-types/factoryWithTypeCheckers'; import { isSchema, isFileSchema, @@ -18,17 +17,9 @@ import { parseThisRequiredExpression, parseI18n, parseData, - checkPropTypes, - transformPropTypesRuleToString, - isRequiredType, - isBasicType, } from '../../src/utils/common'; import logger from '../../src/utils/logger'; -var ReactIs = require('react-is'); - -const PropTypes = factoryWithTypeCheckers(ReactIs.isElement, true); - describe('test isSchema', () => { it('should be false when empty value is passed', () => { expect(isSchema(null)).toBeFalsy(); @@ -470,213 +461,3 @@ describe('test parseData ', () => { }); }); - -describe('test isBasicType ', () => { - it('should work', () => { - expect(isBasicType(null)).toBeFalsy(); - expect(isBasicType(undefined)).toBeFalsy(); - expect(isBasicType({})).toBeFalsy(); - expect(isBasicType({ type: 'any other type' })).toBeFalsy(); - expect(isBasicType('string')).toBeTruthy(); - }); -}); - -describe('test isRequiredType', () => { - it('should work', () => { - expect(isRequiredType(null)).toBeFalsy(); - expect(isRequiredType(undefined)).toBeFalsy(); - expect(isRequiredType({})).toBeFalsy(); - expect(isRequiredType({ type: 'any other type' })).toBeFalsy(); - expect(isRequiredType('string')).toBeFalsy(); - expect(isRequiredType({ type: 'string' })).toBeTruthy(); - expect(isRequiredType({ type: 'string', isRequired: true })).toBeTruthy(); - }); -}) - -describe('checkPropTypes', () => { - it('should validate correctly with valid prop type', () => { - expect(checkPropTypes(123, 'age', PropTypes.number, 'TestComponent')).toBe(true); - expect(checkPropTypes('123', 'age', PropTypes.string, 'TestComponent')).toBe(true); - }); - - it('should log a warning and return false with invalid prop type', () => { - expect(checkPropTypes(123, 'age', PropTypes.string, 'TestComponent')).toBe(false); - expect(checkPropTypes('123', 'age', PropTypes.number, 'TestComponent')).toBe(false); - }); - - it('should handle custom rule functions correctly', () => { - const customRule = (props, propName) => { - if (props[propName] !== 123) { - return new Error('Invalid value'); - } - }; - const result = checkPropTypes(123, 'customProp', customRule, 'TestComponent'); - expect(result).toBe(true); - }); - - - it('should interpret and validate a rule given as a string', () => { - const result = checkPropTypes(123, 'age', 'PropTypes.number', 'TestComponent'); - expect(result).toBe(true); - }); - - it('should log a warning for invalid rule type', () => { - const result = checkPropTypes(123, 'age', 123, 'TestComponent'); - expect(result).toBe(true); - }); - - // oneOf - it('should validate correctly with valid oneOf prop type', () => { - const rule = { - type: 'oneOf', - value: ['News', 'Photos'], - } - expect(transformPropTypesRuleToString(rule)).toBe(`PropTypes.oneOf(["News","Photos"])`); - expect(checkPropTypes('News', 'type', rule, 'TestComponent')).toBe(true); - expect(checkPropTypes('Others', 'type', rule, 'TestComponent')).toBe(false); - }); - - // oneOfType - it('should validate correctly with valid oneOfType prop type', () => { - const rule = { - type: 'oneOfType', - value: ['string', 'number', { - type: 'array', - isRequired: true, - }], - }; - expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.array.isRequired])'); - expect(checkPropTypes(['News', 'Photos'], 'type', rule, 'TestComponent')).toBe(true); - expect(checkPropTypes('News', 'type', rule, 'TestComponent')).toBe(true); - expect(checkPropTypes(123, 'type', rule, 'TestComponent')).toBe(true); - expect(checkPropTypes({}, 'type', rule, 'TestComponent')).toBe(false); - }); - - // arrayOf - it('should validate correctly with valid arrayOf prop type', () => { - const rule = { - type: 'arrayOf', - value: { - type: 'string', - isRequired: true, - }, - }; - expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.arrayOf(PropTypes.string.isRequired)'); - expect(checkPropTypes(['News', 'Photos'], 'type', rule, 'TestComponent')).toBe(true); - expect(checkPropTypes(['News', 123], 'type', rule, 'TestComponent')).toBe(false); - }); - - // objectOf - it('should validate correctly with valid objectOf prop type', () => { - const rule = { - type: 'objectOf', - value: { - type: 'string', - isRequired: true, - }, - }; - expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.objectOf(PropTypes.string.isRequired)'); - expect(checkPropTypes({ a: 'News', b: 'Photos' }, 'type', rule, 'TestComponent')).toBe(true); - expect(checkPropTypes({ a: 'News', b: 123 }, 'type', rule, 'TestComponent')).toBe(false); - }); - - // shape - it('should validate correctly with valid shape prop type', () => { - const rule = { - type: 'shape', - value: [ - { - name: 'a', - propType: { - type: 'string', - isRequired: true, - }, - }, - { - name: 'b', - propType: { - type: 'number', - isRequired: true, - }, - }, - ], - }; - expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.shape({a: PropTypes.string.isRequired,b: PropTypes.number.isRequired})'); - expect(checkPropTypes({ a: 'News', b: 123 }, 'type', rule, 'TestComponent')).toBe(true); - expect(checkPropTypes({ a: 'News', b: 'Photos' }, 'type', rule, 'TestComponent')).toBe(false); - - // isRequired - const rule2 = { - type: 'shape', - value: [ - { - name: 'a', - propType: { - type: 'string', - isRequired: true, - }, - }, - { - name: 'b', - propType: { - type: 'number', - isRequired: false, - }, - }, - ], - }; - expect(transformPropTypesRuleToString(rule2)).toBe('PropTypes.shape({a: PropTypes.string.isRequired,b: PropTypes.number})'); - expect(checkPropTypes({ a: 'News', b: 123 }, 'type', rule2, 'TestComponent')).toBe(true); - expect(checkPropTypes({ b: 123 }, 'type', rule2, 'TestComponent')).toBe(false); - }); - - // exact - it('should validate correctly with valid exact prop type', () => { - const rule = { - type: 'exact', - value: [ - { - name: 'a', - propType: { - type: 'string', - isRequired: true, - }, - }, - { - name: 'b', - propType: { - type: 'number', - isRequired: true, - }, - }, - ], - }; - expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.exact({a: PropTypes.string.isRequired,b: PropTypes.number.isRequired})'); - expect(checkPropTypes({ a: 'News', b: 123 }, 'type', rule, 'TestComponent')).toBe(true); - expect(checkPropTypes({ a: 'News', b: 'Photos' }, 'type', rule, 'TestComponent')).toBe(false); - - // isRequired - const rule2 = { - type: 'exact', - value: [ - { - name: 'a', - propType: { - type: 'string', - isRequired: true, - }, - }, - { - name: 'b', - propType: { - type: 'number', - isRequired: false, - }, - }, - ], - }; - expect(transformPropTypesRuleToString(rule2)).toBe('PropTypes.exact({a: PropTypes.string.isRequired,b: PropTypes.number})'); - expect(checkPropTypes({ a: 'News', b: 123 }, 'type', rule2, 'TestComponent')).toBe(true); - expect(checkPropTypes({ b: 123 }, 'type', rule2, 'TestComponent')).toBe(false); - }); -}); \ No newline at end of file diff --git a/packages/utils/package.json b/packages/utils/package.json index 12e3ebc1b3..cc363a7292 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -17,6 +17,7 @@ "@alilc/lowcode-types": "1.3.1", "lodash": "^4.17.21", "mobx": "^6.3.0", + "prop-types": "^15.8.1", "react": "^16" }, "devDependencies": { diff --git a/packages/utils/src/check-prop-types.ts b/packages/utils/src/check-prop-types.ts new file mode 100644 index 0000000000..89555c70b4 --- /dev/null +++ b/packages/utils/src/check-prop-types.ts @@ -0,0 +1,68 @@ +import * as ReactIs from 'react-is'; +import { default as ReactPropTypesSecret } from 'prop-types/lib/ReactPropTypesSecret'; +import { default as factoryWithTypeCheckers } from 'prop-types/factoryWithTypeCheckers'; +import { IPublicTypePropType } from '@alilc/lowcode-types'; +import { isRequiredPropType } from './check-types/is-required-prop-type'; +import { Logger } from './logger'; + +const PropTypes2 = factoryWithTypeCheckers(ReactIs.isElement, true); +const logger = new Logger({ level: 'warn', bizName: 'utils' }); + +export function transformPropTypesRuleToString(rule: IPublicTypePropType): string { + if (!rule) { + return 'PropTypes.any'; + } + + if (typeof rule === 'string') { + return `PropTypes.${rule}`; + } + + if (isRequiredPropType(rule)) { + const { type, isRequired } = rule; + return `PropTypes.${type}${isRequired ? '.isRequired' : ''}`; + } + + const { type, value } = rule; + switch (type) { + case 'oneOf': + return `PropTypes.oneOf([${value.map((item: any) => `"${item}"`).join(',')}])`; + case 'oneOfType': + return `PropTypes.oneOfType([${value.map((item: any) => transformPropTypesRuleToString(item)).join(', ')}])`; + case 'arrayOf': + case 'objectOf': + return `PropTypes.${type}(${transformPropTypesRuleToString(value)})`; + case 'shape': + case 'exact': + return `PropTypes.${type}({${value.map((item: any) => `${item.name}: ${transformPropTypesRuleToString(item.propType)}`).join(',')}})`; + } +} + +export function checkPropTypes(value: any, name: string, rule: any, componentName: string): boolean { + let ruleFunction = rule; + if (typeof rule === 'object') { + // eslint-disable-next-line no-new-func + ruleFunction = new Function(`"use strict"; const PropTypes = arguments[0]; return ${transformPropTypesRuleToString(rule)}`)(PropTypes2); + } + if (typeof rule === 'string') { + // eslint-disable-next-line no-new-func + ruleFunction = new Function(`"use strict"; const PropTypes = arguments[0]; return ${rule}`)(PropTypes2); + } + if (!ruleFunction || typeof ruleFunction !== 'function') { + logger.warn('checkPropTypes should have a function type rule argument'); + return true; + } + const err = ruleFunction( + { + [name]: value, + }, + name, + componentName, + 'prop', + null, + ReactPropTypesSecret, + ); + if (err) { + logger.warn(err); + } + return !err; +} diff --git a/packages/utils/src/check-types/index.ts b/packages/utils/src/check-types/index.ts index 3155926ef2..507259b2c5 100644 --- a/packages/utils/src/check-types/index.ts +++ b/packages/utils/src/check-types/index.ts @@ -23,4 +23,6 @@ export * from './is-location-data'; export * from './is-setting-field'; export * from './is-lowcode-component-type'; export * from './is-lowcode-project-schema'; -export * from './is-component-schema'; \ No newline at end of file +export * from './is-component-schema'; +export * from './is-basic-prop-type'; +export * from './is-required-prop-type'; \ No newline at end of file diff --git a/packages/utils/src/check-types/is-basic-prop-type.ts b/packages/utils/src/check-types/is-basic-prop-type.ts new file mode 100644 index 0000000000..fd3b1b1dcb --- /dev/null +++ b/packages/utils/src/check-types/is-basic-prop-type.ts @@ -0,0 +1,8 @@ +import { IPublicTypeBasicType, IPublicTypePropType } from '@alilc/lowcode-types'; + +export function isBasicPropType(propType: IPublicTypePropType): propType is IPublicTypeBasicType { + if (!propType) { + return false; + } + return typeof propType === 'string'; +} \ No newline at end of file diff --git a/packages/utils/src/check-types/is-required-prop-type.ts b/packages/utils/src/check-types/is-required-prop-type.ts new file mode 100644 index 0000000000..106da78a00 --- /dev/null +++ b/packages/utils/src/check-types/is-required-prop-type.ts @@ -0,0 +1,8 @@ +import { IPublicTypePropType, IPublicTypeRequiredType } from '@alilc/lowcode-types'; + +export function isRequiredPropType(propType: IPublicTypePropType): propType is IPublicTypeRequiredType { + if (!propType) { + return false; + } + return typeof propType === 'object' && propType.type && ['array', 'bool', 'func', 'number', 'object', 'string', 'node', 'element', 'any'].includes(propType.type); +} \ No newline at end of file diff --git a/packages/utils/src/context-menu.tsx b/packages/utils/src/context-menu.tsx index d783a96434..185abbb343 100644 --- a/packages/utils/src/context-menu.tsx +++ b/packages/utils/src/context-menu.tsx @@ -5,7 +5,7 @@ import classNames from 'classnames'; import React from 'react'; import './context-menu.scss'; -const logger = new Logger({ level: 'warn', bizName: 'designer' }); +const logger = new Logger({ level: 'warn', bizName: 'utils' }); const { Item, Divider, PopupItem } = Menu; const MAX_LEVEL = 2; diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index b99ab02073..22bad0e36e 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -32,3 +32,4 @@ export { transactionManager } from './transaction-manager'; export * from './check-types'; export * from './workspace'; export * from './context-menu'; +export { checkPropTypes } from './check-prop-types'; \ No newline at end of file diff --git a/packages/utils/test/src/check-prop-types.test.ts b/packages/utils/test/src/check-prop-types.test.ts new file mode 100644 index 0000000000..c1902bec38 --- /dev/null +++ b/packages/utils/test/src/check-prop-types.test.ts @@ -0,0 +1,190 @@ +import { checkPropTypes, transformPropTypesRuleToString } from '../../src/check-prop-types'; +import PropTypes from 'prop-types'; + +describe('checkPropTypes', () => { + it('should validate correctly with valid prop type', () => { + expect(checkPropTypes(123, 'age', PropTypes.number, 'TestComponent')).toBe(true); + expect(checkPropTypes('123', 'age', PropTypes.string, 'TestComponent')).toBe(true); + }); + + it('should log a warning and return false with invalid prop type', () => { + expect(checkPropTypes(123, 'age', PropTypes.string, 'TestComponent')).toBe(false); + expect(checkPropTypes('123', 'age', PropTypes.number, 'TestComponent')).toBe(false); + }); + + it('should handle custom rule functions correctly', () => { + const customRule = (props, propName) => { + if (props[propName] !== 123) { + return new Error('Invalid value'); + } + }; + const result = checkPropTypes(123, 'customProp', customRule, 'TestComponent'); + expect(result).toBe(true); + }); + + + it('should interpret and validate a rule given as a string', () => { + const result = checkPropTypes(123, 'age', 'PropTypes.number', 'TestComponent'); + expect(result).toBe(true); + }); + + it('should log a warning for invalid rule type', () => { + const result = checkPropTypes(123, 'age', 123, 'TestComponent'); + expect(result).toBe(true); + }); + + // oneOf + it('should validate correctly with valid oneOf prop type', () => { + const rule = { + type: 'oneOf', + value: ['News', 'Photos'], + } + expect(transformPropTypesRuleToString(rule)).toBe(`PropTypes.oneOf(["News","Photos"])`); + expect(checkPropTypes('News', 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes('Others', 'type', rule, 'TestComponent')).toBe(false); + }); + + // oneOfType + it('should validate correctly with valid oneOfType prop type', () => { + const rule = { + type: 'oneOfType', + value: ['string', 'number', { + type: 'array', + isRequired: true, + }], + }; + expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.array.isRequired])'); + expect(checkPropTypes(['News', 'Photos'], 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes('News', 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes(123, 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes({}, 'type', rule, 'TestComponent')).toBe(false); + }); + + // arrayOf + it('should validate correctly with valid arrayOf prop type', () => { + const rule = { + type: 'arrayOf', + value: { + type: 'string', + isRequired: true, + }, + }; + expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.arrayOf(PropTypes.string.isRequired)'); + expect(checkPropTypes(['News', 'Photos'], 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes(['News', 123], 'type', rule, 'TestComponent')).toBe(false); + }); + + // objectOf + it('should validate correctly with valid objectOf prop type', () => { + const rule = { + type: 'objectOf', + value: { + type: 'string', + isRequired: true, + }, + }; + expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.objectOf(PropTypes.string.isRequired)'); + expect(checkPropTypes({ a: 'News', b: 'Photos' }, 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes({ a: 'News', b: 123 }, 'type', rule, 'TestComponent')).toBe(false); + }); + + // shape + it('should validate correctly with valid shape prop type', () => { + const rule = { + type: 'shape', + value: [ + { + name: 'a', + propType: { + type: 'string', + isRequired: true, + }, + }, + { + name: 'b', + propType: { + type: 'number', + isRequired: true, + }, + }, + ], + }; + expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.shape({a: PropTypes.string.isRequired,b: PropTypes.number.isRequired})'); + expect(checkPropTypes({ a: 'News', b: 123 }, 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes({ a: 'News', b: 'Photos' }, 'type', rule, 'TestComponent')).toBe(false); + + // isRequired + const rule2 = { + type: 'shape', + value: [ + { + name: 'a', + propType: { + type: 'string', + isRequired: true, + }, + }, + { + name: 'b', + propType: { + type: 'number', + isRequired: false, + }, + }, + ], + }; + expect(transformPropTypesRuleToString(rule2)).toBe('PropTypes.shape({a: PropTypes.string.isRequired,b: PropTypes.number})'); + expect(checkPropTypes({ a: 'News', b: 123 }, 'type', rule2, 'TestComponent')).toBe(true); + expect(checkPropTypes({ b: 123 }, 'type', rule2, 'TestComponent')).toBe(false); + }); + + // exact + it('should validate correctly with valid exact prop type', () => { + const rule = { + type: 'exact', + value: [ + { + name: 'a', + propType: { + type: 'string', + isRequired: true, + }, + }, + { + name: 'b', + propType: { + type: 'number', + isRequired: true, + }, + }, + ], + }; + expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.exact({a: PropTypes.string.isRequired,b: PropTypes.number.isRequired})'); + expect(checkPropTypes({ a: 'News', b: 123 }, 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes({ a: 'News', b: 'Photos' }, 'type', rule, 'TestComponent')).toBe(false); + + // isRequired + const rule2 = { + type: 'exact', + value: [ + { + name: 'a', + propType: { + type: 'string', + isRequired: true, + }, + }, + { + name: 'b', + propType: { + type: 'number', + isRequired: false, + }, + }, + ], + }; + expect(transformPropTypesRuleToString(rule2)).toBe('PropTypes.exact({a: PropTypes.string.isRequired,b: PropTypes.number})'); + expect(checkPropTypes({ a: 'News', b: 123 }, 'type', rule2, 'TestComponent')).toBe(true); + expect(checkPropTypes({ b: 123 }, 'type', rule2, 'TestComponent')).toBe(false); + }); +}); \ No newline at end of file diff --git a/packages/utils/test/src/check-types/is-basic-prop-type.test.ts b/packages/utils/test/src/check-types/is-basic-prop-type.test.ts new file mode 100644 index 0000000000..81a1bf0d34 --- /dev/null +++ b/packages/utils/test/src/check-types/is-basic-prop-type.test.ts @@ -0,0 +1,11 @@ +import { isBasicPropType } from '../../../src'; + +describe('test isBasicPropType ', () => { + it('should work', () => { + expect(isBasicPropType(null)).toBeFalsy(); + expect(isBasicPropType(undefined)).toBeFalsy(); + expect(isBasicPropType({})).toBeFalsy(); + expect(isBasicPropType({ type: 'any other type' })).toBeFalsy(); + expect(isBasicPropType('string')).toBeTruthy(); + }); +}); \ No newline at end of file diff --git a/packages/utils/test/src/check-types/is-required-prop-type.test.ts b/packages/utils/test/src/check-types/is-required-prop-type.test.ts new file mode 100644 index 0000000000..25515f9aab --- /dev/null +++ b/packages/utils/test/src/check-types/is-required-prop-type.test.ts @@ -0,0 +1,13 @@ +import { isRequiredPropType } from '../../../src'; + +describe('test isRequiredType', () => { + it('should work', () => { + expect(isRequiredPropType(null)).toBeFalsy(); + expect(isRequiredPropType(undefined)).toBeFalsy(); + expect(isRequiredPropType({})).toBeFalsy(); + expect(isRequiredPropType({ type: 'any other type' })).toBeFalsy(); + expect(isRequiredPropType('string')).toBeFalsy(); + expect(isRequiredPropType({ type: 'string' })).toBeTruthy(); + expect(isRequiredPropType({ type: 'string', isRequired: true })).toBeTruthy(); + }); +}) From dca3448cbf52d6f96d7219858f6b2aed6609cf02 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 25 Jan 2024 15:45:26 +0800 Subject: [PATCH 197/219] chore(editor-core): init test --- .github/workflows/test packages.yml | 18 +++++++++++++++++- packages/editor-core/build.test.json | 9 +++++++++ packages/editor-core/jest.config.js | 26 ++++++++++++++++++++++++++ packages/editor-core/package.json | 4 +++- 4 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 packages/editor-core/build.test.json create mode 100644 packages/editor-core/jest.config.js diff --git a/.github/workflows/test packages.yml b/.github/workflows/test packages.yml index 4ee9b4156c..abb2973708 100644 --- a/.github/workflows/test packages.yml +++ b/.github/workflows/test packages.yml @@ -105,4 +105,20 @@ jobs: run: npm i && npm run setup:skip-build - name: test - run: cd packages/utils && npm test \ No newline at end of file + run: cd packages/utils && npm test + + test-editor-core: + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v2 + + - uses: actions/setup-node@v2 + with: + node-version: '14' + + - name: install + run: npm i && npm run setup:skip-build + + - name: test + run: cd packages/editor-core && npm test \ No newline at end of file diff --git a/packages/editor-core/build.test.json b/packages/editor-core/build.test.json new file mode 100644 index 0000000000..10d18109b8 --- /dev/null +++ b/packages/editor-core/build.test.json @@ -0,0 +1,9 @@ +{ + "plugins": [ + "@alilc/build-plugin-lce", + "@alilc/lowcode-test-mate/plugin/index.ts" + ], + "babelPlugins": [ + ["@babel/plugin-proposal-private-property-in-object", { "loose": true }] + ] +} diff --git a/packages/editor-core/jest.config.js b/packages/editor-core/jest.config.js new file mode 100644 index 0000000000..e8441e3dbb --- /dev/null +++ b/packages/editor-core/jest.config.js @@ -0,0 +1,26 @@ +const fs = require('fs'); +const { join } = require('path'); +const esModules = [].join('|'); +const pkgNames = fs.readdirSync(join('..')).filter(pkgName => !pkgName.startsWith('.')); + +const jestConfig = { + transformIgnorePatterns: [ + `/node_modules/(?!${esModules})/`, + ], + moduleFileExtensions: ['ts', 'tsx', 'js', 'json'], + collectCoverage: false, + collectCoverageFrom: [ + 'src/**/*.ts', + '!src/**/*.d.ts', + '!src/icons/**', + '!src/locale/**', + '!**/node_modules/**', + '!**/vendor/**', + ], +}; + +// 只对本仓库内的 pkg 做 mapping +jestConfig.moduleNameMapper = {}; +jestConfig.moduleNameMapper[`^@alilc/lowcode\\-(${pkgNames.join('|')})$`] = '<rootDir>/../$1/src'; + +module.exports = jestConfig; \ No newline at end of file diff --git a/packages/editor-core/package.json b/packages/editor-core/package.json index f807ef5155..98644ad3d6 100644 --- a/packages/editor-core/package.json +++ b/packages/editor-core/package.json @@ -10,7 +10,9 @@ "es" ], "scripts": { - "build": "build-scripts build" + "build": "build-scripts build", + "test": "build-scripts test --config build.test.json", + "test:cov": "build-scripts test --config build.test.json --jest-coverage" }, "dependencies": { "@alifd/next": "^1.19.16", From 947c6218225e8b88df604cb3fa964e1298b18b84 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 25 Jan 2024 15:47:48 +0800 Subject: [PATCH 198/219] test(utils): add more test case for checkPropTypes --- packages/utils/src/check-prop-types.ts | 10 ++- .../utils/test/src/check-prop-types.test.ts | 65 +++++++++++++++++++ 2 files changed, 72 insertions(+), 3 deletions(-) diff --git a/packages/utils/src/check-prop-types.ts b/packages/utils/src/check-prop-types.ts index 89555c70b4..dc9ce31ed5 100644 --- a/packages/utils/src/check-prop-types.ts +++ b/packages/utils/src/check-prop-types.ts @@ -8,13 +8,13 @@ import { Logger } from './logger'; const PropTypes2 = factoryWithTypeCheckers(ReactIs.isElement, true); const logger = new Logger({ level: 'warn', bizName: 'utils' }); -export function transformPropTypesRuleToString(rule: IPublicTypePropType): string { +export function transformPropTypesRuleToString(rule: IPublicTypePropType | string): string { if (!rule) { return 'PropTypes.any'; } if (typeof rule === 'string') { - return `PropTypes.${rule}`; + return rule.startsWith('PropTypes.') ? rule : `PropTypes.${rule}`; } if (isRequiredPropType(rule)) { @@ -34,7 +34,11 @@ export function transformPropTypesRuleToString(rule: IPublicTypePropType): strin case 'shape': case 'exact': return `PropTypes.${type}({${value.map((item: any) => `${item.name}: ${transformPropTypesRuleToString(item.propType)}`).join(',')}})`; + default: + logger.error(`Unknown prop type: ${type}`); } + + return 'PropTypes.any'; } export function checkPropTypes(value: any, name: string, rule: any, componentName: string): boolean { @@ -45,7 +49,7 @@ export function checkPropTypes(value: any, name: string, rule: any, componentNam } if (typeof rule === 'string') { // eslint-disable-next-line no-new-func - ruleFunction = new Function(`"use strict"; const PropTypes = arguments[0]; return ${rule}`)(PropTypes2); + ruleFunction = new Function(`"use strict"; const PropTypes = arguments[0]; return ${transformPropTypesRuleToString(rule)}`)(PropTypes2); } if (!ruleFunction || typeof ruleFunction !== 'function') { logger.warn('checkPropTypes should have a function type rule argument'); diff --git a/packages/utils/test/src/check-prop-types.test.ts b/packages/utils/test/src/check-prop-types.test.ts index c1902bec38..74146f2d94 100644 --- a/packages/utils/test/src/check-prop-types.test.ts +++ b/packages/utils/test/src/check-prop-types.test.ts @@ -12,6 +12,26 @@ describe('checkPropTypes', () => { expect(checkPropTypes('123', 'age', PropTypes.number, 'TestComponent')).toBe(false); }); + it('should validate correctly with valid object prop type', () => { + expect(checkPropTypes({ a: 123 }, 'age', PropTypes.object, 'TestComponent')).toBe(true); + expect(checkPropTypes({ a: '123' }, 'age', PropTypes.object, 'TestComponent')).toBe(true); + }); + + it('should validate correctly with valid object string prop type', () => { + expect(checkPropTypes({ a: 123 }, 'age', 'object', 'TestComponent')).toBe(true); + expect(checkPropTypes({ a: '123' }, 'age', 'object', 'TestComponent')).toBe(true); + }); + + it('should validate correctly with valid isRequired prop type', () => { + const rule = { + type: 'string', + isRequired: true, + }; + expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.string.isRequired'); + expect(checkPropTypes('News', 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes(undefined, 'type', rule, 'TestComponent')).toBe(false); + }); + it('should handle custom rule functions correctly', () => { const customRule = (props, propName) => { if (props[propName] !== 123) { @@ -28,6 +48,11 @@ describe('checkPropTypes', () => { expect(result).toBe(true); }); + it('should interpret and validate a rule given as a string', () => { + expect(checkPropTypes(123, 'age', 'number', 'TestComponent')).toBe(true); + expect(checkPropTypes('123', 'age', 'string', 'TestComponent')).toBe(true); + }); + it('should log a warning for invalid rule type', () => { const result = checkPropTypes(123, 'age', 123, 'TestComponent'); expect(result).toBe(true); @@ -60,6 +85,46 @@ describe('checkPropTypes', () => { expect(checkPropTypes({}, 'type', rule, 'TestComponent')).toBe(false); }); + it('should validate correctly with valid oneOfType prop type', () => { + const rule = { + type: 'oneOfType', + value: [ + 'bool', + { + type: 'shape', + value: [ + { + name: 'type', + propType: { + type: 'oneOf', + value: ['JSExpression'], + } + }, + { + name: 'value', + propType: 'string', + }, + ], + }, + ], + }; + expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.oneOfType([PropTypes.bool, PropTypes.shape({type: PropTypes.oneOf(["JSExpression"]),value: PropTypes.string})])'); + expect(checkPropTypes(true, 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes({ type: 'JSExpression', value: '1 + 1 === 2' }, 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes({ type: 'JSExpression' }, 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes({ type: 'JSExpression', value: 123 }, 'type', rule, 'TestComponent')).toBe(false); + }); + + it('should log a warning for invalid type', () => { + const rule = { + type: 'inval', + value: ['News', 'Photos'], + } + expect(transformPropTypesRuleToString(rule)).toBe('PropTypes.any'); + expect(checkPropTypes('News', 'type', rule, 'TestComponent')).toBe(true); + expect(checkPropTypes('Others', 'type', rule, 'TestComponent')).toBe(true); + }); + // arrayOf it('should validate correctly with valid arrayOf prop type', () => { const rule = { From b3880e9a96c70d750f8f8487913bf6329cdcfb92 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 25 Jan 2024 15:55:32 +0800 Subject: [PATCH 199/219] feat(command): add command apis --- packages/designer/src/plugin/plugin-types.ts | 2 + packages/editor-core/src/command.ts | 91 +++ packages/editor-core/src/index.ts | 1 + packages/editor-core/test/command.test.ts | 326 +++++++++++ packages/engine/src/engine-core.ts | 29 + .../src/inner-plugins/default-command.ts | 524 ++++++++++++++++++ .../inner-plugins/default-command.test.ts | 110 ++++ packages/renderer-core/src/utils/common.ts | 2 +- packages/shell/src/api/command.ts | 46 ++ packages/shell/src/api/index.ts | 3 +- packages/shell/src/index.ts | 2 + packages/shell/src/symbols.ts | 3 +- packages/types/src/shell/api/command.ts | 34 ++ packages/types/src/shell/api/index.ts | 1 + .../types/src/shell/model/plugin-context.ts | 3 + packages/types/src/shell/type/command.ts | 71 +++ packages/types/src/shell/type/index.ts | 3 +- packages/types/src/shell/type/plugin-meta.ts | 8 + .../workspace/src/context/base-context.ts | 7 + 19 files changed, 1262 insertions(+), 4 deletions(-) create mode 100644 packages/editor-core/src/command.ts create mode 100644 packages/editor-core/test/command.test.ts create mode 100644 packages/engine/src/inner-plugins/default-command.ts create mode 100644 packages/engine/tests/inner-plugins/default-command.test.ts create mode 100644 packages/shell/src/api/command.ts create mode 100644 packages/types/src/shell/api/command.ts create mode 100644 packages/types/src/shell/type/command.ts diff --git a/packages/designer/src/plugin/plugin-types.ts b/packages/designer/src/plugin/plugin-types.ts index d648067a36..cfc38866f5 100644 --- a/packages/designer/src/plugin/plugin-types.ts +++ b/packages/designer/src/plugin/plugin-types.ts @@ -19,6 +19,7 @@ import { IPublicModelWindow, IPublicEnumPluginRegisterLevel, IPublicApiCommonUI, + IPublicApiCommand, } from '@alilc/lowcode-types'; import PluginContext from './plugin-context'; @@ -63,6 +64,7 @@ export interface ILowCodePluginContextPrivate { set registerLevel(level: IPublicEnumPluginRegisterLevel); set isPluginRegisteredInWorkspace(flag: boolean); set commonUI(commonUI: IPublicApiCommonUI); + set command(command: IPublicApiCommand); } export interface ILowCodePluginContextApiAssembler { assembleApis( diff --git a/packages/editor-core/src/command.ts b/packages/editor-core/src/command.ts new file mode 100644 index 0000000000..7facc33d94 --- /dev/null +++ b/packages/editor-core/src/command.ts @@ -0,0 +1,91 @@ +import { IPublicApiCommand, IPublicEnumTransitionType, IPublicModelPluginContext, IPublicTypeCommand, IPublicTypeCommandHandlerArgs, IPublicTypeListCommand } from '@alilc/lowcode-types'; +import { checkPropTypes } from '@alilc/lowcode-utils'; +export interface ICommand extends Omit<IPublicApiCommand, 'registerCommand' | 'batchExecuteCommand'> { + registerCommand(command: IPublicTypeCommand, options?: { + commandScope?: string; + }): void; + + batchExecuteCommand(commands: { name: string; args: IPublicTypeCommandHandlerArgs }[], pluginContext?: IPublicModelPluginContext): void; +} + +export interface ICommandOptions { + commandScope?: string; +} + +export class Command implements ICommand { + private commands: Map<string, IPublicTypeCommand> = new Map(); + private commandErrors: Function[] = []; + + registerCommand(command: IPublicTypeCommand, options?: ICommandOptions): void { + if (!options?.commandScope) { + throw new Error('plugin meta.commandScope is required.'); + } + const name = `${options.commandScope}:${command.name}`; + if (this.commands.has(name)) { + throw new Error(`Command '${command.name}' is already registered.`); + } + this.commands.set(name, { + ...command, + name, + }); + } + + unregisterCommand(name: string): void { + if (!this.commands.has(name)) { + throw new Error(`Command '${name}' is not registered.`); + } + this.commands.delete(name); + } + + executeCommand(name: string, args: IPublicTypeCommandHandlerArgs): void { + const command = this.commands.get(name); + if (!command) { + throw new Error(`Command '${name}' is not registered.`); + } + command.parameters?.forEach(d => { + if (!checkPropTypes(args[d.name], d.name, d.propType, 'command')) { + throw new Error(`Command '${name}' arguments ${d.name} is invalid.`); + } + }); + try { + command.handler(args); + } catch (error) { + if (this.commandErrors && this.commandErrors.length) { + this.commandErrors.forEach(callback => callback(name, error)); + } else { + throw error; + } + } + } + + batchExecuteCommand(commands: { name: string; args: IPublicTypeCommandHandlerArgs }[], pluginContext: IPublicModelPluginContext): void { + if (!commands || !commands.length) { + return; + } + pluginContext.common.utils.executeTransaction(() => { + commands.forEach(command => this.executeCommand(command.name, command.args)); + }, IPublicEnumTransitionType.REPAINT); + } + + listCommands(): IPublicTypeListCommand[] { + return Array.from(this.commands.values()).map(d => { + const result: IPublicTypeListCommand = { + name: d.name, + }; + + if (d.description) { + result.description = d.description; + } + + if (d.parameters) { + result.parameters = d.parameters; + } + + return result; + }); + } + + onCommandError(callback: (name: string, error: Error) => void): void { + this.commandErrors.push(callback); + } +} diff --git a/packages/editor-core/src/index.ts b/packages/editor-core/src/index.ts index 9b0542bdaf..c4a54bccde 100644 --- a/packages/editor-core/src/index.ts +++ b/packages/editor-core/src/index.ts @@ -6,3 +6,4 @@ export * from './hotkey'; export * from './widgets'; export * from './config'; export * from './event-bus'; +export * from './command'; diff --git a/packages/editor-core/test/command.test.ts b/packages/editor-core/test/command.test.ts new file mode 100644 index 0000000000..bb2e15943d --- /dev/null +++ b/packages/editor-core/test/command.test.ts @@ -0,0 +1,326 @@ +import { Command } from '../src/command'; + +describe('Command', () => { + let commandInstance; + let mockHandler; + + beforeEach(() => { + commandInstance = new Command(); + mockHandler = jest.fn(); + }); + + describe('registerCommand', () => { + it('should register a command successfully', () => { + const command = { + name: 'testCommand', + handler: mockHandler, + }; + commandInstance.registerCommand(command, { commandScope: 'testScope' }); + + const registeredCommand = commandInstance.listCommands().find(c => c.name === 'testScope:testCommand'); + expect(registeredCommand).toBeDefined(); + expect(registeredCommand.name).toBe('testScope:testCommand'); + }); + + it('should throw an error if commandScope is not provided', () => { + const command = { + name: 'testCommand', + handler: mockHandler, + }; + + expect(() => { + commandInstance.registerCommand(command); + }).toThrow('plugin meta.commandScope is required.'); + }); + + it('should throw an error if command is already registered', () => { + const command = { + name: 'testCommand', + handler: mockHandler, + }; + commandInstance.registerCommand(command, { commandScope: 'testScope' }); + + expect(() => { + commandInstance.registerCommand(command, { commandScope: 'testScope' }); + }).toThrow(`Command 'testCommand' is already registered.`); + }); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); +}); + +describe('unregisterCommand', () => { + let commandInstance; + let mockHandler; + + beforeEach(() => { + commandInstance = new Command(); + mockHandler = jest.fn(); + // 先注册一个命令以便之后注销 + const command = { + name: 'testCommand', + handler: mockHandler, + }; + commandInstance.registerCommand(command, { commandScope: 'testScope' }); + }); + + it('should unregister a command successfully', () => { + const commandName = 'testScope:testCommand'; + expect(commandInstance.listCommands().find(c => c.name === commandName)).toBeDefined(); + + commandInstance.unregisterCommand(commandName); + + expect(commandInstance.listCommands().find(c => c.name === commandName)).toBeUndefined(); + }); + + it('should throw an error if the command is not registered', () => { + const nonExistingCommandName = 'testScope:nonExistingCommand'; + expect(() => { + commandInstance.unregisterCommand(nonExistingCommandName); + }).toThrow(`Command '${nonExistingCommandName}' is not registered.`); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); +}); + +describe('executeCommand', () => { + let commandInstance; + let mockHandler; + + beforeEach(() => { + commandInstance = new Command(); + mockHandler = jest.fn(); + // 注册一个带参数校验的命令 + const command = { + name: 'testCommand', + handler: mockHandler, + parameters: [ + { name: 'param1', propType: 'string' }, + { name: 'param2', propType: 'number' } + ], + }; + commandInstance.registerCommand(command, { commandScope: 'testScope' }); + }); + + it('should execute a command successfully', () => { + const commandName = 'testScope:testCommand'; + const args = { param1: 'test', param2: 42 }; + + commandInstance.executeCommand(commandName, args); + + expect(mockHandler).toHaveBeenCalledWith(args); + }); + + it('should throw an error if the command is not registered', () => { + const nonExistingCommandName = 'testScope:nonExistingCommand'; + expect(() => { + commandInstance.executeCommand(nonExistingCommandName, {}); + }).toThrow(`Command '${nonExistingCommandName}' is not registered.`); + }); + + it('should throw an error if arguments are invalid', () => { + const commandName = 'testScope:testCommand'; + const invalidArgs = { param1: 'test', param2: 'not-a-number' }; // param2 should be a number + + expect(() => { + commandInstance.executeCommand(commandName, invalidArgs); + }).toThrow(`Command '${commandName}' arguments param2 is invalid.`); + }); + + it('should handle errors thrown by the command handler', () => { + const commandName = 'testScope:testCommand'; + const args = { param1: 'test', param2: 42 }; + const errorMessage = 'Command handler error'; + mockHandler.mockImplementation(() => { + throw new Error(errorMessage); + }); + + expect(() => { + commandInstance.executeCommand(commandName, args); + }).toThrow(errorMessage); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); +}); + +describe('batchExecuteCommand', () => { + let commandInstance; + let mockHandler; + let mockExecuteTransaction; + let mockPluginContext; + + beforeEach(() => { + commandInstance = new Command(); + mockHandler = jest.fn(); + mockExecuteTransaction = jest.fn(callback => callback()); + mockPluginContext = { + common: { + utils: { + executeTransaction: mockExecuteTransaction + } + } + }; + + // 注册几个命令 + const command1 = { + name: 'testCommand1', + handler: mockHandler, + }; + const command2 = { + name: 'testCommand2', + handler: mockHandler, + }; + commandInstance.registerCommand(command1, { commandScope: 'testScope' }); + commandInstance.registerCommand(command2, { commandScope: 'testScope' }); + }); + + it('should execute a batch of commands', () => { + const commands = [ + { name: 'testScope:testCommand1', args: { param: 'value1' } }, + { name: 'testScope:testCommand2', args: { param: 'value2' } }, + ]; + + commandInstance.batchExecuteCommand(commands, mockPluginContext); + + expect(mockExecuteTransaction).toHaveBeenCalledTimes(1); + expect(mockHandler).toHaveBeenCalledWith({ param: 'value1' }); + expect(mockHandler).toHaveBeenCalledWith({ param: 'value2' }); + }); + + it('should not execute anything if commands array is empty', () => { + commandInstance.batchExecuteCommand([], mockPluginContext); + + expect(mockExecuteTransaction).not.toHaveBeenCalled(); + expect(mockHandler).not.toHaveBeenCalled(); + }); + + it('should handle errors thrown during command execution', () => { + const errorMessage = 'Command handler error'; + mockHandler.mockImplementation(() => { + throw new Error(errorMessage); + }); + + const commands = [ + { name: 'testScope:testCommand1', args: { param: 'value1' } }, + { name: 'testScope:testCommand2', args: { param: 'value2' } }, + ]; + + expect(() => { + commandInstance.batchExecuteCommand(commands, mockPluginContext); + }).toThrow(errorMessage); + + expect(mockExecuteTransaction).toHaveBeenCalledTimes(1); // Still called once + }); + + afterEach(() => { + jest.clearAllMocks(); + }); +}); + +describe('listCommands', () => { + let commandInstance; + let mockHandler; + + beforeEach(() => { + commandInstance = new Command(); + mockHandler = jest.fn(); + }); + + it('should list all registered commands', () => { + // 注册几个命令 + const command1 = { + name: 'testCommand1', + handler: mockHandler, + description: 'Test Command 1', + parameters: [{ name: 'param1', propType: 'string' }] + }; + const command2 = { + name: 'testCommand2', + handler: mockHandler, + description: 'Test Command 2', + parameters: [{ name: 'param2', propType: 'number' }] + }; + commandInstance.registerCommand(command1, { commandScope: 'testScope' }); + commandInstance.registerCommand(command2, { commandScope: 'testScope' }); + + const listedCommands = commandInstance.listCommands(); + + expect(listedCommands.length).toBe(2); + expect(listedCommands).toEqual(expect.arrayContaining([ + expect.objectContaining({ + name: 'testScope:testCommand1', + description: 'Test Command 1', + parameters: [{ name: 'param1', propType: 'string' }] + }), + expect.objectContaining({ + name: 'testScope:testCommand2', + description: 'Test Command 2', + parameters: [{ name: 'param2', propType: 'number' }] + }) + ])); + }); + + it('should return an empty array if no commands are registered', () => { + const listedCommands = commandInstance.listCommands(); + expect(listedCommands).toEqual([]); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); +}); + +describe('onCommandError', () => { + let commandInstance; + let mockHandler; + let mockErrorHandler1; + let mockErrorHandler2; + + beforeEach(() => { + commandInstance = new Command(); + mockHandler = jest.fn(); + mockErrorHandler1 = jest.fn(); + mockErrorHandler2 = jest.fn(); + + // 注册一个命令,该命令会抛出错误 + const command = { + name: 'testCommand', + handler: () => { + throw new Error('Command execution failed'); + }, + }; + commandInstance.registerCommand(command, { commandScope: 'testScope' }); + }); + + it('should call all registered error handlers when a command throws an error', () => { + const commandName = 'testScope:testCommand'; + commandInstance.onCommandError(mockErrorHandler1); + commandInstance.onCommandError(mockErrorHandler2); + + expect(() => { + commandInstance.executeCommand(commandName, {}); + }).not.toThrow(); + + // 确保所有错误处理函数都被调用,并且传递了正确的参数 + expect(mockErrorHandler1).toHaveBeenCalledWith(commandName, expect.any(Error)); + expect(mockErrorHandler2).toHaveBeenCalledWith(commandName, expect.any(Error)); + }); + + it('should throw the error if no error handlers are registered', () => { + const commandName = 'testScope:testCommand'; + + expect(() => { + commandInstance.executeCommand(commandName, {}); + }).toThrow('Command execution failed'); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); +}); diff --git a/packages/engine/src/engine-core.ts b/packages/engine/src/engine-core.ts index 3ccfdf51d1..778438a3d4 100644 --- a/packages/engine/src/engine-core.ts +++ b/packages/engine/src/engine-core.ts @@ -10,6 +10,7 @@ import { Setters as InnerSetters, Hotkey as InnerHotkey, IEditor, + Command as InnerCommand, } from '@alilc/lowcode-editor-core'; import { IPublicTypeEngineOptions, @@ -19,6 +20,7 @@ import { IPublicApiPlugins, IPublicApiWorkspace, IPublicEnumPluginRegisterLevel, + IPublicModelPluginContext, } from '@alilc/lowcode-types'; import { Designer, @@ -52,6 +54,7 @@ import { Workspace, Config, CommonUI, + Command, } from '@alilc/lowcode-shell'; import { isPlainObject } from '@alilc/lowcode-utils'; import './modules/live-editing'; @@ -63,6 +66,7 @@ import { defaultPanelRegistry } from './inner-plugins/default-panel-registry'; import { shellModelFactory } from './modules/shell-model-factory'; import { builtinHotkey } from './inner-plugins/builtin-hotkey'; import { defaultContextMenu } from './inner-plugins/default-context-menu'; +import { defaultCommand } from './inner-plugins/default-command'; import { OutlinePlugin } from '@alilc/lowcode-plugin-outline-pane'; export * from './modules/skeleton-types'; @@ -80,6 +84,7 @@ async function registryInnerPlugin(designer: IDesigner, editor: IEditor, plugins await plugins.register(builtinHotkey); await plugins.register(registerDefaults, {}, { autoInit: true }); await plugins.register(defaultContextMenu); + await plugins.register(defaultCommand, {}); return () => { plugins.delete(OutlinePlugin.pluginName); @@ -89,6 +94,7 @@ async function registryInnerPlugin(designer: IDesigner, editor: IEditor, plugins plugins.delete(builtinHotkey.pluginName); plugins.delete(registerDefaults.pluginName); plugins.delete(defaultContextMenu.pluginName); + plugins.delete(defaultCommand.pluginName); }; } @@ -99,6 +105,8 @@ globalContext.register(editor, Editor); globalContext.register(editor, 'editor'); globalContext.register(innerWorkspace, 'workspace'); +const engineContext: Partial<ILowCodePluginContextPrivate> = {}; + const innerSkeleton = new InnerSkeleton(editor); editor.set('skeleton' as any, innerSkeleton); @@ -113,6 +121,8 @@ const project = new Project(innerProject); const skeleton = new Skeleton(innerSkeleton, 'any', false); const innerSetters = new InnerSetters(); const setters = new Setters(innerSetters); +const innerCommand = new InnerCommand(); +const command = new Command(innerCommand, engineContext as IPublicModelPluginContext); const material = new Material(editor); const commonUI = new CommonUI(editor); @@ -136,6 +146,7 @@ const pluginContextApiAssembler: ILowCodePluginContextApiAssembler = { context.setters = setters; context.material = material; const eventPrefix = meta?.eventPrefix || 'common'; + const commandScope = meta?.commandScope; context.event = new Event(commonEvent, { prefix: eventPrefix }); context.config = config; context.common = common; @@ -144,6 +155,9 @@ const pluginContextApiAssembler: ILowCodePluginContextApiAssembler = { context.logger = new Logger({ level: 'warn', bizName: `plugin:${pluginName}` }); context.workspace = workspace; context.commonUI = commonUI; + context.command = new Command(innerCommand, context as IPublicModelPluginContext, { + commandScope, + }); context.registerLevel = IPublicEnumPluginRegisterLevel.Default; context.isPluginRegisteredInWorkspace = false; editor.set('pluginContext', context); @@ -155,6 +169,20 @@ plugins = new Plugins(innerPlugins).toProxy(); editor.set('innerPlugins' as any, innerPlugins); editor.set('plugins' as any, plugins); +engineContext.skeleton = skeleton; +engineContext.plugins = plugins; +engineContext.project = project; +engineContext.setters = setters; +engineContext.material = material; +engineContext.event = event; +engineContext.logger = logger; +engineContext.hotkey = hotkey; +engineContext.common = common; +engineContext.workspace = workspace; +engineContext.canvas = canvas; +engineContext.commonUI = commonUI; +engineContext.command = command; + export { skeleton, plugins, @@ -169,6 +197,7 @@ export { workspace, canvas, commonUI, + command, }; // declare this is open-source version export const isOpenSource = true; diff --git a/packages/engine/src/inner-plugins/default-command.ts b/packages/engine/src/inner-plugins/default-command.ts new file mode 100644 index 0000000000..b2b899acb0 --- /dev/null +++ b/packages/engine/src/inner-plugins/default-command.ts @@ -0,0 +1,524 @@ +import { + IPublicModelPluginContext, + IPublicTypeNodeSchema, + IPublicTypePropType, +} from '@alilc/lowcode-types'; +import { isNodeSchema } from '@alilc/lowcode-utils'; + +const sampleNodeSchema: IPublicTypePropType = { + type: 'shape', + value: [ + { + name: 'id', + propType: { + type: 'string', + isRequired: true, + }, + }, + { + name: 'componentName', + propType: { + type: 'string', + isRequired: true, + }, + }, + { + name: 'props', + propType: 'object', + }, + { + name: 'condition', + propType: 'any', + }, + { + name: 'loop', + propType: 'any', + }, + { + name: 'loopArgs', + propType: 'any', + }, + { + name: 'children', + propType: 'any', + }, + ], +}; + +export const nodeSchemaPropType: IPublicTypePropType = { + type: 'shape', + value: [ + sampleNodeSchema.value[0], + sampleNodeSchema.value[1], + { + name: 'props', + propType: { + type: 'objectOf', + value: { + type: 'oneOfType', + // 不会强制校验,更多作为提示 + value: [ + 'any', + { + type: 'shape', + value: [ + { + name: 'type', + propType: { + type: 'oneOf', + value: ['JSExpression'], + }, + }, + { + name: 'value', + propType: 'string', + }, + ], + }, + { + type: 'shape', + value: [ + { + name: 'type', + propType: { + type: 'oneOf', + value: ['JSFunction'], + }, + }, + { + name: 'value', + propType: 'string', + }, + ], + }, + { + type: 'shape', + value: [ + { + name: 'type', + propType: { + type: 'oneOf', + value: ['JSSlot'], + }, + }, + { + name: 'value', + propType: { + type: 'oneOfType', + value: [ + sampleNodeSchema, + { + type: 'arrayOf', + value: sampleNodeSchema, + }, + ], + }, + }, + ], + }, + ], + }, + }, + }, + { + name: 'condition', + propType: { + type: 'oneOfType', + value: [ + 'bool', + { + type: 'shape', + value: [ + { + name: 'type', + propType: { + type: 'oneOf', + value: ['JSExpression'], + }, + }, + { + name: 'value', + propType: 'string', + }, + ], + }, + ], + }, + }, + { + name: 'loop', + propType: { + type: 'oneOfType', + value: [ + 'array', + { + type: 'shape', + value: [ + { + name: 'type', + propType: { + type: 'oneOf', + value: ['JSExpression'], + }, + }, + { + name: 'value', + propType: 'string', + }, + ], + }, + ], + }, + }, + { + name: 'loopArgs', + propType: { + type: 'oneOfType', + value: [ + { + type: 'arrayOf', + value: { + type: 'oneOfType', + value: [ + 'any', + { + type: 'shape', + value: [ + { + name: 'type', + propType: { + type: 'oneOf', + value: ['JSExpression'], + }, + }, + { + name: 'value', + propType: 'string', + }, + ], + }, + ], + }, + }, + { + type: 'shape', + value: [ + { + name: 'type', + propType: { + type: 'oneOf', + value: ['JSExpression'], + }, + }, + { + name: 'value', + propType: 'string', + }, + ], + }, + ], + }, + }, + { + name: 'children', + propType: { + type: 'arrayOf', + value: sampleNodeSchema, + }, + }, + ], +}; + +export const historyCommand = (ctx: IPublicModelPluginContext) => { + const { command, project } = ctx; + return { + init() { + command.registerCommand({ + name: 'undo', + description: 'Undo the last operation.', + handler: () => { + const state = project.currentDocument?.history.getState() || 0; + const enable = !!(state & 1); + if (!enable) { + throw new Error('Can not undo.'); + } + project.currentDocument?.history.back(); + }, + }); + + command.registerCommand({ + name: 'redo', + description: 'Redo the last operation.', + handler: () => { + const state = project.currentDocument?.history.getState() || 0; + const enable = !!(state & 2); + if (!enable) { + throw new Error('Can not redo.'); + } + project.currentDocument?.history.forward(); + }, + }); + }, + }; +}; + +historyCommand.pluginName = '___history_command___'; +historyCommand.meta = { + commandScope: 'history', +}; + +export const nodeCommand = (ctx: IPublicModelPluginContext) => { + const { command, project } = ctx; + return { + init() { + command.registerCommand({ + name: 'add', + description: 'Add a node to the canvas.', + handler: (param: { + parentNodeId: string; + nodeSchema: IPublicTypeNodeSchema; + }) => { + const { + parentNodeId, + nodeSchema, + } = param; + const { project } = ctx; + const parentNode = project.currentDocument?.getNodeById(parentNodeId); + if (!parentNode) { + throw new Error(`Can not find node '${parentNodeId}'.`); + } + + if (!parentNode.isContainerNode) { + throw new Error(`Node '${parentNodeId}' is not a container node.`); + } + + if (!isNodeSchema(nodeSchema)) { + throw new Error('Invalid node.'); + } + + project.currentDocument?.insertNode(parentNode, nodeSchema); + }, + parameters: [ + { + name: 'parentNodeId', + propType: 'string', + description: 'The id of the parent node.', + }, + { + name: 'nodeSchema', + propType: nodeSchemaPropType, + description: 'The node to be added.', + }, + ], + }); + + command.registerCommand({ + name: 'move', + description: 'Move a node to another node.', + handler(param: { + nodeId: string; + targetNodeId: string; + index: number; + }) { + const { + nodeId, + targetNodeId, + index = 0, + } = param; + + const node = project.currentDocument?.getNodeById(nodeId); + const targetNode = project.currentDocument?.getNodeById(targetNodeId); + if (!node) { + throw new Error(`Can not find node '${nodeId}'.`); + } + + if (!targetNode) { + throw new Error(`Can not find node '${targetNodeId}'.`); + } + + if (!targetNode.isContainerNode) { + throw new Error(`Node '${targetNodeId}' is not a container node.`); + } + + if (index < 0 || index > (targetNode.children?.size || 0)) { + throw new Error(`Invalid index '${index}'.`); + } + + project.currentDocument?.removeNode(node); + project.currentDocument?.insertNode(targetNode, node, index); + }, + parameters: [ + { + name: 'nodeId', + propType: 'string', + description: 'The id of the node to be moved.', + }, + { + name: 'targetNodeId', + propType: 'string', + description: 'The id of the target node.', + }, + { + name: 'index', + propType: 'number', + description: 'The index of the node to be moved.', + }, + ], + }); + + command.registerCommand({ + name: 'remove', + description: 'Remove a node from the canvas.', + handler(param: { + nodeId: string; + }) { + const { + nodeId, + } = param; + + const node = project.currentDocument?.getNodeById(nodeId); + if (!node) { + throw new Error(`Can not find node '${nodeId}'.`); + } + + project.currentDocument?.removeNode(node); + }, + parameters: [ + { + name: 'nodeId', + propType: 'string', + description: 'The id of the node to be removed.', + }, + ], + }); + + command.registerCommand({ + name: 'replace', + description: 'Replace a node with another node.', + handler(param: { + nodeId: string; + nodeSchema: IPublicTypeNodeSchema; + }) { + const { + nodeId, + nodeSchema, + } = param; + + const node = project.currentDocument?.getNodeById(nodeId); + if (!node) { + throw new Error(`Can not find node '${nodeId}'.`); + } + + if (!isNodeSchema(nodeSchema)) { + throw new Error('Invalid node.'); + } + + node.importSchema(nodeSchema); + }, + parameters: [ + { + name: 'nodeId', + propType: 'string', + description: 'The id of the node to be replaced.', + }, + { + name: 'nodeSchema', + propType: nodeSchemaPropType, + description: 'The node to replace.', + }, + ], + }); + + command.registerCommand({ + name: 'updateProps', + description: 'Update the properties of a node.', + handler(param: { + nodeId: string; + props: Record<string, any>; + }) { + const { + nodeId, + props, + } = param; + + const node = project.currentDocument?.getNodeById(nodeId); + if (!node) { + throw new Error(`Can not find node '${nodeId}'.`); + } + + Object.keys(props).forEach(key => { + node.setPropValue(key, props[key]); + }); + }, + parameters: [ + { + name: 'nodeId', + propType: 'string', + description: 'The id of the node to be updated.', + }, + { + name: 'props', + propType: 'object', + description: 'The properties to be updated.', + }, + ], + }); + + command.registerCommand({ + name: 'removeProps', + description: 'Remove the properties of a node.', + handler(param: { + nodeId: string; + propNames: string[]; + }) { + const { + nodeId, + propNames, + } = param; + + const node = project.currentDocument?.getNodeById(nodeId); + if (!node) { + throw new Error(`Can not find node '${nodeId}'.`); + } + + propNames.forEach(key => { + node.props?.getProp(key)?.remove(); + }); + }, + parameters: [ + { + name: 'nodeId', + propType: 'string', + description: 'The id of the node to be updated.', + }, + { + name: 'propNames', + propType: 'array', + description: 'The properties to be removed.', + }, + ], + }); + }, + }; +}; + +nodeCommand.pluginName = '___node_command___'; +nodeCommand.meta = { + commandScope: 'node', +}; + +export const defaultCommand = (ctx: IPublicModelPluginContext) => { + const { plugins } = ctx; + plugins.register(nodeCommand); + plugins.register(historyCommand); + + return { + init() { + }, + }; +}; + +defaultCommand.pluginName = '___default_command___'; +defaultCommand.meta = { + commandScope: 'common', +}; diff --git a/packages/engine/tests/inner-plugins/default-command.test.ts b/packages/engine/tests/inner-plugins/default-command.test.ts new file mode 100644 index 0000000000..0e28c642b8 --- /dev/null +++ b/packages/engine/tests/inner-plugins/default-command.test.ts @@ -0,0 +1,110 @@ +import { checkPropTypes } from '@alilc/lowcode-utils/src/check-prop-types'; +import { nodeSchemaPropType } from '../../src/inner-plugins/default-command'; + +describe('nodeSchemaPropType', () => { + const componentName = 'NodeComponent'; + const getPropType = (name: string) => nodeSchemaPropType.value.find(d => d.name === name)?.propType; + + it('should validate the id as a string', () => { + const validId = 'node1'; + const invalidId = 123; // Not a string + expect(checkPropTypes(validId, 'id', getPropType('id'), componentName)).toBe(true); + expect(checkPropTypes(invalidId, 'id', getPropType('id'), componentName)).toBe(false); + // isRequired + expect(checkPropTypes(undefined, 'id', getPropType('id'), componentName)).toBe(false); + }); + + it('should validate the componentName as a string', () => { + const validComponentName = 'Button'; + const invalidComponentName = false; // Not a string + expect(checkPropTypes(validComponentName, 'componentName', getPropType('componentName'), componentName)).toBe(true); + expect(checkPropTypes(invalidComponentName, 'componentName', getPropType('componentName'), componentName)).toBe(false); + // isRequired + expect(checkPropTypes(undefined, 'componentName', getPropType('componentName'), componentName)).toBe(false); + }); + + it('should validate the props as an object', () => { + const validProps = { key: 'value' }; + const invalidProps = 'Not an object'; // Not an object + expect(checkPropTypes(validProps, 'props', getPropType('props'), componentName)).toBe(true); + expect(checkPropTypes(invalidProps, 'props', getPropType('props'), componentName)).toBe(false); + }); + + it('should validate the props as a JSExpression', () => { + const validProps = { type: 'JSExpression', value: 'props' }; + expect(checkPropTypes(validProps, 'props', getPropType('props'), componentName)).toBe(true); + }); + + it('should validate the props as a JSFunction', () => { + const validProps = { type: 'JSFunction', value: 'props' }; + expect(checkPropTypes(validProps, 'props', getPropType('props'), componentName)).toBe(true); + }); + + it('should validate the props as a JSSlot', () => { + const validProps = { type: 'JSSlot', value: 'props' }; + expect(checkPropTypes(validProps, 'props', getPropType('props'), componentName)).toBe(true); + }); + + it('should validate the condition as a bool', () => { + const validCondition = true; + const invalidCondition = 'Not a bool'; // Not a boolean + expect(checkPropTypes(validCondition, 'condition', getPropType('condition'), componentName)).toBe(true); + expect(checkPropTypes(invalidCondition, 'condition', getPropType('condition'), componentName)).toBe(false); + }); + + it('should validate the condition as a JSExpression', () => { + const validCondition = { type: 'JSExpression', value: '1 + 1 === 2' }; + const invalidCondition = { type: 'JSExpression', value: 123 }; // Not a string + expect(checkPropTypes(validCondition, 'condition', getPropType('condition'), componentName)).toBe(true); + expect(checkPropTypes(invalidCondition, 'condition', getPropType('condition'), componentName)).toBe(false); + }); + + it('should validate the loop as an array', () => { + const validLoop = ['item1', 'item2']; + const invalidLoop = 'Not an array'; // Not an array + expect(checkPropTypes(validLoop, 'loop', getPropType('loop'), componentName)).toBe(true); + expect(checkPropTypes(invalidLoop, 'loop', getPropType('loop'), componentName)).toBe(false); + }); + + it('should validate the loop as a JSExpression', () => { + const validLoop = { type: 'JSExpression', value: 'items' }; + const invalidLoop = { type: 'JSExpression', value: 123 }; // Not a string + expect(checkPropTypes(validLoop, 'loop', getPropType('loop'), componentName)).toBe(true); + expect(checkPropTypes(invalidLoop, 'loop', getPropType('loop'), componentName)).toBe(false); + }) + + it('should validate the loopArgs as an array', () => { + const validLoopArgs = ['item']; + const invalidLoopArgs = 'Not an array'; // Not an array + expect(checkPropTypes(validLoopArgs, 'loopArgs', getPropType('loopArgs'), componentName)).toBe(true); + expect(checkPropTypes(invalidLoopArgs, 'loopArgs', getPropType('loopArgs'), componentName)).toBe(false); + }); + + it('should validate the loopArgs as a JSExpression', () => { + const validLoopArgs = { type: 'JSExpression', value: 'item' }; + const invalidLoopArgs = { type: 'JSExpression', value: 123 }; // Not a string + const validLoopArgs2 = [{ type: 'JSExpression', value: 'item' }, { type: 'JSExpression', value: 'index' }]; + expect(checkPropTypes(validLoopArgs, 'loopArgs', getPropType('loopArgs'), componentName)).toBe(true); + expect(checkPropTypes(invalidLoopArgs, 'loopArgs', getPropType('loopArgs'), componentName)).toBe(false); + expect(checkPropTypes(validLoopArgs2, 'loopArgs', getPropType('loopArgs'), componentName)).toBe(true); + }); + + it('should validate the children as an array', () => { + const validChildren = [{ + id: 'child1', + componentName: 'Button', + }, { + id: 'child2', + componentName: 'Button', + }]; + const invalidChildren = 'Not an array'; // Not an array + const invalidChildren2 = [{}]; // Not an valid array + expect(checkPropTypes(invalidChildren, 'children', getPropType('children'), componentName)).toBe(false); + expect(checkPropTypes(validChildren, 'children', getPropType('children'), componentName)).toBe(true); + expect(checkPropTypes(invalidChildren2, 'children', getPropType('children'), componentName)).toBe(false); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); +}); diff --git a/packages/renderer-core/src/utils/common.ts b/packages/renderer-core/src/utils/common.ts index 80150f379f..0462d358a7 100644 --- a/packages/renderer-core/src/utils/common.ts +++ b/packages/renderer-core/src/utils/common.ts @@ -1,7 +1,7 @@ /* eslint-disable no-console */ /* eslint-disable no-new-func */ import logger from './logger'; -import { IPublicTypeRootSchema, IPublicTypeNodeSchema, IPublicTypeJSSlot, IPublicTypePropType, IPublicTypeRequiredType, IPublicTypeBasicType } from '@alilc/lowcode-types'; +import { IPublicTypeRootSchema, IPublicTypeNodeSchema, IPublicTypeJSSlot } from '@alilc/lowcode-types'; import { isI18nData, isJSExpression } from '@alilc/lowcode-utils'; import { isEmpty } from 'lodash'; import IntlMessageFormat from 'intl-messageformat'; diff --git a/packages/shell/src/api/command.ts b/packages/shell/src/api/command.ts new file mode 100644 index 0000000000..ebab4a9ff5 --- /dev/null +++ b/packages/shell/src/api/command.ts @@ -0,0 +1,46 @@ +import { IPublicApiCommand, IPublicModelPluginContext, IPublicTypeCommand, IPublicTypeCommandHandlerArgs, IPublicTypeListCommand } from '@alilc/lowcode-types'; +import { commandSymbol, pluginContextSymbol } from '../symbols'; +import { ICommand, ICommandOptions } from '@alilc/lowcode-editor-core'; + +const optionsSymbol = Symbol('options'); +const commandScopeSet = new Set<string>(); + +export class Command implements IPublicApiCommand { + [commandSymbol]: ICommand; + [optionsSymbol]?: ICommandOptions; + [pluginContextSymbol]?: IPublicModelPluginContext; + + constructor(innerCommand: ICommand, pluginContext?: IPublicModelPluginContext, options?: ICommandOptions) { + this[commandSymbol] = innerCommand; + this[optionsSymbol] = options; + this[pluginContextSymbol] = pluginContext; + const commandScope = options?.commandScope; + if (commandScope && commandScopeSet.has(commandScope)) { + throw new Error(`Command scope "${commandScope}" has been registered.`); + } + } + + registerCommand(command: IPublicTypeCommand): void { + this[commandSymbol].registerCommand(command, this[optionsSymbol]); + } + + batchExecuteCommand(commands: { name: string; args: IPublicTypeCommandHandlerArgs }[]): void { + this[commandSymbol].batchExecuteCommand(commands, this[pluginContextSymbol]); + } + + executeCommand(name: string, args: IPublicTypeCommandHandlerArgs): void { + this[commandSymbol].executeCommand(name, args); + } + + listCommands(): IPublicTypeListCommand[] { + return this[commandSymbol].listCommands(); + } + + unregisterCommand(name: string): void { + this[commandSymbol].unregisterCommand(name); + } + + onCommandError(callback: (name: string, error: Error) => void): void { + this[commandSymbol].onCommandError(callback); + } +} diff --git a/packages/shell/src/api/index.ts b/packages/shell/src/api/index.ts index 3726020de0..79340f6777 100644 --- a/packages/shell/src/api/index.ts +++ b/packages/shell/src/api/index.ts @@ -11,4 +11,5 @@ export * from './skeleton'; export * from './canvas'; export * from './workspace'; export * from './config'; -export * from './commonUI'; \ No newline at end of file +export * from './commonUI'; +export * from './command'; \ No newline at end of file diff --git a/packages/shell/src/index.ts b/packages/shell/src/index.ts index ce09ccaaa7..fb1e7228f3 100644 --- a/packages/shell/src/index.ts +++ b/packages/shell/src/index.ts @@ -29,6 +29,7 @@ import { SimulatorHost, Config, CommonUI, + Command, } from './api'; export * from './symbols'; @@ -70,4 +71,5 @@ export { SettingField, SkeletonItem, CommonUI, + Command, }; diff --git a/packages/shell/src/symbols.ts b/packages/shell/src/symbols.ts index 8e2962a24f..e0f846ad36 100644 --- a/packages/shell/src/symbols.ts +++ b/packages/shell/src/symbols.ts @@ -39,4 +39,5 @@ export const configSymbol = Symbol('configSymbol'); export const conditionGroupSymbol = Symbol('conditionGroup'); export const editorViewSymbol = Symbol('editorView'); export const pluginContextSymbol = Symbol('pluginContext'); -export const skeletonItemSymbol = Symbol('skeletonItem'); \ No newline at end of file +export const skeletonItemSymbol = Symbol('skeletonItem'); +export const commandSymbol = Symbol('command'); \ No newline at end of file diff --git a/packages/types/src/shell/api/command.ts b/packages/types/src/shell/api/command.ts new file mode 100644 index 0000000000..5cbfaa2e10 --- /dev/null +++ b/packages/types/src/shell/api/command.ts @@ -0,0 +1,34 @@ +import { IPublicTypeCommand, IPublicTypeCommandHandlerArgs, IPublicTypeListCommand } from '../type'; + +export interface IPublicApiCommand { + + /** + * 注册一个新命令及其处理函数 + */ + registerCommand(command: IPublicTypeCommand): void; + + /** + * 注销一个已存在的命令 + */ + unregisterCommand(name: string): void; + + /** + * 通过名称和给定参数执行一个命令,会校验参数是否符合命令定义 + */ + executeCommand(name: string, args: IPublicTypeCommandHandlerArgs): void; + + /** + * 批量执行命令,执行完所有命令后再进行一次重绘,历史记录中只会记录一次 + */ + batchExecuteCommand(commands: { name: string; args: IPublicTypeCommandHandlerArgs }[]): void; + + /** + * 列出所有已注册的命令 + */ + listCommands(): IPublicTypeListCommand[]; + + /** + * 注册错误处理回调函数 + */ + onCommandError(callback: (name: string, error: Error) => void): void; +} \ No newline at end of file diff --git a/packages/types/src/shell/api/index.ts b/packages/types/src/shell/api/index.ts index 79f1b0dc7c..8f14d8dadd 100644 --- a/packages/types/src/shell/api/index.ts +++ b/packages/types/src/shell/api/index.ts @@ -11,3 +11,4 @@ export * from './logger'; export * from './canvas'; export * from './workspace'; export * from './commonUI'; +export * from './command'; \ No newline at end of file diff --git a/packages/types/src/shell/model/plugin-context.ts b/packages/types/src/shell/model/plugin-context.ts index 45568424de..d4d715e96b 100644 --- a/packages/types/src/shell/model/plugin-context.ts +++ b/packages/types/src/shell/model/plugin-context.ts @@ -12,6 +12,7 @@ import { IPublicApiPlugins, IPublicApiWorkspace, IPublicApiCommonUI, + IPublicApiCommand, } from '../api'; import { IPublicEnumPluginRegisterLevel } from '../enum'; import { IPublicModelEngineConfig, IPublicModelWindow } from './'; @@ -109,6 +110,8 @@ export interface IPublicModelPluginContext { */ get commonUI(): IPublicApiCommonUI; + get command(): IPublicApiCommand; + /** * 插件注册层级 * @since v1.1.7 diff --git a/packages/types/src/shell/type/command.ts b/packages/types/src/shell/type/command.ts new file mode 100644 index 0000000000..dd0420def1 --- /dev/null +++ b/packages/types/src/shell/type/command.ts @@ -0,0 +1,71 @@ +// 定义命令处理函数的参数类型 +export interface IPublicTypeCommandHandlerArgs { + [key: string]: any; +} + +// 定义复杂参数类型的接口 +export interface IPublicTypeCommandPropType { + + /** + * 参数基础类型 + */ + type: string; + + /** + * 参数是否必需(可选) + */ + isRequired?: boolean; +} + +// 定义命令参数的接口 +export interface IPublicTypeCommandParameter { + + /** + * 参数名称 + */ + name: string; + + /** + * 参数类型或详细类型描述 + */ + propType: string | IPublicTypeCommandPropType; + + /** + * 参数描述 + */ + description: string; + + /** + * 参数默认值(可选) + */ + defaultValue?: any; +} + +// 定义单个命令的接口 +export interface IPublicTypeCommand { + + /** + * 命令名称 + * 命名规则:commandName + * 使用规则:commandScope:commandName (commandScope 在插件 meta 中定义,用于区分不同插件的命令) + */ + name: string; + + /** + * 命令参数 + */ + parameters?: IPublicTypeCommandParameter[]; + + /** + * 命令描述 + */ + description?: string; + + /** + * 命令处理函数 + */ + handler: (args: any) => void; +} + +export interface IPublicTypeListCommand extends Pick<IPublicTypeCommand, 'name' | 'description' | 'parameters'> { +} \ No newline at end of file diff --git a/packages/types/src/shell/type/index.ts b/packages/types/src/shell/type/index.ts index b1c7779d05..76dd389255 100644 --- a/packages/types/src/shell/type/index.ts +++ b/packages/types/src/shell/type/index.ts @@ -92,4 +92,5 @@ export * from './hotkey-callbacks'; export * from './scrollable'; export * from './simulator-renderer'; export * from './config-transducer'; -export * from './context-menu'; \ No newline at end of file +export * from './context-menu'; +export * from './command'; \ No newline at end of file diff --git a/packages/types/src/shell/type/plugin-meta.ts b/packages/types/src/shell/type/plugin-meta.ts index 421e59ad0a..bf7f6212e8 100644 --- a/packages/types/src/shell/type/plugin-meta.ts +++ b/packages/types/src/shell/type/plugin-meta.ts @@ -1,14 +1,17 @@ import { IPublicTypePluginDeclaration } from './'; export interface IPublicTypePluginMeta { + /** * define dependencies which the plugin depends on */ dependencies?: string[]; + /** * specify which engine version is compatible with the plugin */ engines?: { + /** e.g. '^1.0.0' */ lowcodeEngine?: string; }; @@ -26,4 +29,9 @@ export interface IPublicTypePluginMeta { * event.emit('someEventName') is actually sending event with name 'myEvent:someEventName' */ eventPrefix?: string; + + /** + * 如果要使用 command 注册命令,需要在插件 meta 中定义 commandScope + */ + commandScope?: string; } diff --git a/packages/workspace/src/context/base-context.ts b/packages/workspace/src/context/base-context.ts index 2f6154788f..db33597aea 100644 --- a/packages/workspace/src/context/base-context.ts +++ b/packages/workspace/src/context/base-context.ts @@ -5,6 +5,7 @@ import { commonEvent, IEngineConfig, IHotKey, + Command as InnerCommand, } from '@alilc/lowcode-editor-core'; import { Designer, @@ -33,6 +34,7 @@ import { Window, Canvas, CommonUI, + Command, } from '@alilc/lowcode-shell'; import { IPluginPreferenceMananger, @@ -129,6 +131,7 @@ export class BasicContext implements IBasicContext { const skeleton = new Skeleton(innerSkeleton, 'any', true); const canvas = new Canvas(editor, true); const commonUI = new CommonUI(editor); + const innerCommand = new InnerCommand(); editor.set('setters', setters); editor.set('project', project); editor.set('material', material); @@ -162,6 +165,7 @@ export class BasicContext implements IBasicContext { context.setters = setters; context.material = material; const eventPrefix = meta?.eventPrefix || 'common'; + const commandScope = meta?.commandScope; context.event = new Event(commonEvent, { prefix: eventPrefix }); context.config = config; context.common = common; @@ -172,6 +176,9 @@ export class BasicContext implements IBasicContext { if (editorWindow) { context.editorWindow = new Window(editorWindow); } + context.command = new Command(innerCommand, context as IPublicModelPluginContext, { + commandScope, + }); context.registerLevel = registerLevel; context.isPluginRegisteredInWorkspace = registerLevel === IPublicEnumPluginRegisterLevel.Workspace; editor.set('pluginContext', context); From b29c53901e4a1c1f437d9fe71aadaa16d02686f4 Mon Sep 17 00:00:00 2001 From: ZeralZhang <zeralzhang@gmail.com> Date: Fri, 26 Jan 2024 09:38:37 +0800 Subject: [PATCH 200/219] fix(react-simulator-renderer): detached node has children detached node has children will return false, causing memory leaks. --- packages/react-simulator-renderer/src/renderer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-simulator-renderer/src/renderer.ts b/packages/react-simulator-renderer/src/renderer.ts index efebeda040..20f6e18c0b 100644 --- a/packages/react-simulator-renderer/src/renderer.ts +++ b/packages/react-simulator-renderer/src/renderer.ts @@ -614,7 +614,7 @@ function getNodeInstance(fiberNode: any, specId?: string): IPublicTypeNodeInstan function checkInstanceMounted(instance: any): boolean { if (isElement(instance)) { - return instance.parentElement != null; + return instance.parentElement != null && window.document.contains(instance); } return true; } From b97570f10c1035991d17aba49031edd0ef710024 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 26 Jan 2024 15:20:13 +0800 Subject: [PATCH 201/219] docs(demo): add dialog use desc --- docs/docs/demoUsage/makeStuff/dialog.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/docs/demoUsage/makeStuff/dialog.md b/docs/docs/demoUsage/makeStuff/dialog.md index 56303067cb..da78cc8e8c 100644 --- a/docs/docs/demoUsage/makeStuff/dialog.md +++ b/docs/docs/demoUsage/makeStuff/dialog.md @@ -2,6 +2,8 @@ title: 3. 如何通过按钮展示/隐藏弹窗 sidebar_position: 1 --- +> 说明:这个方式依赖低代码弹窗组件是否对外保留了相关的 API,不同的物料支持的方式不一样,这里只针对综合场景的弹窗物料。 + ## 1.拖拽一个按钮 ![image.png](https://img.alicdn.com/imgextra/i1/O1CN01kLaWA31D6WwTui9VW_!!6000000000167-2-tps-3584-1812.png) From 739572172a9901c7223f7bc1617495b8e8752900 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Fri, 26 Jan 2024 08:40:59 +0000 Subject: [PATCH 202/219] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 69dddfce2c..ce6a969c1f 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.29", + "version": "1.2.30", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 6e89d4d605760d376fedf350b99f24bc11770ec5 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 26 Jan 2024 15:14:16 +0800 Subject: [PATCH 203/219] feat(setter): add field ts --- packages/editor-core/src/di/setter.ts | 6 +++--- .../src/components/settings/settings-pane.tsx | 4 ++-- packages/editor-skeleton/src/transducers/parse-props.ts | 3 ++- packages/types/src/shell/type/field-extra-props.ts | 2 +- packages/types/src/shell/type/registered-setter.ts | 7 +++++-- 5 files changed, 13 insertions(+), 9 deletions(-) diff --git a/packages/editor-core/src/di/setter.ts b/packages/editor-core/src/di/setter.ts index 437d9a89e2..5af2c0230f 100644 --- a/packages/editor-core/src/di/setter.ts +++ b/packages/editor-core/src/di/setter.ts @@ -1,5 +1,5 @@ import { ReactNode } from 'react'; -import { IPublicApiSetters, IPublicTypeCustomView, IPublicTypeRegisteredSetter } from '@alilc/lowcode-types'; +import { IPublicApiSetters, IPublicModelSettingField, IPublicTypeCustomView, IPublicTypeRegisteredSetter } from '@alilc/lowcode-types'; import { createContent, isCustomView } from '@alilc/lowcode-utils'; const settersMap = new Map<string, IPublicTypeRegisteredSetter & { @@ -28,7 +28,7 @@ export function registerSetter( if (!setter.initialValue) { const initial = getInitialFromSetter(setter.component); if (initial) { - setter.initialValue = (field: any) => { + setter.initialValue = (field: IPublicModelSettingField) => { return initial.call(field, field.getValue()); }; } @@ -81,7 +81,7 @@ export class Setters implements ISetters { if (!setter.initialValue) { const initial = getInitialFromSetter(setter.component); if (initial) { - setter.initialValue = (field: any) => { + setter.initialValue = (field: IPublicModelSettingField) => { return initial.call(field, field.getValue()); }; } diff --git a/packages/editor-skeleton/src/components/settings/settings-pane.tsx b/packages/editor-skeleton/src/components/settings/settings-pane.tsx index 1d651bb5a3..1561bf8bbe 100644 --- a/packages/editor-skeleton/src/components/settings/settings-pane.tsx +++ b/packages/editor-skeleton/src/components/settings/settings-pane.tsx @@ -225,7 +225,7 @@ class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldView const value = this.value; - let _onChange = extraProps?.onChange; + let onChangeAPI = extraProps?.onChange; let stageName = this.stageName; return createField( @@ -261,7 +261,7 @@ class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldView value, }); field.setValue(value, true); - if (_onChange) _onChange(value, field); + if (onChangeAPI) onChangeAPI(value, field.internalToShellField()); }, onInitial: () => { if (initialValue == null) { diff --git a/packages/editor-skeleton/src/transducers/parse-props.ts b/packages/editor-skeleton/src/transducers/parse-props.ts index d22f07f437..573d24ac62 100644 --- a/packages/editor-skeleton/src/transducers/parse-props.ts +++ b/packages/editor-skeleton/src/transducers/parse-props.ts @@ -9,6 +9,7 @@ import { IPublicTypeTransformedComponentMetadata, IPublicTypeOneOfType, ConfigureSupportEvent, + IPublicModelSettingField, } from '@alilc/lowcode-types'; function propConfigToFieldConfig(propConfig: IPublicTypePropConfig): IPublicTypeFieldConfig { @@ -102,7 +103,7 @@ function propTypeToSetter(propType: IPublicTypePropType): IPublicTypeSetterType }, }, isRequired, - initialValue: (field: any) => { + initialValue: (field: IPublicModelSettingField) => { const data: any = {}; items.forEach((item: any) => { let initial = item.defaultValue; diff --git a/packages/types/src/shell/type/field-extra-props.ts b/packages/types/src/shell/type/field-extra-props.ts index 3e2df280b7..7aae7e0fe8 100644 --- a/packages/types/src/shell/type/field-extra-props.ts +++ b/packages/types/src/shell/type/field-extra-props.ts @@ -77,5 +77,5 @@ export interface IPublicTypeFieldExtraProps { /** * onChange 事件 */ - onChange?: (value: any, field: any) => void; + onChange?: (value: any, field: IPublicModelSettingField) => void; } diff --git a/packages/types/src/shell/type/registered-setter.ts b/packages/types/src/shell/type/registered-setter.ts index 85cad5a803..55a90465a8 100644 --- a/packages/types/src/shell/type/registered-setter.ts +++ b/packages/types/src/shell/type/registered-setter.ts @@ -1,17 +1,20 @@ +import { IPublicModelSettingField } from '../model'; import { IPublicTypeCustomView, IPublicTypeTitleContent } from './'; export interface IPublicTypeRegisteredSetter { component: IPublicTypeCustomView; defaultProps?: object; title?: IPublicTypeTitleContent; + /** * for MixedSetter to check this setter if available */ - condition?: (field: any) => boolean; + condition?: (field: IPublicModelSettingField) => boolean; + /** * for MixedSetter to manual change to this setter */ - initialValue?: any | ((field: any) => any); + initialValue?: any | ((field: IPublicModelSettingField) => any); recommend?: boolean; // 标识是否为动态 setter,默认为 true isDynamic?: boolean; From e3a19896d78cf79736e0fabba9dd37c4c3f22997 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 26 Jan 2024 16:58:20 +0800 Subject: [PATCH 204/219] fix(prop): emit event when unset prop --- .../designer/src/document/node/props/prop.ts | 43 ++++--- .../tests/document/node/props/prop.test.ts | 106 +++++++++++++++++- 2 files changed, 132 insertions(+), 17 deletions(-) diff --git a/packages/designer/src/document/node/props/prop.ts b/packages/designer/src/document/node/props/prop.ts index e2d9f12e8e..fd9401314a 100644 --- a/packages/designer/src/document/node/props/prop.ts +++ b/packages/designer/src/document/node/props/prop.ts @@ -353,7 +353,6 @@ export class Prop implements IProp, IPropParent { @action setValue(val: IPublicTypeCompositeValue) { if (val === this._value) return; - const editor = this.owner.document?.designer.editor; const oldValue = this._value; this._value = val; this._code = null; @@ -386,22 +385,31 @@ export class Prop implements IProp, IPropParent { this.setupItems(); if (oldValue !== this._value) { - const propsInfo = { - key: this.key, - prop: this, - oldValue, - newValue: this._value, - }; - - editor?.eventBus.emit(GlobalEvent.Node.Prop.InnerChange, { - node: this.owner as any, - ...propsInfo, - }); - - this.owner?.emitPropChange?.(propsInfo); + this.emitChange({ oldValue }); } } + emitChange = ({ + oldValue, + }: { + oldValue: IPublicTypeCompositeValue | UNSET; + }) => { + const editor = this.owner.document?.designer.editor; + const propsInfo = { + key: this.key, + prop: this, + oldValue, + newValue: this.type === 'unset' ? undefined : this._value, + }; + + editor?.eventBus.emit(GlobalEvent.Node.Prop.InnerChange, { + node: this.owner as any, + ...propsInfo, + }); + + this.owner?.emitPropChange?.(propsInfo); + }; + getValue(): IPublicTypeCompositeValue { return this.export(IPublicEnumTransformStage.Serilize); } @@ -462,7 +470,12 @@ export class Prop implements IProp, IPropParent { */ @action unset() { - this._type = 'unset'; + if (this._type !== 'unset') { + this._type = 'unset'; + this.emitChange({ + oldValue: this._value, + }); + } } /** diff --git a/packages/designer/tests/document/node/props/prop.test.ts b/packages/designer/tests/document/node/props/prop.test.ts index 4424eb6010..8630376b68 100644 --- a/packages/designer/tests/document/node/props/prop.test.ts +++ b/packages/designer/tests/document/node/props/prop.test.ts @@ -3,7 +3,7 @@ import { Editor, engineConfig } from '@alilc/lowcode-editor-core'; import { Designer } from '../../../../src/designer/designer'; import { DocumentModel } from '../../../../src/document/document-model'; import { Prop, isProp, isValidArrayIndex } from '../../../../src/document/node/props/prop'; -import { IPublicEnumTransformStage } from '@alilc/lowcode-types'; +import { GlobalEvent, IPublicEnumTransformStage } from '@alilc/lowcode-types'; import { shellModelFactory } from '../../../../../engine/src/modules/shell-model-factory'; const slotNodeImportMockFn = jest.fn(); @@ -24,9 +24,16 @@ const mockOwner = { remove: slotNodeRemoveMockFn, }; }, - designer: {}, + designer: { + editor: { + eventBus: { + emit: jest.fn(), + }, + }, + }, }, isInited: true, + emitPropChange: jest.fn(), }; const mockPropsInst = { @@ -564,3 +571,98 @@ describe('其他导出函数', () => { expect(isValidArrayIndex('2', 1)).toBeFalsy(); }); }); + +describe('setValue with event', () => { + let propInstance; + let mockEmitChange; + let mockEventBusEmit; + let mockEmitPropChange; + + beforeEach(() => { + // Initialize the instance of your class + propInstance = new Prop(mockPropsInst, true, 'stringProp');; + + // Mock necessary methods and properties + mockEmitChange = jest.spyOn(propInstance, 'emitChange'); + propInstance.owner = { + document: { + designer: { + editor: { + eventBus: { + emit: jest.fn(), + }, + }, + }, + }, + emitPropChange: jest.fn(), + }; + mockEventBusEmit = jest.spyOn(propInstance.owner.document.designer.editor.eventBus, 'emit'); + mockEmitPropChange = jest.spyOn(propInstance.owner, 'emitPropChange'); + }); + + afterEach(() => { + jest.restoreAllMocks(); + }); + + it('should correctly handle string values and emit changes', () => { + const oldValue = propInstance._value; + const newValue = 'new string value'; + + propInstance.setValue(newValue); + + const expectedPartialPropsInfo = expect.objectContaining({ + key: propInstance.key, + newValue, // You can specifically test only certain keys + oldValue, + }); + + expect(propInstance.getValue()).toBe(newValue); + expect(propInstance.type).toBe('literal'); + expect(mockEmitChange).toHaveBeenCalledWith({ oldValue }); + expect(mockEventBusEmit).toHaveBeenCalledWith(GlobalEvent.Node.Prop.InnerChange, expectedPartialPropsInfo); + expect(mockEmitPropChange).toHaveBeenCalledWith(expectedPartialPropsInfo); + }); + + it('should handle object values and set type to map', () => { + const oldValue = propInstance._value; + const newValue = 234; + + const expectedPartialPropsInfo = expect.objectContaining({ + key: propInstance.key, + newValue, // You can specifically test only certain keys + oldValue, + }); + + propInstance.setValue(newValue); + + expect(propInstance.getValue()).toEqual(newValue); + expect(propInstance.type).toBe('literal'); + expect(mockEmitChange).toHaveBeenCalledWith({ oldValue }); + expect(mockEventBusEmit).toHaveBeenCalledWith(GlobalEvent.Node.Prop.InnerChange, expectedPartialPropsInfo); + expect(mockEmitPropChange).toHaveBeenCalledWith(expectedPartialPropsInfo); + }); + + it('should has event when unset call', () => { + const oldValue = propInstance._value; + + propInstance.unset(); + + const expectedPartialPropsInfo = expect.objectContaining({ + key: propInstance.key, + newValue: undefined, // You can specifically test only certain keys + oldValue, + }); + + expect(propInstance.getValue()).toEqual(undefined); + expect(propInstance.type).toBe('unset'); + expect(mockEmitChange).toHaveBeenCalledWith({ + oldValue, + newValue: undefined, + }); + expect(mockEventBusEmit).toHaveBeenCalledWith(GlobalEvent.Node.Prop.InnerChange, expectedPartialPropsInfo); + expect(mockEmitPropChange).toHaveBeenCalledWith(expectedPartialPropsInfo); + + propInstance.unset(); + expect(mockEmitChange).toHaveBeenCalledTimes(1); + }); +}); From ed7befbff01d174a0335f0a1832fd9e313e308ea Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 30 Jan 2024 10:22:43 +0800 Subject: [PATCH 205/219] feat(context-menu): prevent event bubbling when "menus" is empty --- packages/shell/src/components/context-menu.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/shell/src/components/context-menu.tsx b/packages/shell/src/components/context-menu.tsx index ccd910efc4..8c7ab446ba 100644 --- a/packages/shell/src/components/context-menu.tsx +++ b/packages/shell/src/components/context-menu.tsx @@ -34,7 +34,7 @@ export function ContextMenu({ children, menus, pluginContext }: { ); } - if (!menus || !menus.length) { + if (!menus) { return ( <>{ children }</> ); @@ -53,6 +53,9 @@ export function ContextMenu({ children, menus, pluginContext }: { } ContextMenu.create = (pluginContext: IPublicModelPluginContext, menus: IPublicTypeContextMenuAction[], event: MouseEvent) => { + event.preventDefault(); + event.stopPropagation(); + const children: React.ReactNode[] = parseContextMenuAsReactNode(parseContextMenuProperties(menus, { pluginContext, }), { From 80bb7102b65ccfc24399e372cff5f3fbaf8258a4 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 30 Jan 2024 14:19:30 +0800 Subject: [PATCH 206/219] feat(command): update default commands --- .../src/inner-plugins/default-command.ts | 44 ++++++++++++++----- packages/types/src/shell/api/command.ts | 4 +- 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/packages/engine/src/inner-plugins/default-command.ts b/packages/engine/src/inner-plugins/default-command.ts index b2b899acb0..68d65c5001 100644 --- a/packages/engine/src/inner-plugins/default-command.ts +++ b/packages/engine/src/inner-plugins/default-command.ts @@ -10,10 +10,7 @@ const sampleNodeSchema: IPublicTypePropType = { value: [ { name: 'id', - propType: { - type: 'string', - isRequired: true, - }, + propType: 'string', }, { name: 'componentName', @@ -277,10 +274,12 @@ export const nodeCommand = (ctx: IPublicModelPluginContext) => { handler: (param: { parentNodeId: string; nodeSchema: IPublicTypeNodeSchema; + index: number; }) => { const { parentNodeId, nodeSchema, + index, } = param; const { project } = ctx; const parentNode = project.currentDocument?.getNodeById(parentNodeId); @@ -296,7 +295,11 @@ export const nodeCommand = (ctx: IPublicModelPluginContext) => { throw new Error('Invalid node.'); } - project.currentDocument?.insertNode(parentNode, nodeSchema); + if (index < 0 || index > (parentNode.children?.size || 0)) { + throw new Error(`Invalid index '${index}'.`); + } + + project.currentDocument?.insertNode(parentNode, nodeSchema, index); }, parameters: [ { @@ -309,6 +312,11 @@ export const nodeCommand = (ctx: IPublicModelPluginContext) => { propType: nodeSchemaPropType, description: 'The node to be added.', }, + { + name: 'index', + propType: 'number', + description: 'The index of the node to be added.', + }, ], }); @@ -326,6 +334,14 @@ export const nodeCommand = (ctx: IPublicModelPluginContext) => { index = 0, } = param; + if (!nodeId) { + throw new Error('Invalid node id.'); + } + + if (!targetNodeId) { + throw new Error('Invalid target node id.'); + } + const node = project.currentDocument?.getNodeById(nodeId); const targetNode = project.currentDocument?.getNodeById(targetNodeId); if (!node) { @@ -350,12 +366,18 @@ export const nodeCommand = (ctx: IPublicModelPluginContext) => { parameters: [ { name: 'nodeId', - propType: 'string', + propType: { + type: 'string', + isRequired: true, + }, description: 'The id of the node to be moved.', }, { name: 'targetNodeId', - propType: 'string', + propType: { + type: 'string', + isRequired: true, + }, description: 'The id of the target node.', }, { @@ -393,8 +415,8 @@ export const nodeCommand = (ctx: IPublicModelPluginContext) => { }); command.registerCommand({ - name: 'replace', - description: 'Replace a node with another node.', + name: 'update', + description: 'Update a node.', handler(param: { nodeId: string; nodeSchema: IPublicTypeNodeSchema; @@ -419,12 +441,12 @@ export const nodeCommand = (ctx: IPublicModelPluginContext) => { { name: 'nodeId', propType: 'string', - description: 'The id of the node to be replaced.', + description: 'The id of the node to be updated.', }, { name: 'nodeSchema', propType: nodeSchemaPropType, - description: 'The node to replace.', + description: 'The node to be updated.', }, ], }); diff --git a/packages/types/src/shell/api/command.ts b/packages/types/src/shell/api/command.ts index 5cbfaa2e10..1f8425dcef 100644 --- a/packages/types/src/shell/api/command.ts +++ b/packages/types/src/shell/api/command.ts @@ -15,12 +15,12 @@ export interface IPublicApiCommand { /** * 通过名称和给定参数执行一个命令,会校验参数是否符合命令定义 */ - executeCommand(name: string, args: IPublicTypeCommandHandlerArgs): void; + executeCommand(name: string, args?: IPublicTypeCommandHandlerArgs): void; /** * 批量执行命令,执行完所有命令后再进行一次重绘,历史记录中只会记录一次 */ - batchExecuteCommand(commands: { name: string; args: IPublicTypeCommandHandlerArgs }[]): void; + batchExecuteCommand(commands: { name: string; args?: IPublicTypeCommandHandlerArgs }[]): void; /** * 列出所有已注册的命令 From 557a462b9f0e90e953862fd5fc7b528d4701a278 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 30 Jan 2024 14:34:53 +0800 Subject: [PATCH 207/219] fix(prop): emit event when delete prop --- .../designer/src/document/node/props/prop.ts | 1 + .../tests/document/node/props/prop.test.ts | 29 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/packages/designer/src/document/node/props/prop.ts b/packages/designer/src/document/node/props/prop.ts index fd9401314a..d70f0f56ec 100644 --- a/packages/designer/src/document/node/props/prop.ts +++ b/packages/designer/src/document/node/props/prop.ts @@ -570,6 +570,7 @@ export class Prop implements IProp, IPropParent { @action remove() { this.parent.delete(this); + this.unset(); } /** diff --git a/packages/designer/tests/document/node/props/prop.test.ts b/packages/designer/tests/document/node/props/prop.test.ts index 8630376b68..ff4147a34a 100644 --- a/packages/designer/tests/document/node/props/prop.test.ts +++ b/packages/designer/tests/document/node/props/prop.test.ts @@ -34,11 +34,14 @@ const mockOwner = { }, isInited: true, emitPropChange: jest.fn(), + delete() {}, }; const mockPropsInst = { owner: mockOwner, + delete() {}, }; + mockPropsInst.props = mockPropsInst; describe('Prop 类测试', () => { @@ -595,6 +598,7 @@ describe('setValue with event', () => { }, }, emitPropChange: jest.fn(), + delete() {}, }; mockEventBusEmit = jest.spyOn(propInstance.owner.document.designer.editor.eventBus, 'emit'); mockEmitPropChange = jest.spyOn(propInstance.owner, 'emitPropChange'); @@ -665,4 +669,29 @@ describe('setValue with event', () => { propInstance.unset(); expect(mockEmitChange).toHaveBeenCalledTimes(1); }); + + // remove + it('should has event when remove call', () => { + const oldValue = propInstance._value; + + propInstance.remove(); + + const expectedPartialPropsInfo = expect.objectContaining({ + key: propInstance.key, + newValue: undefined, // You can specifically test only certain keys + oldValue, + }); + + expect(propInstance.getValue()).toEqual(undefined); + // expect(propInstance.type).toBe('unset'); + expect(mockEmitChange).toHaveBeenCalledWith({ + oldValue, + newValue: undefined, + }); + expect(mockEventBusEmit).toHaveBeenCalledWith(GlobalEvent.Node.Prop.InnerChange, expectedPartialPropsInfo); + expect(mockEmitPropChange).toHaveBeenCalledWith(expectedPartialPropsInfo); + + propInstance.remove(); + expect(mockEmitChange).toHaveBeenCalledTimes(1); + }); }); From 43921cea2d21321fa9366e34e27ea15649a7f944 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Tue, 30 Jan 2024 18:31:52 +0800 Subject: [PATCH 208/219] fix(workspace): fix workspace.plugins.xxx api is invalid --- packages/shell/src/api/workspace.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/shell/src/api/workspace.ts b/packages/shell/src/api/workspace.ts index fd3e82fa90..f5bc79009f 100644 --- a/packages/shell/src/api/workspace.ts +++ b/packages/shell/src/api/workspace.ts @@ -90,7 +90,7 @@ export class Workspace implements IPublicApiWorkspace { } get plugins() { - return new Plugins(this[workspaceSymbol].plugins, true); + return new Plugins(this[workspaceSymbol].plugins, true).toProxy(); } get skeleton() { From de95b87b1e2ef1a7bd90b52e7f3cf8ca22a5f999 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 31 Jan 2024 18:53:23 +0800 Subject: [PATCH 209/219] feat: update ts defined --- packages/types/src/shell/api/workspace.ts | 5 ++++- packages/types/src/shell/type/command.ts | 18 +++--------------- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/packages/types/src/shell/api/workspace.ts b/packages/types/src/shell/api/workspace.ts index 9e1080b31e..b6e7d84cb7 100644 --- a/packages/types/src/shell/api/workspace.ts +++ b/packages/types/src/shell/api/workspace.ts @@ -1,8 +1,9 @@ import { IPublicModelWindow } from '../model'; -import { IPublicApiPlugins, IPublicModelResource, IPublicResourceList, IPublicTypeDisposable, IPublicTypeResourceType } from '@alilc/lowcode-types'; +import { IPublicApiPlugins, IPublicApiSkeleton, IPublicModelResource, IPublicResourceList, IPublicTypeDisposable, IPublicTypeResourceType } from '@alilc/lowcode-types'; export interface IPublicApiWorkspace< Plugins = IPublicApiPlugins, + Skeleton = IPublicApiSkeleton, ModelWindow = IPublicModelWindow, Resource = IPublicModelResource, > { @@ -15,6 +16,8 @@ export interface IPublicApiWorkspace< plugins: Plugins; + skeleton: Skeleton; + /** 当前设计器的编辑窗口 */ windows: ModelWindow[]; diff --git a/packages/types/src/shell/type/command.ts b/packages/types/src/shell/type/command.ts index dd0420def1..0f301bd658 100644 --- a/packages/types/src/shell/type/command.ts +++ b/packages/types/src/shell/type/command.ts @@ -1,22 +1,10 @@ +import { IPublicTypePropType } from './prop-types'; + // 定义命令处理函数的参数类型 export interface IPublicTypeCommandHandlerArgs { [key: string]: any; } -// 定义复杂参数类型的接口 -export interface IPublicTypeCommandPropType { - - /** - * 参数基础类型 - */ - type: string; - - /** - * 参数是否必需(可选) - */ - isRequired?: boolean; -} - // 定义命令参数的接口 export interface IPublicTypeCommandParameter { @@ -28,7 +16,7 @@ export interface IPublicTypeCommandParameter { /** * 参数类型或详细类型描述 */ - propType: string | IPublicTypeCommandPropType; + propType: string | IPublicTypePropType; /** * 参数描述 From 24393211b404575bd81c62007e324ed1dfdca112 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 1 Feb 2024 12:23:31 +0800 Subject: [PATCH 210/219] refactor(plugin-command): add plugin-command package --- .github/workflows/test packages.yml | 18 ++++- packages/engine/src/engine-core.ts | 2 +- packages/plugin-command/README.md | 11 +++ .../__tests__/node-command.test.ts} | 8 +-- packages/plugin-command/build.json | 9 +++ packages/plugin-command/build.test.json | 19 +++++ packages/plugin-command/package.json | 34 +++++++++ .../plugin-command/src/history-command.ts | 43 ++++++++++++ packages/plugin-command/src/index.ts | 23 +++++++ .../src/node-command.ts} | 69 +++---------------- 10 files changed, 171 insertions(+), 65 deletions(-) create mode 100644 packages/plugin-command/README.md rename packages/{engine/tests/inner-plugins/default-command.test.ts => plugin-command/__tests__/node-command.test.ts} (97%) create mode 100644 packages/plugin-command/build.json create mode 100644 packages/plugin-command/build.test.json create mode 100644 packages/plugin-command/package.json create mode 100644 packages/plugin-command/src/history-command.ts create mode 100644 packages/plugin-command/src/index.ts rename packages/{engine/src/inner-plugins/default-command.ts => plugin-command/src/node-command.ts} (88%) diff --git a/.github/workflows/test packages.yml b/.github/workflows/test packages.yml index abb2973708..573a1ade01 100644 --- a/.github/workflows/test packages.yml +++ b/.github/workflows/test packages.yml @@ -121,4 +121,20 @@ jobs: run: npm i && npm run setup:skip-build - name: test - run: cd packages/editor-core && npm test \ No newline at end of file + run: cd packages/editor-core && npm test + + test-plugin-command + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v2 + + - uses: actions/setup-node@v2 + with: + node-version: '14' + + - name: install + run: npm i && npm run setup:skip-build + + - name: test + run: cd packages/plugin-command && npm test \ No newline at end of file diff --git a/packages/engine/src/engine-core.ts b/packages/engine/src/engine-core.ts index 778438a3d4..5a2cbbc656 100644 --- a/packages/engine/src/engine-core.ts +++ b/packages/engine/src/engine-core.ts @@ -66,7 +66,7 @@ import { defaultPanelRegistry } from './inner-plugins/default-panel-registry'; import { shellModelFactory } from './modules/shell-model-factory'; import { builtinHotkey } from './inner-plugins/builtin-hotkey'; import { defaultContextMenu } from './inner-plugins/default-context-menu'; -import { defaultCommand } from './inner-plugins/default-command'; +import { defaultCommand } from '@alilc/lowcode-plugin-command'; import { OutlinePlugin } from '@alilc/lowcode-plugin-outline-pane'; export * from './modules/skeleton-types'; diff --git a/packages/plugin-command/README.md b/packages/plugin-command/README.md new file mode 100644 index 0000000000..8476b47e55 --- /dev/null +++ b/packages/plugin-command/README.md @@ -0,0 +1,11 @@ +# `@alilc/plugin-command` + +> TODO: description + +## Usage + +``` +const pluginCommand = require('@alilc/plugin-command'); + +// TODO: DEMONSTRATE API +``` diff --git a/packages/engine/tests/inner-plugins/default-command.test.ts b/packages/plugin-command/__tests__/node-command.test.ts similarity index 97% rename from packages/engine/tests/inner-plugins/default-command.test.ts rename to packages/plugin-command/__tests__/node-command.test.ts index 0e28c642b8..2e9d21b35e 100644 --- a/packages/engine/tests/inner-plugins/default-command.test.ts +++ b/packages/plugin-command/__tests__/node-command.test.ts @@ -1,5 +1,5 @@ import { checkPropTypes } from '@alilc/lowcode-utils/src/check-prop-types'; -import { nodeSchemaPropType } from '../../src/inner-plugins/default-command'; +import { nodeSchemaPropType } from '../src/node-command'; describe('nodeSchemaPropType', () => { const componentName = 'NodeComponent'; @@ -10,8 +10,8 @@ describe('nodeSchemaPropType', () => { const invalidId = 123; // Not a string expect(checkPropTypes(validId, 'id', getPropType('id'), componentName)).toBe(true); expect(checkPropTypes(invalidId, 'id', getPropType('id'), componentName)).toBe(false); - // isRequired - expect(checkPropTypes(undefined, 'id', getPropType('id'), componentName)).toBe(false); + // is not required + expect(checkPropTypes(undefined, 'id', getPropType('id'), componentName)).toBe(true); }); it('should validate the componentName as a string', () => { @@ -71,7 +71,7 @@ describe('nodeSchemaPropType', () => { const invalidLoop = { type: 'JSExpression', value: 123 }; // Not a string expect(checkPropTypes(validLoop, 'loop', getPropType('loop'), componentName)).toBe(true); expect(checkPropTypes(invalidLoop, 'loop', getPropType('loop'), componentName)).toBe(false); - }) + }); it('should validate the loopArgs as an array', () => { const validLoopArgs = ['item']; diff --git a/packages/plugin-command/build.json b/packages/plugin-command/build.json new file mode 100644 index 0000000000..d0aec10385 --- /dev/null +++ b/packages/plugin-command/build.json @@ -0,0 +1,9 @@ +{ + "plugins": [ + "@alilc/build-plugin-lce", + "build-plugin-fusion", + ["build-plugin-moment-locales", { + "locales": ["zh-cn"] + }] + ] +} diff --git a/packages/plugin-command/build.test.json b/packages/plugin-command/build.test.json new file mode 100644 index 0000000000..9596d43e79 --- /dev/null +++ b/packages/plugin-command/build.test.json @@ -0,0 +1,19 @@ +{ + "plugins": [ + [ + "@alilc/build-plugin-lce", + { + "filename": "editor-preset-vision", + "library": "LowcodeEditor", + "libraryTarget": "umd", + "externals": { + "react": "var window.React", + "react-dom": "var window.ReactDOM", + "prop-types": "var window.PropTypes", + "rax": "var window.Rax" + } + } + ], + "@alilc/lowcode-test-mate/plugin/index.ts" + ] +} diff --git a/packages/plugin-command/package.json b/packages/plugin-command/package.json new file mode 100644 index 0000000000..3c84e265ec --- /dev/null +++ b/packages/plugin-command/package.json @@ -0,0 +1,34 @@ +{ + "name": "@alilc/lowcode-plugin-command", + "version": "1.3.1", + "description": "> TODO: description", + "author": "liujuping <liujup@foxmail.com>", + "homepage": "https://github.com/alibaba/lowcode-engine#readme", + "license": "ISC", + "main": "lib/plugin-command.js", + "directories": { + "lib": "lib", + "test": "__tests__" + }, + "files": [ + "lib" + ], + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/alibaba/lowcode-engine.git" + }, + "scripts": { + "test": "build-scripts test --config build.test.json --jest-passWithNoTests", + "build": "build-scripts build" + }, + "bugs": { + "url": "https://github.com/alibaba/lowcode-engine/issues" + }, + "dependencies": { + "@alilc/lowcode-types": "^1.3.1", + "@alilc/lowcode-utils": "^1.3.1" + } +} diff --git a/packages/plugin-command/src/history-command.ts b/packages/plugin-command/src/history-command.ts new file mode 100644 index 0000000000..ea7e491bce --- /dev/null +++ b/packages/plugin-command/src/history-command.ts @@ -0,0 +1,43 @@ +import { IPublicModelPluginContext, IPublicTypePlugin } from '@alilc/lowcode-types'; + +export const historyCommand: IPublicTypePlugin = (ctx: IPublicModelPluginContext) => { + const { command, project } = ctx; + return { + init() { + command.registerCommand({ + name: 'undo', + description: 'Undo the last operation.', + handler: () => { + const state = project.currentDocument?.history.getState() || 0; + const enable = !!(state & 1); + if (!enable) { + throw new Error('Can not undo.'); + } + project.currentDocument?.history.back(); + }, + }); + + command.registerCommand({ + name: 'redo', + description: 'Redo the last operation.', + handler: () => { + const state = project.currentDocument?.history.getState() || 0; + const enable = !!(state & 2); + if (!enable) { + throw new Error('Can not redo.'); + } + project.currentDocument?.history.forward(); + }, + }); + }, + destroy() { + command.unregisterCommand('history:undo'); + command.unregisterCommand('history:redo'); + }, + }; +}; + +historyCommand.pluginName = '___history_command___'; +historyCommand.meta = { + commandScope: 'history', +}; diff --git a/packages/plugin-command/src/index.ts b/packages/plugin-command/src/index.ts new file mode 100644 index 0000000000..8e5d64ebcf --- /dev/null +++ b/packages/plugin-command/src/index.ts @@ -0,0 +1,23 @@ +import { IPublicModelPluginContext, IPublicTypePlugin } from '@alilc/lowcode-types'; +import { nodeCommand } from './node-command'; +import { historyCommand } from './history-command'; + +export const defaultCommand: IPublicTypePlugin = (ctx: IPublicModelPluginContext) => { + const { plugins } = ctx; + + return { + async init() { + await plugins.register(nodeCommand, {}, { autoInit: true }); + await plugins.register(historyCommand, {}, { autoInit: true }); + }, + destroy() { + plugins.delete(nodeCommand.pluginName); + plugins.delete(historyCommand.pluginName); + }, + }; +}; + +defaultCommand.pluginName = '___default_command___'; +defaultCommand.meta = { + commandScope: 'common', +}; diff --git a/packages/engine/src/inner-plugins/default-command.ts b/packages/plugin-command/src/node-command.ts similarity index 88% rename from packages/engine/src/inner-plugins/default-command.ts rename to packages/plugin-command/src/node-command.ts index 68d65c5001..eeda1d1688 100644 --- a/packages/engine/src/inner-plugins/default-command.ts +++ b/packages/plugin-command/src/node-command.ts @@ -1,8 +1,4 @@ -import { - IPublicModelPluginContext, - IPublicTypeNodeSchema, - IPublicTypePropType, -} from '@alilc/lowcode-types'; +import { IPublicModelPluginContext, IPublicTypeNodeSchema, IPublicTypePlugin, IPublicTypePropType } from '@alilc/lowcode-types'; import { isNodeSchema } from '@alilc/lowcode-utils'; const sampleNodeSchema: IPublicTypePropType = { @@ -226,45 +222,7 @@ export const nodeSchemaPropType: IPublicTypePropType = { ], }; -export const historyCommand = (ctx: IPublicModelPluginContext) => { - const { command, project } = ctx; - return { - init() { - command.registerCommand({ - name: 'undo', - description: 'Undo the last operation.', - handler: () => { - const state = project.currentDocument?.history.getState() || 0; - const enable = !!(state & 1); - if (!enable) { - throw new Error('Can not undo.'); - } - project.currentDocument?.history.back(); - }, - }); - - command.registerCommand({ - name: 'redo', - description: 'Redo the last operation.', - handler: () => { - const state = project.currentDocument?.history.getState() || 0; - const enable = !!(state & 2); - if (!enable) { - throw new Error('Can not redo.'); - } - project.currentDocument?.history.forward(); - }, - }); - }, - }; -}; - -historyCommand.pluginName = '___history_command___'; -historyCommand.meta = { - commandScope: 'history', -}; - -export const nodeCommand = (ctx: IPublicModelPluginContext) => { +export const nodeCommand: IPublicTypePlugin = (ctx: IPublicModelPluginContext) => { const { command, project } = ctx; return { init() { @@ -521,6 +479,14 @@ export const nodeCommand = (ctx: IPublicModelPluginContext) => { ], }); }, + destroy() { + command.unregisterCommand('node:add'); + command.unregisterCommand('node:move'); + command.unregisterCommand('node:remove'); + command.unregisterCommand('node:update'); + command.unregisterCommand('node:updateProps'); + command.unregisterCommand('node:removeProps'); + }, }; }; @@ -529,18 +495,3 @@ nodeCommand.meta = { commandScope: 'node', }; -export const defaultCommand = (ctx: IPublicModelPluginContext) => { - const { plugins } = ctx; - plugins.register(nodeCommand); - plugins.register(historyCommand); - - return { - init() { - }, - }; -}; - -defaultCommand.pluginName = '___default_command___'; -defaultCommand.meta = { - commandScope: 'common', -}; From 5b46d96df77d738249b0170bad222eedc29a1802 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 1 Feb 2024 14:41:55 +0800 Subject: [PATCH 211/219] refactor(plugin-command): add plugin-command package --- scripts/build.sh | 1 + scripts/sync.sh | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/build.sh b/scripts/build.sh index 828bb16d99..751e9094fe 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -10,6 +10,7 @@ lerna run build \ --scope @alilc/lowcode-editor-skeleton \ --scope @alilc/lowcode-designer \ --scope @alilc/lowcode-plugin-designer \ + --scope @alilc/lowcode-plugin-command \ --scope @alilc/lowcode-plugin-outline-pane \ --scope @alilc/lowcode-react-renderer \ --scope @alilc/lowcode-react-simulator-renderer \ diff --git a/scripts/sync.sh b/scripts/sync.sh index e9840eeca6..3edac03845 100755 --- a/scripts/sync.sh +++ b/scripts/sync.sh @@ -13,4 +13,5 @@ tnpm sync @alilc/lowcode-renderer-core tnpm sync @alilc/lowcode-react-renderer tnpm sync @alilc/lowcode-react-simulator-renderer tnpm sync @alilc/lowcode-engine -tnpm sync @alilc/lowcode-workspace \ No newline at end of file +tnpm sync @alilc/lowcode-workspace +tnpm sync @alilc/lowcode-plugin-command \ No newline at end of file From 5657d9c084899e91077008c491284248776ad7d8 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 1 Feb 2024 14:49:25 +0800 Subject: [PATCH 212/219] feat: update test package.yaml --- .github/workflows/test packages.yml | 2 +- packages/workspace/src/context/base-context.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test packages.yml b/.github/workflows/test packages.yml index 573a1ade01..45fa665465 100644 --- a/.github/workflows/test packages.yml +++ b/.github/workflows/test packages.yml @@ -123,7 +123,7 @@ jobs: - name: test run: cd packages/editor-core && npm test - test-plugin-command + test-plugin-command: runs-on: ubuntu-latest steps: - name: checkout diff --git a/packages/workspace/src/context/base-context.ts b/packages/workspace/src/context/base-context.ts index db33597aea..445677a618 100644 --- a/packages/workspace/src/context/base-context.ts +++ b/packages/workspace/src/context/base-context.ts @@ -96,7 +96,7 @@ export class BasicContext implements IBasicContext { designer: IDesigner; registerInnerPlugins: () => Promise<void>; innerSetters: InnerSetters; - innerSkeleton: InnerSkeleton; + innerSkeleton: ISkeleton; innerHotkey: IHotKey; innerPlugins: ILowCodePluginManager; canvas: IPublicApiCanvas; From 76b2a0504959972b38d75fb97101a0ebe2426cc9 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 1 Feb 2024 16:01:36 +0800 Subject: [PATCH 213/219] docs(command): add command api docs --- docs/docs/api/canvas.md | 2 +- docs/docs/api/command.md | 101 ++++++++++++++++++++++++++++ docs/docs/api/common.md | 2 +- docs/docs/api/commonUI.md | 2 +- docs/docs/api/config.md | 2 +- docs/docs/api/configOptions.md | 2 +- docs/docs/api/event.md | 2 +- docs/docs/api/hotkey.md | 2 +- docs/docs/api/init.md | 2 +- docs/docs/api/logger.md | 2 +- docs/docs/api/material.md | 2 +- docs/docs/api/model/_category_.json | 2 +- docs/docs/api/plugins.md | 2 +- docs/docs/api/project.md | 2 +- docs/docs/api/setters.md | 2 +- docs/docs/api/simulatorHost.md | 2 +- docs/docs/api/skeleton.md | 2 +- docs/docs/api/workspace.md | 2 +- 18 files changed, 118 insertions(+), 17 deletions(-) create mode 100644 docs/docs/api/command.md diff --git a/docs/docs/api/canvas.md b/docs/docs/api/canvas.md index 582f2354b5..865b9ac311 100644 --- a/docs/docs/api/canvas.md +++ b/docs/docs/api/canvas.md @@ -1,6 +1,6 @@ --- title: canvas - 画布 API -sidebar_position: 12 +sidebar_position: 10 --- > **@types** [IPublicApiCanvas](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/canvas.ts)<br/> diff --git a/docs/docs/api/command.md b/docs/docs/api/command.md new file mode 100644 index 0000000000..fc36c8ad89 --- /dev/null +++ b/docs/docs/api/command.md @@ -0,0 +1,101 @@ +--- +title: command - 指令 API +sidebar_position: 10 +--- + + + +## 模块概览 + +该模块使得与命令系统的交互成为可能,提供了一种全面的方式来处理、执行和管理应用程序中的命令。 + + + +## 接口 + +### IPublicApiCommand + +与命令交互的接口。它提供了注册、注销、执行和管理命令的方法。 + + + +## 方法 + +### registerCommand + +注册一个新命令及其处理函数。 + +``` +typescriptCopy code +/** + * 注册一个新的命令及其处理程序。 + * @param command {IPublicTypeCommand} - 要注册的命令。 + */ +registerCommand(command: IPublicTypeCommand): void; +``` + +### unregisterCommand + +注销一个已存在的命令。 + +``` +typescriptCopy code +/** + * 注销一个已存在的命令。 + * @param name {string} - 要注销的命令的名称。 + */ +unregisterCommand(name: string): void; +``` + +### executeCommand + +根据名称和提供的参数执行命令,确保参数符合命令的定义。 + +``` +typescriptCopy code +/** + * 根据名称和提供的参数执行命令。 + * @param name {string} - 要执行的命令的名称。 + * @param args {IPublicTypeCommandHandlerArgs} - 命令的参数。 + */ +executeCommand(name: string, args?: IPublicTypeCommandHandlerArgs): void; +``` + +### batchExecuteCommand + +批量执行命令,在所有命令执行后进行重绘,历史记录中只记录一次。 + +``` +typescriptCopy code +/** + * 批量执行命令,随后进行重绘,历史记录中只记录一次。 + * @param commands {Array} - 命令对象的数组,包含名称和可选参数。 + */ +batchExecuteCommand(commands: { name: string; args?: IPublicTypeCommandHandlerArgs }[]): void; +``` + +### listCommands + +列出所有已注册的命令。 + +``` +typescriptCopy code +/** + * 列出所有已注册的命令。 + * @returns {IPublicTypeListCommand[]} - 已注册命令的数组。 + */ +listCommands(): IPublicTypeListCommand[]; +``` + +### onCommandError + +为命令执行过程中的错误注册错误处理回调函数。 + +``` +typescriptCopy code +/** + * 为命令执行过程中的错误注册一个回调函数。 + * @param callback {(name: string, error: Error) => void} - 错误处理的回调函数。 + */ +onCommandError(callback: (name: string, error: Error) => void): void; +``` diff --git a/docs/docs/api/common.md b/docs/docs/api/common.md index 1a70436adf..c278bf2ad8 100644 --- a/docs/docs/api/common.md +++ b/docs/docs/api/common.md @@ -1,6 +1,6 @@ --- title: common - 通用 API -sidebar_position: 11 +sidebar_position: 10 --- > **@types** [IPublicApiCommon](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/common.ts)<br/> diff --git a/docs/docs/api/commonUI.md b/docs/docs/api/commonUI.md index c0bbda588e..45640051f2 100644 --- a/docs/docs/api/commonUI.md +++ b/docs/docs/api/commonUI.md @@ -1,6 +1,6 @@ --- title: commonUI - UI 组件库 -sidebar_position: 11 +sidebar_position: 10 --- ## 简介 diff --git a/docs/docs/api/config.md b/docs/docs/api/config.md index fb631a945f..414cfc979f 100644 --- a/docs/docs/api/config.md +++ b/docs/docs/api/config.md @@ -1,6 +1,6 @@ --- title: config - 配置 API -sidebar_position: 8 +sidebar_position: 5 --- > **@types** [IPublicModelEngineConfig](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/engine-config.ts)<br/> diff --git a/docs/docs/api/configOptions.md b/docs/docs/api/configOptions.md index 67d2fae2c1..5d6e8d7abb 100644 --- a/docs/docs/api/configOptions.md +++ b/docs/docs/api/configOptions.md @@ -1,6 +1,6 @@ --- title: config options - 配置列表 -sidebar_position: 13 +sidebar_position: 5 --- > **@types** [IPublicTypeEngineOptions](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/engine-options.ts)<br/> diff --git a/docs/docs/api/event.md b/docs/docs/api/event.md index 0919b41fd2..c2e86f7106 100644 --- a/docs/docs/api/event.md +++ b/docs/docs/api/event.md @@ -1,6 +1,6 @@ --- title: event - 事件 API -sidebar_position: 7 +sidebar_position: 10 --- > **@types** [IPublicApiEvent](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/event.ts)<br/> diff --git a/docs/docs/api/hotkey.md b/docs/docs/api/hotkey.md index a244b94c27..be6a3033d0 100644 --- a/docs/docs/api/hotkey.md +++ b/docs/docs/api/hotkey.md @@ -1,6 +1,6 @@ --- title: hotkey - 快捷键 API -sidebar_position: 5 +sidebar_position: 10 --- > **@types** [IPublicApiHotkey](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/hotkey.ts)<br/> diff --git a/docs/docs/api/init.md b/docs/docs/api/init.md index 55b116a579..dd84d9c00f 100644 --- a/docs/docs/api/init.md +++ b/docs/docs/api/init.md @@ -1,6 +1,6 @@ --- title: init - 初始化 API -sidebar_position: 10 +sidebar_position: 0 --- > **@since** v1.0.0 diff --git a/docs/docs/api/logger.md b/docs/docs/api/logger.md index 7493f34dc2..38d986258b 100644 --- a/docs/docs/api/logger.md +++ b/docs/docs/api/logger.md @@ -1,6 +1,6 @@ --- title: logger - 日志 API -sidebar_position: 9 +sidebar_position: 10 --- > **@types** [IPublicApiLogger](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/logger.ts)<br/> diff --git a/docs/docs/api/material.md b/docs/docs/api/material.md index b6ef070b2c..0e09441275 100644 --- a/docs/docs/api/material.md +++ b/docs/docs/api/material.md @@ -1,6 +1,6 @@ --- title: material - 物料 API -sidebar_position: 2 +sidebar_position: 10 --- > **@types** [IPublicApiMaterial](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/material.ts)<br/> diff --git a/docs/docs/api/model/_category_.json b/docs/docs/api/model/_category_.json index 5b1f74b36f..3afc4f79b5 100644 --- a/docs/docs/api/model/_category_.json +++ b/docs/docs/api/model/_category_.json @@ -1,6 +1,6 @@ { "label": "模型定义 Models", - "position": 14, + "position": 100, "collapsed": false, "collapsible": true } diff --git a/docs/docs/api/plugins.md b/docs/docs/api/plugins.md index e35411d3a8..df025f49e9 100644 --- a/docs/docs/api/plugins.md +++ b/docs/docs/api/plugins.md @@ -1,6 +1,6 @@ --- title: plugins - 插件 API -sidebar_position: 4 +sidebar_position: 2 --- > **@types** [IPublicApiPlugins](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/plugins.ts)<br/> > **@since** v1.0.0 diff --git a/docs/docs/api/project.md b/docs/docs/api/project.md index 49d3193858..54bd1474cf 100644 --- a/docs/docs/api/project.md +++ b/docs/docs/api/project.md @@ -1,6 +1,6 @@ --- title: project - 模型 API -sidebar_position: 3 +sidebar_position: 10 --- ## 模块简介 diff --git a/docs/docs/api/setters.md b/docs/docs/api/setters.md index cc7b6d429c..0d3435b3d3 100644 --- a/docs/docs/api/setters.md +++ b/docs/docs/api/setters.md @@ -1,6 +1,6 @@ --- title: setters - 设置器 API -sidebar_position: 6 +sidebar_position: 10 --- > **@types** [IPublicApiSetters](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/setters.ts)<br/> > **@since** v1.0.0 diff --git a/docs/docs/api/simulatorHost.md b/docs/docs/api/simulatorHost.md index c7f739f6b4..70eaca0220 100644 --- a/docs/docs/api/simulatorHost.md +++ b/docs/docs/api/simulatorHost.md @@ -1,6 +1,6 @@ --- title: simulatorHost - 模拟器 API -sidebar_position: 3 +sidebar_position: 10 --- > **@types** [IPublicApiSimulatorHost](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/simulator-host.ts)<br/> > **@since** v1.0.0 diff --git a/docs/docs/api/skeleton.md b/docs/docs/api/skeleton.md index 0713546e19..396fad9e9e 100644 --- a/docs/docs/api/skeleton.md +++ b/docs/docs/api/skeleton.md @@ -1,6 +1,6 @@ --- title: skeleton - 面板 API -sidebar_position: 1 +sidebar_position: 10 --- > **@types** [IPublicApiSkeleton](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/skeleton.ts)<br/> > **@since** v1.0.0 diff --git a/docs/docs/api/workspace.md b/docs/docs/api/workspace.md index 6d0714ae09..74f7d6950f 100644 --- a/docs/docs/api/workspace.md +++ b/docs/docs/api/workspace.md @@ -1,6 +1,6 @@ --- title: workspace - 应用级 API -sidebar_position: 12 +sidebar_position: 10 --- > **[@experimental](./#experimental)**<br/> From 501ad872c476faacf2bba8c25963b189e1a7cac3 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Thu, 1 Feb 2024 08:17:01 +0000 Subject: [PATCH 214/219] chore(docs): publish documentation --- docs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index ce6a969c1f..7facd9db8b 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine-docs", - "version": "1.2.30", + "version": "1.2.31", "description": "低代码引擎版本化文档", "license": "MIT", "files": [ From 19eb91725952d34fc90ba470fc639ad1fe60b102 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Thu, 1 Feb 2024 15:47:26 +0800 Subject: [PATCH 215/219] refactor(plugin-command): add plugin-command package --- packages/engine/package.json | 1 + packages/engine/src/engine-core.ts | 6 +++--- packages/plugin-command/jest.config.js | 22 ++++++++++++++++++++++ packages/plugin-command/package.json | 9 +++++++-- packages/plugin-command/src/index.ts | 8 +++++--- 5 files changed, 38 insertions(+), 8 deletions(-) create mode 100644 packages/plugin-command/jest.config.js diff --git a/packages/engine/package.json b/packages/engine/package.json index 4b622eaa4b..fb2b42fd09 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -28,6 +28,7 @@ "@alilc/lowcode-shell": "1.3.1", "@alilc/lowcode-utils": "1.3.1", "@alilc/lowcode-workspace": "1.3.1", + "@alilc/lowcode-plugin-command": "1.3.1", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/engine/src/engine-core.ts b/packages/engine/src/engine-core.ts index 5a2cbbc656..4dffa628bd 100644 --- a/packages/engine/src/engine-core.ts +++ b/packages/engine/src/engine-core.ts @@ -66,7 +66,7 @@ import { defaultPanelRegistry } from './inner-plugins/default-panel-registry'; import { shellModelFactory } from './modules/shell-model-factory'; import { builtinHotkey } from './inner-plugins/builtin-hotkey'; import { defaultContextMenu } from './inner-plugins/default-context-menu'; -import { defaultCommand } from '@alilc/lowcode-plugin-command'; +import { CommandPlugin } from '@alilc/lowcode-plugin-command'; import { OutlinePlugin } from '@alilc/lowcode-plugin-outline-pane'; export * from './modules/skeleton-types'; @@ -84,7 +84,7 @@ async function registryInnerPlugin(designer: IDesigner, editor: IEditor, plugins await plugins.register(builtinHotkey); await plugins.register(registerDefaults, {}, { autoInit: true }); await plugins.register(defaultContextMenu); - await plugins.register(defaultCommand, {}); + await plugins.register(CommandPlugin, {}); return () => { plugins.delete(OutlinePlugin.pluginName); @@ -94,7 +94,7 @@ async function registryInnerPlugin(designer: IDesigner, editor: IEditor, plugins plugins.delete(builtinHotkey.pluginName); plugins.delete(registerDefaults.pluginName); plugins.delete(defaultContextMenu.pluginName); - plugins.delete(defaultCommand.pluginName); + plugins.delete(CommandPlugin.pluginName); }; } diff --git a/packages/plugin-command/jest.config.js b/packages/plugin-command/jest.config.js new file mode 100644 index 0000000000..822a526b7d --- /dev/null +++ b/packages/plugin-command/jest.config.js @@ -0,0 +1,22 @@ +const fs = require('fs'); +const { join } = require('path'); +const esModules = [].join('|'); +const pkgNames = fs.readdirSync(join('..')).filter(pkgName => !pkgName.startsWith('.')); + +const jestConfig = { + transformIgnorePatterns: [ + `/node_modules/(?!${esModules})/`, + ], + moduleFileExtensions: ['ts', 'tsx', 'js', 'json'], + collectCoverage: true, + collectCoverageFrom: [ + 'src/**/*.ts', + 'src/**/*.tsx', + ], +}; + +// 只对本仓库内的 pkg 做 mapping +jestConfig.moduleNameMapper = {}; +jestConfig.moduleNameMapper[`^@alilc/lowcode\\-(${pkgNames.join('|')})$`] = '<rootDir>/../$1/src'; + +module.exports = jestConfig; \ No newline at end of file diff --git a/packages/plugin-command/package.json b/packages/plugin-command/package.json index 3c84e265ec..5cdd99660f 100644 --- a/packages/plugin-command/package.json +++ b/packages/plugin-command/package.json @@ -5,13 +5,15 @@ "author": "liujuping <liujup@foxmail.com>", "homepage": "https://github.com/alibaba/lowcode-engine#readme", "license": "ISC", - "main": "lib/plugin-command.js", + "main": "lib/index.js", + "module": "es/index.js", "directories": { "lib": "lib", "test": "__tests__" }, "files": [ - "lib" + "lib", + "es" ], "publishConfig": { "access": "public" @@ -30,5 +32,8 @@ "dependencies": { "@alilc/lowcode-types": "^1.3.1", "@alilc/lowcode-utils": "^1.3.1" + }, + "devDependencies": { + "@alib/build-scripts": "^0.1.18" } } diff --git a/packages/plugin-command/src/index.ts b/packages/plugin-command/src/index.ts index 8e5d64ebcf..fa6f32b32d 100644 --- a/packages/plugin-command/src/index.ts +++ b/packages/plugin-command/src/index.ts @@ -2,7 +2,7 @@ import { IPublicModelPluginContext, IPublicTypePlugin } from '@alilc/lowcode-typ import { nodeCommand } from './node-command'; import { historyCommand } from './history-command'; -export const defaultCommand: IPublicTypePlugin = (ctx: IPublicModelPluginContext) => { +export const CommandPlugin: IPublicTypePlugin = (ctx: IPublicModelPluginContext) => { const { plugins } = ctx; return { @@ -17,7 +17,9 @@ export const defaultCommand: IPublicTypePlugin = (ctx: IPublicModelPluginContext }; }; -defaultCommand.pluginName = '___default_command___'; -defaultCommand.meta = { +CommandPlugin.pluginName = '___default_command___'; +CommandPlugin.meta = { commandScope: 'common', }; + +export default CommandPlugin; \ No newline at end of file From 86d50e094628602347e09864850d23b49153bb89 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Fri, 2 Feb 2024 17:45:25 +0800 Subject: [PATCH 216/219] fix(setter): params is not shell SettingField --- packages/designer/src/designer/setting/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/designer/src/designer/setting/utils.ts b/packages/designer/src/designer/setting/utils.ts index 1e061f20ae..75ed1dfc1a 100644 --- a/packages/designer/src/designer/setting/utils.ts +++ b/packages/designer/src/designer/setting/utils.ts @@ -70,7 +70,7 @@ export class Transducer { } if (isDynamicSetter(setter) && isDynamic) { try { - setter = setter.call(context, context); + setter = setter.call(context.internalToShellField(), context.internalToShellField()); } catch (e) { console.error(e); } } From 44beb2a25ad57cbc4cc2c88c577c5467542a9fd4 Mon Sep 17 00:00:00 2001 From: liujuping <liujup@foxmail.com> Date: Wed, 7 Feb 2024 12:52:56 +0800 Subject: [PATCH 217/219] fix(workspace): fix workspace editorView is undefined --- packages/shell/src/api/material.ts | 8 +++++++- packages/shell/src/model/window.ts | 4 ++-- packages/workspace/src/window.ts | 25 ++++++++++++++++--------- 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/packages/shell/src/api/material.ts b/packages/shell/src/api/material.ts index f0c37d8a4d..284b88fbbf 100644 --- a/packages/shell/src/api/material.ts +++ b/packages/shell/src/api/material.ts @@ -3,7 +3,7 @@ import { IDesigner, isComponentMeta, } from '@alilc/lowcode-designer'; -import { IPublicTypeAssetsJson } from '@alilc/lowcode-utils'; +import { IPublicTypeAssetsJson, getLogger } from '@alilc/lowcode-utils'; import { IPublicTypeComponentAction, IPublicTypeComponentMetadata, @@ -21,6 +21,8 @@ import { editorSymbol, designerSymbol } from '../symbols'; import { ComponentMeta as ShellComponentMeta } from '../model'; import { ComponentType } from 'react'; +const logger = getLogger({ level: 'warn', bizName: 'shell-material' }); + const innerEditorSymbol = Symbol('editor'); export class Material implements IPublicApiMaterial { private readonly [innerEditorSymbol]: IPublicModelEditor; @@ -31,6 +33,10 @@ export class Material implements IPublicApiMaterial { } const workspace: InnerWorkspace = globalContext.get('workspace'); if (workspace.isActive) { + if (!workspace.window.editor) { + logger.error('Material api 调用时机出现问题,请检查'); + return this[innerEditorSymbol]; + } return workspace.window.editor; } diff --git a/packages/shell/src/model/window.ts b/packages/shell/src/model/window.ts index 2b5e0dd8c3..1bc84e661c 100644 --- a/packages/shell/src/model/window.ts +++ b/packages/shell/src/model/window.ts @@ -48,8 +48,8 @@ export class Window implements IPublicModelWindow { } get currentEditorView() { - if (this[windowSymbol].editorView) { - return new EditorView(this[windowSymbol].editorView).toProxy() as any; + if (this[windowSymbol]._editorView) { + return new EditorView(this[windowSymbol]._editorView).toProxy() as any; } return null; } diff --git a/packages/workspace/src/window.ts b/packages/workspace/src/window.ts index ce5aab4142..cd64a9b112 100644 --- a/packages/workspace/src/window.ts +++ b/packages/workspace/src/window.ts @@ -17,7 +17,7 @@ export interface IEditorWindow extends Omit<IPublicModelWindow<IResource>, 'chan editorViews: Map<string, IViewContext>; - editorView: IViewContext; + _editorView: IViewContext; changeViewName: (name: string, ignoreEmit?: boolean) => void; @@ -54,7 +54,7 @@ export class EditorWindow implements IEditorWindow { url: string | undefined; - @obx.ref editorView: Context; + @obx.ref _editorView: Context; @obx editorViews: Map<string, Context> = new Map<string, Context>(); @@ -62,6 +62,13 @@ export class EditorWindow implements IEditorWindow { sleep: boolean | undefined; + get editorView() { + if (!this._editorView) { + return this.editorViews.values().next().value; + } + return this._editorView; + } + constructor(readonly resource: IResource, readonly workspace: IWorkspace, private config: IWindowCOnfig) { makeObservable(this); this.title = config.title; @@ -75,10 +82,10 @@ export class EditorWindow implements IEditorWindow { updateState(state: WINDOW_STATE): void { switch (state) { case WINDOW_STATE.active: - this.editorView?.setActivate(true); + this._editorView?.setActivate(true); break; case WINDOW_STATE.inactive: - this.editorView?.setActivate(false); + this._editorView?.setActivate(false); break; case WINDOW_STATE.destroyed: break; @@ -146,7 +153,7 @@ export class EditorWindow implements IEditorWindow { for (let i = 0; i < editorViews.length; i++) { const name = editorViews[i].viewName; await this.initViewType(name); - if (!this.editorView) { + if (!this._editorView) { this.changeViewName(name); } } @@ -190,14 +197,14 @@ export class EditorWindow implements IEditorWindow { }; changeViewName = (name: string, ignoreEmit: boolean = true) => { - this.editorView?.setActivate(false); - this.editorView = this.editorViews.get(name)!; + this._editorView?.setActivate(false); + this._editorView = this.editorViews.get(name)!; - if (!this.editorView) { + if (!this._editorView) { return; } - this.editorView.setActivate(true); + this._editorView.setActivate(true); if (!ignoreEmit) { this.emitter.emit('window.change.view.type', name); From bd85ca3ca6adc89a5ed67644f1f14322e512db72 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Fri, 23 Feb 2024 01:51:23 +0000 Subject: [PATCH 218/219] chore(release): publish 1.3.2 --- lerna.json | 2 +- packages/designer/package.json | 8 ++++---- packages/editor-core/package.json | 6 +++--- packages/editor-skeleton/package.json | 10 +++++----- packages/engine/package.json | 20 +++++++++---------- packages/ignitor/package.json | 2 +- packages/plugin-command/package.json | 6 +++--- packages/plugin-designer/package.json | 8 ++++---- packages/plugin-outline-pane/package.json | 6 +++--- packages/react-renderer/package.json | 4 ++-- .../react-simulator-renderer/package.json | 10 +++++----- packages/renderer-core/package.json | 8 ++++---- packages/shell/package.json | 14 ++++++------- packages/types/package.json | 2 +- packages/utils/package.json | 4 ++-- packages/workspace/package.json | 12 +++++------ 16 files changed, 61 insertions(+), 61 deletions(-) diff --git a/lerna.json b/lerna.json index 7de339c6cd..7fad993f66 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "lerna": "4.0.0", - "version": "1.3.1", + "version": "1.3.2", "npmClient": "yarn", "useWorkspaces": true, "packages": [ diff --git a/packages/designer/package.json b/packages/designer/package.json index ec7c153c80..97256d3a21 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-designer", - "version": "1.3.1", + "version": "1.3.2", "description": "Designer for Ali LowCode Engine", "main": "lib/index.js", "module": "es/index.js", @@ -15,9 +15,9 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-editor-core": "1.3.1", - "@alilc/lowcode-types": "1.3.1", - "@alilc/lowcode-utils": "1.3.1", + "@alilc/lowcode-editor-core": "1.3.2", + "@alilc/lowcode-types": "1.3.2", + "@alilc/lowcode-utils": "1.3.2", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/editor-core/package.json b/packages/editor-core/package.json index 98644ad3d6..55f6d50c39 100644 --- a/packages/editor-core/package.json +++ b/packages/editor-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-core", - "version": "1.3.1", + "version": "1.3.2", "description": "Core Api for Ali lowCode engine", "license": "MIT", "main": "lib/index.js", @@ -16,8 +16,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.3.1", - "@alilc/lowcode-utils": "1.3.1", + "@alilc/lowcode-types": "1.3.2", + "@alilc/lowcode-utils": "1.3.2", "classnames": "^2.2.6", "debug": "^4.1.1", "intl-messageformat": "^9.3.1", diff --git a/packages/editor-skeleton/package.json b/packages/editor-skeleton/package.json index 7c14943552..63aab7e48b 100644 --- a/packages/editor-skeleton/package.json +++ b/packages/editor-skeleton/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-editor-skeleton", - "version": "1.3.1", + "version": "1.3.2", "description": "alibaba lowcode editor skeleton", "main": "lib/index.js", "module": "es/index.js", @@ -19,10 +19,10 @@ ], "dependencies": { "@alifd/next": "^1.20.12", - "@alilc/lowcode-designer": "1.3.1", - "@alilc/lowcode-editor-core": "1.3.1", - "@alilc/lowcode-types": "1.3.1", - "@alilc/lowcode-utils": "1.3.1", + "@alilc/lowcode-designer": "1.3.2", + "@alilc/lowcode-editor-core": "1.3.2", + "@alilc/lowcode-types": "1.3.2", + "@alilc/lowcode-utils": "1.3.2", "classnames": "^2.2.6", "react": "^16.8.1", "react-dom": "^16.8.1" diff --git a/packages/engine/package.json b/packages/engine/package.json index fb2b42fd09..23b3521213 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-engine", - "version": "1.3.1", + "version": "1.3.2", "description": "An enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系", "main": "lib/engine-core.js", "module": "es/engine-core.js", @@ -19,16 +19,16 @@ "license": "MIT", "dependencies": { "@alifd/next": "^1.19.12", - "@alilc/lowcode-designer": "1.3.1", - "@alilc/lowcode-editor-core": "1.3.1", - "@alilc/lowcode-editor-skeleton": "1.3.1", + "@alilc/lowcode-designer": "1.3.2", + "@alilc/lowcode-editor-core": "1.3.2", + "@alilc/lowcode-editor-skeleton": "1.3.2", "@alilc/lowcode-engine-ext": "^1.0.0", - "@alilc/lowcode-plugin-designer": "1.3.1", - "@alilc/lowcode-plugin-outline-pane": "1.3.1", - "@alilc/lowcode-shell": "1.3.1", - "@alilc/lowcode-utils": "1.3.1", - "@alilc/lowcode-workspace": "1.3.1", - "@alilc/lowcode-plugin-command": "1.3.1", + "@alilc/lowcode-plugin-command": "1.3.2", + "@alilc/lowcode-plugin-designer": "1.3.2", + "@alilc/lowcode-plugin-outline-pane": "1.3.2", + "@alilc/lowcode-shell": "1.3.2", + "@alilc/lowcode-utils": "1.3.2", + "@alilc/lowcode-workspace": "1.3.2", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/ignitor/package.json b/packages/ignitor/package.json index a32e30783f..0b109a7ad7 100644 --- a/packages/ignitor/package.json +++ b/packages/ignitor/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-ignitor", - "version": "1.3.1", + "version": "1.3.2", "description": "点火器,bootstrap lce project", "main": "lib/index.js", "private": true, diff --git a/packages/plugin-command/package.json b/packages/plugin-command/package.json index 5cdd99660f..4f53e69e36 100644 --- a/packages/plugin-command/package.json +++ b/packages/plugin-command/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-command", - "version": "1.3.1", + "version": "1.3.2", "description": "> TODO: description", "author": "liujuping <liujup@foxmail.com>", "homepage": "https://github.com/alibaba/lowcode-engine#readme", @@ -30,8 +30,8 @@ "url": "https://github.com/alibaba/lowcode-engine/issues" }, "dependencies": { - "@alilc/lowcode-types": "^1.3.1", - "@alilc/lowcode-utils": "^1.3.1" + "@alilc/lowcode-types": "1.3.2", + "@alilc/lowcode-utils": "1.3.2" }, "devDependencies": { "@alib/build-scripts": "^0.1.18" diff --git a/packages/plugin-designer/package.json b/packages/plugin-designer/package.json index 9fb9a75655..ac25097c78 100644 --- a/packages/plugin-designer/package.json +++ b/packages/plugin-designer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-designer", - "version": "1.3.1", + "version": "1.3.2", "description": "alibaba lowcode editor designer plugin", "files": [ "es", @@ -18,9 +18,9 @@ ], "author": "xiayang.xy", "dependencies": { - "@alilc/lowcode-designer": "1.3.1", - "@alilc/lowcode-editor-core": "1.3.1", - "@alilc/lowcode-utils": "1.3.1", + "@alilc/lowcode-designer": "1.3.2", + "@alilc/lowcode-editor-core": "1.3.2", + "@alilc/lowcode-utils": "1.3.2", "react": "^16.8.1", "react-dom": "^16.8.1" }, diff --git a/packages/plugin-outline-pane/package.json b/packages/plugin-outline-pane/package.json index 1539ac6ae3..f50f71cbfe 100644 --- a/packages/plugin-outline-pane/package.json +++ b/packages/plugin-outline-pane/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-plugin-outline-pane", - "version": "1.3.1", + "version": "1.3.2", "description": "Outline pane for Ali lowCode engine", "files": [ "es", @@ -13,8 +13,8 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.3.1", - "@alilc/lowcode-utils": "1.3.1", + "@alilc/lowcode-types": "1.3.2", + "@alilc/lowcode-utils": "1.3.2", "classnames": "^2.2.6", "react": "^16", "react-dom": "^16.7.0", diff --git a/packages/react-renderer/package.json b/packages/react-renderer/package.json index b041823e85..625801bc25 100644 --- a/packages/react-renderer/package.json +++ b/packages/react-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-renderer", - "version": "1.3.1", + "version": "1.3.2", "description": "react renderer for ali lowcode engine", "main": "lib/index.js", "module": "es/index.js", @@ -22,7 +22,7 @@ ], "dependencies": { "@alifd/next": "^1.21.16", - "@alilc/lowcode-renderer-core": "1.3.1" + "@alilc/lowcode-renderer-core": "1.3.2" }, "devDependencies": { "@alib/build-scripts": "^0.1.18", diff --git a/packages/react-simulator-renderer/package.json b/packages/react-simulator-renderer/package.json index 1361535099..3c3950a124 100644 --- a/packages/react-simulator-renderer/package.json +++ b/packages/react-simulator-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-react-simulator-renderer", - "version": "1.3.1", + "version": "1.3.2", "description": "react simulator renderer for alibaba lowcode designer", "main": "lib/index.js", "module": "es/index.js", @@ -17,10 +17,10 @@ "test:cov": "build-scripts test --config build.test.json --jest-coverage" }, "dependencies": { - "@alilc/lowcode-designer": "1.3.1", - "@alilc/lowcode-react-renderer": "1.3.1", - "@alilc/lowcode-types": "1.3.1", - "@alilc/lowcode-utils": "1.3.1", + "@alilc/lowcode-designer": "1.3.2", + "@alilc/lowcode-react-renderer": "1.3.2", + "@alilc/lowcode-types": "1.3.2", + "@alilc/lowcode-utils": "1.3.2", "classnames": "^2.2.6", "mobx": "^6.3.0", "mobx-react": "^7.2.0", diff --git a/packages/renderer-core/package.json b/packages/renderer-core/package.json index dd48d361f1..199eac1cac 100644 --- a/packages/renderer-core/package.json +++ b/packages/renderer-core/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-renderer-core", - "version": "1.3.1", + "version": "1.3.2", "description": "renderer core", "license": "MIT", "main": "lib/index.js", @@ -16,8 +16,8 @@ }, "dependencies": { "@alilc/lowcode-datasource-engine": "^1.0.0", - "@alilc/lowcode-types": "1.3.1", - "@alilc/lowcode-utils": "1.3.1", + "@alilc/lowcode-types": "1.3.2", + "@alilc/lowcode-utils": "1.3.2", "classnames": "^2.2.6", "debug": "^4.1.1", "fetch-jsonp": "^1.1.3", @@ -32,7 +32,7 @@ "devDependencies": { "@alib/build-scripts": "^0.1.18", "@alifd/next": "^1.26.0", - "@alilc/lowcode-designer": "1.3.1", + "@alilc/lowcode-designer": "1.3.2", "@babel/plugin-transform-typescript": "^7.16.8", "@testing-library/react": "^11.2.2", "@types/classnames": "^2.2.11", diff --git a/packages/shell/package.json b/packages/shell/package.json index 87f71a5ee6..c2b62e2270 100644 --- a/packages/shell/package.json +++ b/packages/shell/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-shell", - "version": "1.3.1", + "version": "1.3.2", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -13,12 +13,12 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.3.1", - "@alilc/lowcode-editor-core": "1.3.1", - "@alilc/lowcode-editor-skeleton": "1.3.1", - "@alilc/lowcode-types": "1.3.1", - "@alilc/lowcode-utils": "1.3.1", - "@alilc/lowcode-workspace": "1.3.1", + "@alilc/lowcode-designer": "1.3.2", + "@alilc/lowcode-editor-core": "1.3.2", + "@alilc/lowcode-editor-skeleton": "1.3.2", + "@alilc/lowcode-types": "1.3.2", + "@alilc/lowcode-utils": "1.3.2", + "@alilc/lowcode-workspace": "1.3.2", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", diff --git a/packages/types/package.json b/packages/types/package.json index 31dadb5ea0..5651d427d4 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-types", - "version": "1.3.1", + "version": "1.3.2", "description": "Types for Ali lowCode engine", "files": [ "es", diff --git a/packages/utils/package.json b/packages/utils/package.json index cc363a7292..60605d81e7 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-utils", - "version": "1.3.1", + "version": "1.3.2", "description": "Utils for Ali lowCode engine", "files": [ "lib", @@ -14,7 +14,7 @@ }, "dependencies": { "@alifd/next": "^1.19.16", - "@alilc/lowcode-types": "1.3.1", + "@alilc/lowcode-types": "1.3.2", "lodash": "^4.17.21", "mobx": "^6.3.0", "prop-types": "^15.8.1", diff --git a/packages/workspace/package.json b/packages/workspace/package.json index 7af4a7159c..778b8167f8 100644 --- a/packages/workspace/package.json +++ b/packages/workspace/package.json @@ -1,6 +1,6 @@ { "name": "@alilc/lowcode-workspace", - "version": "1.3.1", + "version": "1.3.2", "description": "Shell Layer for AliLowCodeEngine", "main": "lib/index.js", "module": "es/index.js", @@ -15,11 +15,11 @@ }, "license": "MIT", "dependencies": { - "@alilc/lowcode-designer": "1.3.1", - "@alilc/lowcode-editor-core": "1.3.1", - "@alilc/lowcode-editor-skeleton": "1.3.1", - "@alilc/lowcode-types": "1.3.1", - "@alilc/lowcode-utils": "1.3.1", + "@alilc/lowcode-designer": "1.3.2", + "@alilc/lowcode-editor-core": "1.3.2", + "@alilc/lowcode-editor-skeleton": "1.3.2", + "@alilc/lowcode-types": "1.3.2", + "@alilc/lowcode-utils": "1.3.2", "classnames": "^2.2.6", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", From 2892a01d298b73d483f34ec20fcf8334f1f8ea72 Mon Sep 17 00:00:00 2001 From: 1ncounter <1ncounter.100@gmail.com> Date: Tue, 11 Jun 2024 21:07:42 +0800 Subject: [PATCH 219/219] chore: update code owners --- .github/CODEOWNERS | 2 +- .github/workflows/publish engine.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 1000fca053..670db7dfbd 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -2,7 +2,7 @@ # These owners will be the default owners for everything in # the repo. Unless a later match takes precedence -* @liujuping @JackLian +* @liujuping @1ncounter /modules/material-parser @akirakai /modules/code-generator @qingniaotonghua diff --git a/.github/workflows/publish engine.yml b/.github/workflows/publish engine.yml index dcbf0547e7..ddbefcde55 100644 --- a/.github/workflows/publish engine.yml +++ b/.github/workflows/publish engine.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest if: >- contains(github.ref, 'refs/heads/release/') && - (github.actor == 'JackLian' || github.actor == 'liujuping') + (github.actor == '1ncounter' || github.actor == 'liujuping') steps: - uses: actions/checkout@v2 - name: Setup Node.js