diff --git a/packages/editor/package.json b/packages/editor/package.json index 07d9bf12..09a4b4f0 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -84,6 +84,7 @@ "rimraf": "^3.0.2", "sass": "^1.35.1", "tsc-alias": "^1.8.5", + "type-fest": "^4.10.3", "typescript": "^5.0.4", "vite": "^5.0.7", "vue-tsc": "^1.8.25" diff --git a/packages/editor/src/services/BaseService.ts b/packages/editor/src/services/BaseService.ts index 517e3dfc..9cd18ca7 100644 --- a/packages/editor/src/services/BaseService.ts +++ b/packages/editor/src/services/BaseService.ts @@ -194,6 +194,9 @@ export default class extends EventEmitter { }); } + /** + * @deprecated 请使用usePlugin代替 + */ public use(options: Record) { Object.entries(options).forEach(([methodName, method]: [string, Function]) => { if (typeof method === 'function') this.middleware[methodName].push(method); diff --git a/packages/editor/src/services/codeBlock.ts b/packages/editor/src/services/codeBlock.ts index dc152658..76aeb7af 100644 --- a/packages/editor/src/services/codeBlock.ts +++ b/packages/editor/src/services/codeBlock.ts @@ -18,16 +18,24 @@ import { reactive } from 'vue'; import { keys, pick } from 'lodash-es'; +import type { Writable } from 'type-fest'; import type { ColumnConfig } from '@tmagic/form'; import type { CodeBlockContent, CodeBlockDSL, Id } from '@tmagic/schema'; -import type { CodeState } from '@editor/type'; +import type { AsyncHookPlugin, CodeState } from '@editor/type'; import { CODE_DRAFT_STORAGE_KEY } from '@editor/type'; import { getConfig } from '@editor/utils/config'; import BaseService from './BaseService'; +const canUsePluginMethods = { + async: ['setCodeDslById', 'setEditStatus', 'setCombineIds', 'setUndeleteableList', 'deleteCodeDslByIds'] as const, + sync: [], +}; + +type AsyncMethodName = Writable<(typeof canUsePluginMethods)['async']>; + class CodeBlock extends BaseService { private state = reactive({ codeDsl: null, @@ -38,13 +46,7 @@ class CodeBlock extends BaseService { }); constructor() { - super([ - { name: 'setCodeDslById', isAsync: true }, - { name: 'setEditStatus', isAsync: true }, - { name: 'setCombineIds', isAsync: true }, - { name: 'setUndeleteableList', isAsync: true }, - { name: 'deleteCodeDslByIds', isAsync: true }, - ]); + super(canUsePluginMethods.async.map((methodName) => ({ name: methodName, isAsync: true }))); } /** @@ -243,6 +245,10 @@ class CodeBlock extends BaseService { this.removeAllListeners(); this.removeAllPlugins(); } + + public usePlugin(options: AsyncHookPlugin): void { + super.usePlugin(options); + } } export type CodeBlockService = CodeBlock; diff --git a/packages/editor/src/services/dataSource.ts b/packages/editor/src/services/dataSource.ts index 045bc63b..c7b7720f 100644 --- a/packages/editor/src/services/dataSource.ts +++ b/packages/editor/src/services/dataSource.ts @@ -1,12 +1,13 @@ import { reactive } from 'vue'; import { cloneDeep } from 'lodash-es'; +import { Writable } from 'type-fest'; import type { EventOption } from '@tmagic/core'; import type { FormConfig } from '@tmagic/form'; import type { DataSourceSchema } from '@tmagic/schema'; import { guid } from '@tmagic/utils'; -import type { DatasourceTypeOption } from '@editor/type'; +import type { DatasourceTypeOption, SyncHookPlugin } from '@editor/type'; import { getFormConfig, getFormValue } from '@editor/utils/data-source'; import BaseService from './BaseService'; @@ -22,6 +23,27 @@ interface State { } type StateKey = keyof State; + +const canUsePluginMethods = { + async: [], + sync: [ + 'getFormConfig', + 'setFormConfig', + 'getFormValue', + 'setFormValue', + 'getFormEvent', + 'setFormEvent', + 'getFormMethod', + 'setFormMethod', + 'add', + 'update', + 'remove', + 'createId', + ] as const, +}; + +type SyncMethodName = Writable<(typeof canUsePluginMethods)['sync']>; + class DataSource extends BaseService { private state = reactive({ datasourceTypeList: [], @@ -34,20 +56,7 @@ class DataSource extends BaseService { }); constructor() { - super([ - { name: 'getFormConfig', isAsync: false }, - { name: 'setFormConfig', isAsync: false }, - { name: 'getFormValue', isAsync: false }, - { name: 'setFormValue', isAsync: false }, - { name: 'getFormEvent', isAsync: false }, - { name: 'setFormEvent', isAsync: false }, - { name: 'getFormMethod', isAsync: false }, - { name: 'setFormMethod', isAsync: false }, - { name: 'add', isAsync: false }, - { name: 'update', isAsync: false }, - { name: 'remove', isAsync: false }, - { name: 'createId', isAsync: false }, - ]); + super(canUsePluginMethods.sync.map((methodName) => ({ name: methodName, isAsync: false }))); } public set(name: K, value: T) { @@ -123,6 +132,10 @@ class DataSource extends BaseService { this.emit('remove', id); } + public createId(): string { + return `ds_${guid()}`; + } + public getDataSourceById(id: string) { return this.get('dataSources').find((ds) => ds.id === id); } @@ -137,8 +150,8 @@ class DataSource extends BaseService { this.removeAllPlugins(); } - private createId(): string { - return `ds_${guid()}`; + public usePlugin(options: SyncHookPlugin): void { + super.usePlugin(options); } } diff --git a/packages/editor/src/services/editor.ts b/packages/editor/src/services/editor.ts index 349b59c5..a8d21e60 100644 --- a/packages/editor/src/services/editor.ts +++ b/packages/editor/src/services/editor.ts @@ -18,6 +18,7 @@ import { reactive, toRaw } from 'vue'; import { cloneDeep, get, isObject, mergeWith, uniq } from 'lodash-es'; +import { Writable } from 'type-fest'; import { DepTargetType } from '@tmagic/dep'; import type { Id, MApp, MComponent, MContainer, MNode, MPage, MPageFragment } from '@tmagic/schema'; @@ -29,7 +30,15 @@ import propsService from '@editor/services//props'; import depService from '@editor/services/dep'; import historyService from '@editor/services/history'; import storageService, { Protocol } from '@editor/services/storage'; -import type { AddMNode, EditorNodeInfo, PastePosition, StepValue, StoreState, StoreStateKey } from '@editor/type'; +import type { + AddMNode, + AsyncHookPlugin, + EditorNodeInfo, + PastePosition, + StepValue, + StoreState, + StoreStateKey, +} from '@editor/type'; import { LayerOffset, Layout } from '@editor/type'; import { change2Fixed, @@ -46,6 +55,36 @@ import { } from '@editor/utils/editor'; import { beforePaste, getAddParent } from '@editor/utils/operator'; +const canUsePluginMethods = { + async: [ + 'getLayout', + 'highlight', + 'select', + 'multiSelect', + 'doAdd', + 'add', + 'doRemove', + 'remove', + 'doUpdate', + 'update', + 'sort', + 'copy', + 'paste', + 'doPaste', + 'doAlignCenter', + 'alignCenter', + 'moveLayer', + 'moveToContainer', + 'dragTo', + 'undo', + 'redo', + 'move', + ] as const, + sync: [], +}; + +type AsyncMethodName = Writable<(typeof canUsePluginMethods)['async']>; + class Editor extends BaseService { public state: StoreState = reactive({ root: null, @@ -65,29 +104,7 @@ class Editor extends BaseService { constructor() { super( - [ - { name: 'getLayout', isAsync: true }, - { name: 'select', isAsync: true }, - { name: 'doAdd', isAsync: true }, - { name: 'add', isAsync: true }, - { name: 'doRemove', isAsync: true }, - { name: 'remove', isAsync: true }, - { name: 'doUpdate', isAsync: true }, - { name: 'update', isAsync: true }, - { name: 'sort', isAsync: true }, - { name: 'copy', isAsync: true }, - { name: 'paste', isAsync: true }, - { name: 'doPaste', isAsync: true }, - { name: 'doAlignCenter', isAsync: true }, - { name: 'alignCenter', isAsync: true }, - { name: 'moveLayer', isAsync: true }, - { name: 'moveToContainer', isAsync: true }, - { name: 'move', isAsync: true }, - { name: 'undo', isAsync: true }, - { name: 'redo', isAsync: true }, - { name: 'highlight', isAsync: true }, - { name: 'dragTo', isAsync: true }, - ], + canUsePluginMethods.async.map((methodName) => ({ name: methodName, isAsync: true })), // 需要注意循环依赖问题,如果函数间有相互调用的话,不能设置为串行调用 ['select', 'update', 'moveLayer'], ); @@ -696,7 +713,7 @@ class Editor extends BaseService { public async doPaste(config: MNode[], position: PastePosition = {}): Promise { propsService.clearRelateId(); - const pasteConfigs = await beforePaste(position, cloneDeep(config)); + const pasteConfigs = beforePaste(position, cloneDeep(config)); return pasteConfigs; } @@ -985,6 +1002,10 @@ class Editor extends BaseService { this.get('modifiedNodeIds').clear(); } + public usePlugin(options: AsyncHookPlugin): void { + super.usePlugin(options); + } + private addModifiedNodeId(id: Id) { if (!this.isHistoryStateChange) { this.get('modifiedNodeIds').set(id, id); diff --git a/packages/editor/src/services/props.ts b/packages/editor/src/services/props.ts index 342ecb08..26646450 100644 --- a/packages/editor/src/services/props.ts +++ b/packages/editor/src/services/props.ts @@ -18,6 +18,7 @@ import { reactive } from 'vue'; import { cloneDeep, mergeWith } from 'lodash-es'; +import { Writable } from 'type-fest'; import { DepTargetType } from '@tmagic/dep'; import type { FormConfig } from '@tmagic/form'; @@ -26,11 +27,26 @@ import { getValueByKeyPath, guid, setValueByKeyPath, toLine } from '@tmagic/util import depService from '@editor/services/dep'; import editorService from '@editor/services/editor'; -import type { PropsState } from '@editor/type'; +import type { AsyncHookPlugin, PropsState, SyncHookPlugin } from '@editor/type'; import { fillConfig } from '@editor/utils/props'; import BaseService from './BaseService'; +const canUsePluginMethods = { + async: [ + 'setPropsConfig', + 'getPropsConfig', + 'setPropsValue', + 'getPropsValue', + 'fillConfig', + 'getDefaultPropsValue', + ] as const, + sync: ['createId', 'setNewItemId'] as const, +}; + +type AsyncMethodName = Writable<(typeof canUsePluginMethods)['async']>; +type SyncMethodName = Writable<(typeof canUsePluginMethods)['sync']>; + class Props extends BaseService { private state = reactive({ propsConfigMap: {}, @@ -40,14 +56,8 @@ class Props extends BaseService { constructor() { super([ - { name: 'setPropsConfig', isAsync: true }, - { name: 'getPropsConfig', isAsync: true }, - { name: 'setPropsValue', isAsync: true }, - { name: 'getPropsValue', isAsync: true }, - { name: 'createId', isAsync: false }, - { name: 'setNewItemId', isAsync: true }, - { name: 'fillConfig', isAsync: true }, - { name: 'getDefaultPropsValue', isAsync: true }, + ...canUsePluginMethods.async.map((methodName) => ({ name: methodName, isAsync: true })), + ...canUsePluginMethods.sync.map((methodName) => ({ name: methodName, isAsync: false })), ]); } @@ -62,11 +72,6 @@ class Props extends BaseService { return fillConfig(config, typeof labelWidth !== 'function' ? labelWidth : '80px'); } - /** - * 为指定类型组件设置组件属性表单配置 - * @param type 组件类型 - * @param config 组件属性表单配置 - */ public async setPropsConfig(type: string, config: FormConfig) { this.state.propsConfigMap[type] = await this.fillConfig(Array.isArray(config) ? config : [config]); } @@ -115,16 +120,14 @@ class Props extends BaseService { return value; } - const [id, defaultPropsValue, data] = await Promise.all([ - this.createId(type), - this.getDefaultPropsValue(type), - this.setNewItemId( - cloneDeep({ - type, - ...defaultValue, - } as any), - ), - ]); + const id = this.createId(type); + const defaultPropsValue = this.getDefaultPropsValue(type); + const data = this.setNewItemId( + cloneDeep({ + type, + ...defaultValue, + } as any), + ); return { id, @@ -133,7 +136,7 @@ class Props extends BaseService { }; } - public async createId(type: string | number): Promise { + public createId(type: string | number): string { return `${type}_${guid()}`; } @@ -144,16 +147,16 @@ class Props extends BaseService { * @param {Boolean} force 是否强制设置新的ID */ /* eslint no-param-reassign: ["error", { "props": false }] */ - public async setNewItemId(config: MNode, force = true) { + public setNewItemId(config: MNode, force = true) { if (force || editorService.getNodeById(config.id)) { - const newId = await this.createId(config.type || 'component'); + const newId = this.createId(config.type || 'component'); this.setRelateId(config.id, newId); config.id = newId; } if (config.items && Array.isArray(config.items)) { for (const item of config.items) { - await this.setNewItemId(item); + this.setNewItemId(item); } } @@ -165,7 +168,7 @@ class Props extends BaseService { * @param type 组件类型 * @returns Object */ - public async getDefaultPropsValue(type: string) { + public getDefaultPropsValue(type: string) { return ['page', 'container'].includes(type) ? { type, @@ -227,6 +230,10 @@ class Props extends BaseService { this.removeAllPlugins(); } + public usePlugin(options: AsyncHookPlugin & SyncHookPlugin): void { + super.usePlugin(options); + } + /** * 获取setNewItemId前后映射关系 * @param oldId 原组件ID diff --git a/packages/editor/src/services/stageOverlay.ts b/packages/editor/src/services/stageOverlay.ts index 1fcae06b..bc5c63ff 100644 --- a/packages/editor/src/services/stageOverlay.ts +++ b/packages/editor/src/services/stageOverlay.ts @@ -1,11 +1,19 @@ import { reactive } from 'vue'; +import type { Writable } from 'type-fest'; import StageCore from '@tmagic/stage'; import { useStage } from '@editor/hooks/use-stage'; import BaseService from '@editor/services//BaseService'; import editorService from '@editor/services//editor'; -import type { StageOptions, StageOverlayState } from '@editor/type'; +import type { StageOptions, StageOverlayState, SyncHookPlugin } from '@editor/type'; + +const canUsePluginMethods = { + async: [], + sync: ['openOverlay', 'closeOverlay', 'updateOverlay', 'createStage'] as const, +}; + +type SyncMethodName = Writable<(typeof canUsePluginMethods)['sync']>; class StageOverlay extends BaseService { private state: StageOverlayState = reactive({ @@ -20,12 +28,7 @@ class StageOverlay extends BaseService { }); constructor() { - super([ - { name: 'openOverlay', isAsync: false }, - { name: 'closeOverlay', isAsync: false }, - { name: 'updateOverlay', isAsync: false }, - { name: 'createStage', isAsync: false }, - ]); + super(canUsePluginMethods.sync.map((methodName) => ({ name: methodName, isAsync: false }))); this.get('wrapDiv').classList.add('tmagic-editor-sub-stage-wrap'); } @@ -111,6 +114,10 @@ class StageOverlay extends BaseService { }); } + public usePlugin(options: SyncHookPlugin): void { + super.usePlugin(options); + } + private createContentEl() { const sourceEl = this.get('sourceEl'); if (!sourceEl) return; diff --git a/packages/editor/src/services/storage.ts b/packages/editor/src/services/storage.ts index be04e3bb..18d1a164 100644 --- a/packages/editor/src/services/storage.ts +++ b/packages/editor/src/services/storage.ts @@ -1,5 +1,7 @@ import serialize from 'serialize-javascript'; +import type { Writable } from 'type-fest'; +import type { SyncHookPlugin } from '@editor/type'; import { getConfig } from '@editor/utils/config'; import BaseService from './BaseService'; @@ -17,6 +19,13 @@ export enum Protocol { BOOLEAN = 'boolean', } +const canUsePluginMethods = { + async: [], + sync: ['getStorage', 'getNamespace', 'clear', 'getItem', 'removeItem', 'setItem'] as const, +}; + +type SyncMethodName = Writable<(typeof canUsePluginMethods)['sync']>; + /** * 数据存储服务 */ @@ -25,14 +34,7 @@ export class WebStorage extends BaseService { private namespace = 'tmagic'; constructor() { - super([ - { name: 'getStorage', isAsync: false }, - { name: 'getNamespace', isAsync: false }, - { name: 'clear', isAsync: false }, - { name: 'getItem', isAsync: false }, - { name: 'removeItem', isAsync: false }, - { name: 'setItem', isAsync: false }, - ]); + super(canUsePluginMethods.sync.map((methodName) => ({ name: methodName, isAsync: false }))); } /** @@ -123,6 +125,10 @@ export class WebStorage extends BaseService { this.removeAllPlugins(); } + public usePlugin(options: SyncHookPlugin): void { + super.usePlugin(options); + } + private getValueAndProtocol(value: string | null) { let protocol = ''; diff --git a/packages/editor/src/services/ui.ts b/packages/editor/src/services/ui.ts index e6b53ba7..772ca1f0 100644 --- a/packages/editor/src/services/ui.ts +++ b/packages/editor/src/services/ui.ts @@ -17,11 +17,12 @@ */ import { reactive } from 'vue'; +import type { Writable } from 'type-fest'; import { convertToNumber } from '@tmagic/utils'; import editorService from '@editor/services/editor'; -import type { StageRect, UiState } from '@editor/type'; +import type { AsyncHookPlugin, StageRect, UiState } from '@editor/type'; import BaseService from './BaseService'; @@ -50,12 +51,16 @@ const state = reactive({ hideSlideBar: false, }); +const canUsePluginMethods = { + async: ['zoom', 'calcZoom'] as const, + sync: [] as const, +}; + +type AsyncMethodName = Writable<(typeof canUsePluginMethods)['async']>; + class Ui extends BaseService { constructor() { - super([ - { name: 'zoom', isAsync: true }, - { name: 'calcZoom', isAsync: true }, - ]); + super(canUsePluginMethods.async.map((methodName) => ({ name: methodName, isAsync: true }))); } public set(name: K, value: T) { @@ -134,6 +139,10 @@ class Ui extends BaseService { this.removeAllPlugins(); } + public usePlugin(options: AsyncHookPlugin): void { + super.usePlugin(options); + } + private async setStageRect(value: StageRect) { state.stageRect = { ...state.stageRect, diff --git a/packages/editor/src/type.ts b/packages/editor/src/type.ts index 64173559..21e9525e 100644 --- a/packages/editor/src/type.ts +++ b/packages/editor/src/type.ts @@ -17,6 +17,7 @@ */ import type { Component } from 'vue'; +import type { PascalCasedProperties } from 'type-fest'; import type { ColumnConfig, FilterFunction, FormConfig, FormItem } from '@tmagic/form'; import type { CodeBlockContent, CodeBlockDSL, Id, MApp, MContainer, MNode, MPage, MPageFragment } from '@tmagic/schema'; @@ -670,3 +671,35 @@ export interface TreeNodeData { items?: TreeNodeData[]; [key: string]: any; } + +export type AsyncBeforeHook, C extends Record any>> = { + [K in Value[number]]?: (...args: Parameters) => Promise>; +}; + +export type AsyncAfterHook, C extends Record any>> = { + [K in Value[number]]?: (result: Awaited>, ...args: Parameters) => ReturnType; +}; + +export type SyncBeforeHook, C extends Record any>> = { + [K in Value[number]]?: (...args: Parameters) => Parameters; +}; + +export type SyncAfterHook, C extends Record any>> = { + [K in Value[number]]?: (result: ReturnType, ...args: Parameters) => ReturnType; +}; + +export type AddPrefixToObject = { + [K in keyof T as K extends string ? `${P}${K}` : never]: T[K]; +}; + +export type AsyncHookPlugin< + T extends Array, + C extends Record any>, +> = AddPrefixToObject>, 'before'> & + AddPrefixToObject>, 'after'>; + +export type SyncHookPlugin< + T extends Array, + C extends Record any>, +> = AddPrefixToObject>, 'before'> & + AddPrefixToObject>, 'after'>; diff --git a/packages/editor/src/utils/operator.ts b/packages/editor/src/utils/operator.ts index 64d8778c..2b7bb296 100644 --- a/packages/editor/src/utils/operator.ts +++ b/packages/editor/src/utils/operator.ts @@ -15,55 +15,53 @@ import { generatePageNameByApp, getInitPositionStyle } from '@editor/utils/edito * @param config 待粘贴的元素配置(复制时保存的那份配置) * @returns */ -export const beforePaste = async (position: PastePosition, config: MNode[]): Promise => { +export const beforePaste = (position: PastePosition, config: MNode[]): MNode[] => { if (!config[0]?.style) return config; const curNode = editorService.get('node'); // 将数组中第一个元素的坐标作为参照点 const { left: referenceLeft, top: referenceTop } = config[0].style; // 坐标校准后的粘贴数据 - const pasteConfigs: MNode[] = await Promise.all( - config.map(async (configItem: MNode): Promise => { - // 解构 position 对象,从 position 删除 offsetX、offsetY字段 - const { offsetX = 0, offsetY = 0, ...positionClone } = position; - let pastePosition = positionClone; + const pasteConfigs: MNode[] = config.map((configItem: MNode): MNode => { + // 解构 position 对象,从 position 删除 offsetX、offsetY字段 + const { offsetX = 0, offsetY = 0, ...positionClone } = position; + let pastePosition = positionClone; - if (!isEmpty(pastePosition) && curNode?.items) { - // 如果没有传入粘贴坐标则可能为键盘操作,不再转换 - // 如果粘贴时选中了容器,则将元素粘贴到容器内,坐标需要转换为相对于容器的坐标 - pastePosition = getPositionInContainer(pastePosition, curNode.id); + if (!isEmpty(pastePosition) && curNode?.items) { + // 如果没有传入粘贴坐标则可能为键盘操作,不再转换 + // 如果粘贴时选中了容器,则将元素粘贴到容器内,坐标需要转换为相对于容器的坐标 + pastePosition = getPositionInContainer(pastePosition, curNode.id); + } + + // 将所有待粘贴元素坐标相对于多选第一个元素坐标重新计算,以保证多选粘贴后元素间距不变 + if (pastePosition.left && configItem.style?.left) { + pastePosition.left = configItem.style.left - referenceLeft + pastePosition.left; + } + if (pastePosition.top && configItem.style?.top) { + pastePosition.top = configItem.style?.top - referenceTop + pastePosition.top; + } + const pasteConfig = propsService.setNewItemId(configItem, false); + + if (pasteConfig.style) { + const { left, top } = pasteConfig.style; + // 判断能转换为数字时,做粘贴偏移量计算 + if (typeof left === 'number' || (!!left && !isNaN(Number(left)))) { + pasteConfig.style.left = Number(left) + offsetX; + } + if (typeof top === 'number' || (!!top && !isNaN(Number(top)))) { + pasteConfig.style.top = Number(top) + offsetY; } - // 将所有待粘贴元素坐标相对于多选第一个元素坐标重新计算,以保证多选粘贴后元素间距不变 - if (pastePosition.left && configItem.style?.left) { - pastePosition.left = configItem.style.left - referenceLeft + pastePosition.left; - } - if (pastePosition.top && configItem.style?.top) { - pastePosition.top = configItem.style?.top - referenceTop + pastePosition.top; - } - const pasteConfig = await propsService.setNewItemId(configItem, false); - - if (pasteConfig.style) { - const { left, top } = pasteConfig.style; - // 判断能转换为数字时,做粘贴偏移量计算 - if (typeof left === 'number' || (!!left && !isNaN(Number(left)))) { - pasteConfig.style.left = Number(left) + offsetX; - } - if (typeof top === 'number' || (!!top && !isNaN(Number(top)))) { - pasteConfig.style.top = Number(top) + offsetY; - } - - pasteConfig.style = { - ...pasteConfig.style, - ...pastePosition, - }; - } - const root = editorService.get('root'); - if ((isPage(pasteConfig) || isPageFragment(pasteConfig)) && root) { - pasteConfig.name = generatePageNameByApp(root, isPage(pasteConfig) ? NodeType.PAGE : NodeType.PAGE_FRAGMENT); - } - return pasteConfig as MNode; - }), - ); + pasteConfig.style = { + ...pasteConfig.style, + ...pastePosition, + }; + } + const root = editorService.get('root'); + if ((isPage(pasteConfig) || isPageFragment(pasteConfig)) && root) { + pasteConfig.name = generatePageNameByApp(root, isPage(pasteConfig) ? NodeType.PAGE : NodeType.PAGE_FRAGMENT); + } + return pasteConfig as MNode; + }); return pasteConfigs; }; diff --git a/packages/editor/src/utils/props.ts b/packages/editor/src/utils/props.ts index 3a8abf2a..e8fe2a43 100644 --- a/packages/editor/src/utils/props.ts +++ b/packages/editor/src/utils/props.ts @@ -328,7 +328,7 @@ export const displayTabConfig: TabPaneConfig = { * @param config 组件属性配置 * @returns Object */ -export const fillConfig = (config: FormConfig = [], labelWidth = '80px') => [ +export const fillConfig = (config: FormConfig = [], labelWidth = '80px'): FormConfig => [ { type: 'tab', labelWidth, diff --git a/packages/editor/tests/unit/services/props.spec.ts b/packages/editor/tests/unit/services/props.spec.ts index 9cdc93a8..43d9da32 100644 --- a/packages/editor/tests/unit/services/props.spec.ts +++ b/packages/editor/tests/unit/services/props.spec.ts @@ -11,17 +11,17 @@ test('createId', async () => { }); describe('setNewItemId', () => { - test('普通', async () => { + test('普通', () => { const config = { id: 1, type: 'text', }; // 将组件与组件的子元素配置中的id都设置成一个新的ID - await props.setNewItemId(config); + props.setNewItemId(config); expect(config.id === 1).toBeFalsy(); }); - test('items', async () => { + test('items', () => { const config = { id: 1, type: NodeType.PAGE, @@ -32,7 +32,7 @@ describe('setNewItemId', () => { }, ], }; - await props.setNewItemId(config); + props.setNewItemId(config); expect(config.id === 1).toBeFalsy(); expect(config.items[0].id === 2).toBeFalsy(); }); diff --git a/playground/src/pages/Editor.vue b/playground/src/pages/Editor.vue index b864b1a0..3e06bf62 100644 --- a/playground/src/pages/Editor.vue +++ b/playground/src/pages/Editor.vue @@ -227,7 +227,7 @@ asyncLoadJs(`${VITE_ENTRY_PATH}/ds-value/index.umd.cjs`).then(() => { save(); editorService.usePlugin({ - beforeDoAdd: (config: MNode, parent?: MContainer | null) => { + beforeDoAdd: async (config: MNode, parent: MContainer) => { if (config.type === 'overlay') { config.style = { ...config.style, @@ -235,7 +235,7 @@ editorService.usePlugin({ top: 0, }; - return [config, editorService.get('page')]; + return [config, editorService.get('page') as MContainer]; } return [config, parent]; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4c76a554..c6e16b40 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -377,6 +377,9 @@ importers: tsc-alias: specifier: ^1.8.5 version: 1.8.5 + type-fest: + specifier: ^4.10.3 + version: 4.11.1 typescript: specifier: ^5.0.4 version: 5.0.4 @@ -9552,7 +9555,7 @@ packages: dependencies: find-up: 6.3.0 read-pkg: 8.1.0 - type-fest: 4.6.0 + type-fest: 4.11.1 dev: true /read-pkg-up@7.0.1: @@ -9581,7 +9584,7 @@ packages: '@types/normalize-package-data': 2.4.1 normalize-package-data: 6.0.0 parse-json: 7.1.1 - type-fest: 4.6.0 + type-fest: 4.11.1 dev: true /readable-stream@3.6.2: @@ -10491,8 +10494,8 @@ packages: engines: {node: '>=14.16'} dev: true - /type-fest@4.6.0: - resolution: {integrity: sha512-rLjWJzQFOq4xw7MgJrCZ6T1jIOvvYElXT12r+y0CC6u67hegDHaxcPqb2fZHOGlqxugGQPNB1EnTezjBetkwkw==} + /type-fest@4.11.1: + resolution: {integrity: sha512-MFMf6VkEVZAETidGGSYW2B1MjXbGX+sWIywn2QPEaJ3j08V+MwVRHMXtf2noB8ENJaD0LIun9wh5Z6OPNf1QzQ==} engines: {node: '>=16'} dev: true diff --git a/runtime/tmagic-form/src/index.ts b/runtime/tmagic-form/src/index.ts index 1c5bf636..0d9a6856 100644 --- a/runtime/tmagic-form/src/index.ts +++ b/runtime/tmagic-form/src/index.ts @@ -21,7 +21,7 @@ export const useRuntime = ({ fillConfig = (config) => config, }: { plugins?: Plugin[]; - fillConfig?: (config: FormConfig) => FormConfig; + fillConfig?: (config: FormConfig, mForm: any) => FormConfig; } = {}) => { const render = (stage: StageCore) => { injectStyle(stage.renderer.getDocument()!, cssStyle); @@ -60,24 +60,24 @@ export const useRuntime = ({ }; propsService.usePlugin({ - afterFillConfig(config: FormConfig, itemConfig: FormConfig) { + async afterFillConfig(config: FormConfig, itemConfig: FormConfig, labelWidth = '80px') { return [ { type: 'tab', items: [ { title: '属性', - labelWidth: '80px', + labelWidth, items: [...commonConfig, ...itemConfig], }, ], }, - ]; + ] as FormConfig; }, }); editorService.usePlugin({ - afterGetLayout() { + async afterGetLayout() { return Layout.RELATIVE; }, });