mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2025-06-22 01:39:31 +08:00
refactor(editor): editor组件改成setup
This commit is contained in:
parent
65854d9c0a
commit
803bf323ce
@ -5,7 +5,7 @@ import { EntryType } from '../types';
|
||||
|
||||
export const prepareEntryFile = async (app: App) => {
|
||||
const { moduleMainFilePath, options } = app;
|
||||
const { componentFileAffix, dynamicImport, hooks, useTs } = options;
|
||||
const { componentFileAffix, dynamicImport, hooks, useTs = true } = options;
|
||||
|
||||
let contentMap: Record<string, string> = {
|
||||
'comp-entry': generateContent(useTs, EntryType.COMPONENT, moduleMainFilePath.componentMap, componentFileAffix),
|
||||
|
@ -80,11 +80,13 @@
|
||||
</Framework>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, provide, reactive } from 'vue';
|
||||
<script lang="ts" setup>
|
||||
import { provide, reactive } from 'vue';
|
||||
|
||||
import { MApp } from '@tmagic/schema';
|
||||
|
||||
import Framework from './layouts/Framework.vue';
|
||||
import NavMenu from './layouts/NavMenu.vue';
|
||||
import TMagicNavMenu from './layouts/NavMenu.vue';
|
||||
import PropsPanel from './layouts/PropsPanel.vue';
|
||||
import Sidebar from './layouts/sidebar/Sidebar.vue';
|
||||
import Workspace from './layouts/workspace/Workspace.vue';
|
||||
@ -100,66 +102,59 @@ import propsService from './services/props';
|
||||
import storageService from './services/storage';
|
||||
import uiService from './services/ui';
|
||||
import keybindingConfig from './utils/keybinding-config';
|
||||
import editorProps from './editorProps';
|
||||
import { defaultEditorProps, EditorProps } from './editorProps';
|
||||
import { initServiceEvents, initServiceState } from './initService';
|
||||
import type { Services } from './type';
|
||||
|
||||
export default defineComponent({
|
||||
defineOptions({
|
||||
name: 'MEditor',
|
||||
|
||||
components: {
|
||||
TMagicNavMenu: NavMenu,
|
||||
Sidebar,
|
||||
Workspace,
|
||||
PropsPanel,
|
||||
Framework,
|
||||
},
|
||||
|
||||
props: editorProps,
|
||||
|
||||
emits: ['props-panel-mounted', 'update:modelValue'],
|
||||
|
||||
setup(props, { emit }) {
|
||||
const services: Services = {
|
||||
componentListService,
|
||||
eventsService,
|
||||
historyService,
|
||||
propsService,
|
||||
editorService,
|
||||
uiService,
|
||||
storageService,
|
||||
codeBlockService,
|
||||
depService,
|
||||
dataSourceService,
|
||||
keybindingService,
|
||||
};
|
||||
|
||||
initServiceEvents(props, emit, services);
|
||||
initServiceState(props, services);
|
||||
keybindingService.registe(keybindingConfig);
|
||||
keybindingService.registeEl('global');
|
||||
|
||||
provide('services', services);
|
||||
|
||||
provide('codeOptions', props.codeOptions);
|
||||
provide(
|
||||
'stageOptions',
|
||||
reactive({
|
||||
runtimeUrl: props.runtimeUrl,
|
||||
autoScrollIntoView: props.autoScrollIntoView,
|
||||
render: props.render,
|
||||
moveableOptions: props.moveableOptions,
|
||||
canSelect: props.canSelect,
|
||||
updateDragEl: props.updateDragEl,
|
||||
isContainer: props.isContainer,
|
||||
containerHighlightClassName: props.containerHighlightClassName,
|
||||
containerHighlightDuration: props.containerHighlightDuration,
|
||||
containerHighlightType: props.containerHighlightType,
|
||||
disabledDragStart: props.disabledDragStart,
|
||||
}),
|
||||
);
|
||||
|
||||
return services;
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
'props-panel-mounted': [instance: InstanceType<typeof PropsPanel>];
|
||||
'update:modelValue': [value: MApp | null];
|
||||
}>();
|
||||
|
||||
const props = withDefaults(defineProps<EditorProps>(), defaultEditorProps);
|
||||
|
||||
const services: Services = {
|
||||
componentListService,
|
||||
eventsService,
|
||||
historyService,
|
||||
propsService,
|
||||
editorService,
|
||||
uiService,
|
||||
storageService,
|
||||
codeBlockService,
|
||||
depService,
|
||||
dataSourceService,
|
||||
keybindingService,
|
||||
};
|
||||
|
||||
initServiceEvents(props, emit, services);
|
||||
initServiceState(props, services);
|
||||
keybindingService.registe(keybindingConfig);
|
||||
keybindingService.registeEl('global');
|
||||
|
||||
provide('services', services);
|
||||
|
||||
provide('codeOptions', props.codeOptions);
|
||||
provide(
|
||||
'stageOptions',
|
||||
reactive({
|
||||
runtimeUrl: props.runtimeUrl,
|
||||
autoScrollIntoView: props.autoScrollIntoView,
|
||||
render: props.render,
|
||||
moveableOptions: props.moveableOptions,
|
||||
canSelect: props.canSelect,
|
||||
updateDragEl: props.updateDragEl,
|
||||
isContainer: props.isContainer,
|
||||
containerHighlightClassName: props.containerHighlightClassName,
|
||||
containerHighlightDuration: props.containerHighlightDuration,
|
||||
containerHighlightType: props.containerHighlightType,
|
||||
disabledDragStart: props.disabledDragStart,
|
||||
}),
|
||||
);
|
||||
|
||||
defineExpose(services);
|
||||
</script>
|
||||
|
@ -1,8 +1,6 @@
|
||||
import type { PropType } from 'vue';
|
||||
|
||||
import type { EventOption } from '@tmagic/core';
|
||||
import type { FormConfig, FormState } from '@tmagic/form';
|
||||
import type { DataSourceSchema, MApp, MNode } from '@tmagic/schema';
|
||||
import type { DataSourceSchema, Id, MApp, MNode } from '@tmagic/schema';
|
||||
import StageCore, {
|
||||
CONTAINER_HIGHLIGHT_CLASS_NAME,
|
||||
ContainerHighlightType,
|
||||
@ -21,145 +19,68 @@ import type {
|
||||
StageRect,
|
||||
} from './type';
|
||||
|
||||
export default {
|
||||
export interface EditorProps {
|
||||
/** 页面初始值 */
|
||||
modelValue: {
|
||||
type: Object as PropType<MApp>,
|
||||
default: () => ({}),
|
||||
require: true,
|
||||
},
|
||||
|
||||
/** 左侧面板中的组件列表 */
|
||||
componentGroupList: {
|
||||
type: Array as PropType<ComponentGroup[]>,
|
||||
default: () => [],
|
||||
},
|
||||
|
||||
/** 左侧面板中的组件列表 */
|
||||
datasourceList: {
|
||||
type: Array as PropType<DatasourceTypeOption[]>,
|
||||
default: () => [],
|
||||
},
|
||||
|
||||
modelValue?: MApp;
|
||||
/** 左侧面板中的组件类型列表 */
|
||||
componentGroupList?: ComponentGroup[];
|
||||
/** 左侧面板中的数据源类型列表 */
|
||||
datasourceList?: DatasourceTypeOption[];
|
||||
/** 左侧面板配置 */
|
||||
sidebar: {
|
||||
type: Object as PropType<SideBarData>,
|
||||
},
|
||||
|
||||
sidebar?: SideBarData;
|
||||
/** 顶部工具栏配置 */
|
||||
menu: {
|
||||
type: Object as PropType<MenuBarData>,
|
||||
default: () => ({ left: [], right: [] }),
|
||||
},
|
||||
|
||||
menu?: MenuBarData;
|
||||
/** 组件树右键菜单 */
|
||||
layerContentMenu: {
|
||||
type: Array as PropType<(MenuButton | MenuComponent)[]>,
|
||||
default: () => [],
|
||||
},
|
||||
|
||||
layerContentMenu?: (MenuButton | MenuComponent)[];
|
||||
/** 画布右键菜单 */
|
||||
stageContentMenu: {
|
||||
type: Array as PropType<(MenuButton | MenuComponent)[]>,
|
||||
default: () => [],
|
||||
},
|
||||
|
||||
stageContentMenu?: (MenuButton | MenuComponent)[];
|
||||
/** 中间工作区域中画布渲染的内容 */
|
||||
render: {
|
||||
type: Function as PropType<(stage: StageCore) => HTMLDivElement | Promise<HTMLDivElement>>,
|
||||
},
|
||||
|
||||
render?: (stage: StageCore) => HTMLDivElement | Promise<HTMLDivElement>;
|
||||
/** 中间工作区域中画布通过iframe渲染时的页面url */
|
||||
runtimeUrl: String,
|
||||
|
||||
runtimeUrl?: string;
|
||||
/** 选中时是否自动滚动到可视区域 */
|
||||
autoScrollIntoView: Boolean,
|
||||
|
||||
autoScrollIntoView?: boolean;
|
||||
/** 组件的属性配置表单的dsl */
|
||||
propsConfigs: {
|
||||
type: Object as PropType<Record<string, FormConfig>>,
|
||||
default: () => ({}),
|
||||
},
|
||||
|
||||
propsConfigs?: Record<string, FormConfig>;
|
||||
/** 添加组件时的默认值 */
|
||||
propsValues: {
|
||||
type: Object as PropType<Record<string, Partial<MNode>>>,
|
||||
default: () => ({}),
|
||||
},
|
||||
|
||||
propsValues?: Record<string, Partial<MNode>>;
|
||||
/** 组件联动事件选项列表 */
|
||||
eventMethodList: {
|
||||
type: Object as PropType<Record<string, { events: EventOption[]; methods: EventOption[] }>>,
|
||||
default: () => ({}),
|
||||
},
|
||||
|
||||
eventMethodList?: Record<string, { events: EventOption[]; methods: EventOption[] }>;
|
||||
/** 添加数据源时的默认值 */
|
||||
datasourceValues: {
|
||||
type: Object as PropType<Record<string, Partial<DataSourceSchema>>>,
|
||||
default: () => ({}),
|
||||
},
|
||||
|
||||
datasourceValues?: Record<string, Partial<DataSourceSchema>>;
|
||||
/** 数据源的属性配置表单的dsl */
|
||||
datasourceConfigs: {
|
||||
type: Object as PropType<Record<string, FormConfig>>,
|
||||
default: () => ({}),
|
||||
},
|
||||
|
||||
datasourceConfigs?: Record<string, FormConfig>;
|
||||
/** 画布中组件选中框的移动范围 */
|
||||
moveableOptions: {
|
||||
type: [Object, Function] as PropType<
|
||||
MoveableOptions | ((config?: CustomizeMoveableOptionsCallbackConfig) => MoveableOptions)
|
||||
>,
|
||||
},
|
||||
|
||||
moveableOptions?: MoveableOptions | ((config?: CustomizeMoveableOptionsCallbackConfig) => MoveableOptions);
|
||||
/** 编辑器初始化时默认选中的组件ID */
|
||||
defaultSelected: {
|
||||
type: [Number, String],
|
||||
},
|
||||
defaultSelected?: Id;
|
||||
canSelect?: (el: HTMLElement) => boolean | Promise<boolean>;
|
||||
isContainer?: (el: HTMLElement) => boolean | Promise<boolean>;
|
||||
containerHighlightClassName?: string;
|
||||
containerHighlightDuration?: number;
|
||||
containerHighlightType?: ContainerHighlightType;
|
||||
stageRect?: StageRect;
|
||||
codeOptions?: { [key: string]: any };
|
||||
updateDragEl?: UpdateDragEl;
|
||||
disabledDragStart?: boolean;
|
||||
extendFormState?: (state: FormState) => Record<string, any> | Promise<Record<string, any>>;
|
||||
}
|
||||
|
||||
canSelect: {
|
||||
type: Function as PropType<(el: HTMLElement) => boolean | Promise<boolean>>,
|
||||
default: (el: HTMLElement) => Boolean(el.id),
|
||||
},
|
||||
|
||||
isContainer: {
|
||||
type: Function as PropType<(el: HTMLElement) => boolean | Promise<boolean>>,
|
||||
default: (el: HTMLElement) => el.classList.contains('magic-ui-container'),
|
||||
},
|
||||
|
||||
containerHighlightClassName: {
|
||||
type: String,
|
||||
default: CONTAINER_HIGHLIGHT_CLASS_NAME,
|
||||
},
|
||||
|
||||
containerHighlightDuration: {
|
||||
type: Number,
|
||||
default: 800,
|
||||
},
|
||||
|
||||
containerHighlightType: {
|
||||
type: String as PropType<ContainerHighlightType>,
|
||||
default: ContainerHighlightType.DEFAULT,
|
||||
},
|
||||
|
||||
stageRect: {
|
||||
type: [String, Object] as PropType<StageRect>,
|
||||
},
|
||||
|
||||
codeOptions: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
|
||||
updateDragEl: {
|
||||
type: Function as PropType<UpdateDragEl>,
|
||||
},
|
||||
|
||||
disabledDragStart: {
|
||||
type: Boolean,
|
||||
},
|
||||
|
||||
extendFormState: {
|
||||
type: Function as PropType<(state: FormState) => Record<string, any> | Promise<Record<string, any>>>,
|
||||
},
|
||||
export const defaultEditorProps = {
|
||||
componentGroupList: () => [],
|
||||
datasourceList: () => [],
|
||||
menu: () => ({ left: [], right: [] }),
|
||||
layerContentMenu: () => [],
|
||||
stageContentMenu: () => [],
|
||||
propsConfigs: () => ({}),
|
||||
propsValues: () => ({}),
|
||||
eventMethodList: () => ({}),
|
||||
datasourceValues: () => ({}),
|
||||
datasourceConfigs: () => ({}),
|
||||
canSelect: (el: HTMLElement) => Boolean(el.id),
|
||||
isContainer: (el: HTMLElement) => el.classList.contains('magic-ui-container'),
|
||||
containerHighlightClassName: CONTAINER_HIGHLIGHT_CLASS_NAME,
|
||||
containerHighlightDuration: 800,
|
||||
containerHighlightType: ContainerHighlightType.DEFAULT,
|
||||
codeOptions: () => ({}),
|
||||
};
|
||||
|
@ -1,4 +1,3 @@
|
||||
import type { ExtractPropTypes } from 'vue';
|
||||
import { onUnmounted, toRaw, watch } from 'vue';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
|
||||
@ -6,6 +5,7 @@ import type { EventOption } from '@tmagic/core';
|
||||
import type { CodeBlockContent, DataSourceSchema, Id, MApp, MNode, MPage } from '@tmagic/schema';
|
||||
import { getNodes } from '@tmagic/utils';
|
||||
|
||||
import PropsPanel from './layouts/PropsPanel.vue';
|
||||
import type { Target } from './services/dep';
|
||||
import {
|
||||
createCodeBlockTarget,
|
||||
@ -13,7 +13,7 @@ import {
|
||||
createDataSourceMethodTarget,
|
||||
createDataSourceTarget,
|
||||
} from './utils/dep';
|
||||
import editorProps from './editorProps';
|
||||
import { EditorProps } from './editorProps';
|
||||
import { DepTargetType, Services } from './type';
|
||||
|
||||
export declare type LooseRequired<T> = {
|
||||
@ -21,7 +21,7 @@ export declare type LooseRequired<T> = {
|
||||
};
|
||||
|
||||
export const initServiceState = (
|
||||
props: Readonly<LooseRequired<Readonly<ExtractPropTypes<typeof editorProps>>>>,
|
||||
props: EditorProps,
|
||||
{
|
||||
editorService,
|
||||
historyService,
|
||||
@ -38,7 +38,7 @@ export const initServiceState = (
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(modelValue) => {
|
||||
editorService.set('root', modelValue);
|
||||
editorService.set('root', modelValue || null);
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
@ -47,7 +47,7 @@ export const initServiceState = (
|
||||
|
||||
watch(
|
||||
() => props.componentGroupList,
|
||||
(componentGroupList) => componentListService.setList(componentGroupList),
|
||||
(componentGroupList) => componentGroupList && componentListService.setList(componentGroupList),
|
||||
{
|
||||
immediate: true,
|
||||
},
|
||||
@ -55,7 +55,7 @@ export const initServiceState = (
|
||||
|
||||
watch(
|
||||
() => props.datasourceList,
|
||||
(datasourceList) => dataSourceService.set('datasourceTypeList', datasourceList),
|
||||
(datasourceList) => datasourceList && dataSourceService.set('datasourceTypeList', datasourceList),
|
||||
{
|
||||
immediate: true,
|
||||
},
|
||||
@ -63,7 +63,7 @@ export const initServiceState = (
|
||||
|
||||
watch(
|
||||
() => props.propsConfigs,
|
||||
(configs) => propsService.setPropsConfigs(configs),
|
||||
(configs) => configs && propsService.setPropsConfigs(configs),
|
||||
{
|
||||
immediate: true,
|
||||
},
|
||||
@ -71,7 +71,7 @@ export const initServiceState = (
|
||||
|
||||
watch(
|
||||
() => props.propsValues,
|
||||
(values) => propsService.setPropsValues(values),
|
||||
(values) => values && propsService.setPropsValues(values),
|
||||
{
|
||||
immediate: true,
|
||||
},
|
||||
@ -83,10 +83,11 @@ export const initServiceState = (
|
||||
const eventsList: Record<string, EventOption[]> = {};
|
||||
const methodsList: Record<string, EventOption[]> = {};
|
||||
|
||||
Object.keys(eventMethodList).forEach((type: string) => {
|
||||
eventsList[type] = eventMethodList[type].events;
|
||||
methodsList[type] = eventMethodList[type].methods;
|
||||
});
|
||||
eventMethodList &&
|
||||
Object.keys(eventMethodList).forEach((type: string) => {
|
||||
eventsList[type] = eventMethodList[type].events;
|
||||
methodsList[type] = eventMethodList[type].methods;
|
||||
});
|
||||
|
||||
eventsService.setEvents(eventsList);
|
||||
eventsService.setMethods(methodsList);
|
||||
@ -99,9 +100,10 @@ export const initServiceState = (
|
||||
watch(
|
||||
() => props.datasourceConfigs,
|
||||
(configs) => {
|
||||
Object.entries(configs).forEach(([key, value]) => {
|
||||
dataSourceService.setFormConfig(key, value);
|
||||
});
|
||||
configs &&
|
||||
Object.entries(configs).forEach(([key, value]) => {
|
||||
dataSourceService.setFormConfig(key, value);
|
||||
});
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
@ -111,9 +113,10 @@ export const initServiceState = (
|
||||
watch(
|
||||
() => props.datasourceValues,
|
||||
(values) => {
|
||||
Object.entries(values).forEach(([key, value]) => {
|
||||
dataSourceService.setFormValue(key, value);
|
||||
});
|
||||
values &&
|
||||
Object.entries(values).forEach(([key, value]) => {
|
||||
dataSourceService.setFormValue(key, value);
|
||||
});
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
@ -148,8 +151,9 @@ export const initServiceState = (
|
||||
};
|
||||
|
||||
export const initServiceEvents = (
|
||||
props: Readonly<LooseRequired<Readonly<ExtractPropTypes<typeof editorProps>>>>,
|
||||
emit: (event: 'props-panel-mounted' | 'update:modelValue', ...args: any[]) => void,
|
||||
props: EditorProps,
|
||||
emit: ((event: 'props-panel-mounted', instance: InstanceType<typeof PropsPanel>) => void) &
|
||||
((event: 'update:modelValue', value: MApp | null) => void),
|
||||
{ editorService, codeBlockService, dataSourceService, depService }: Services,
|
||||
) => {
|
||||
const getApp = () => {
|
||||
@ -247,7 +251,7 @@ export const initServiceEvents = (
|
||||
depService.addTarget(createDataSourceCondTarget(ds.id));
|
||||
};
|
||||
|
||||
const rootChangeHandler = async (value: MApp, preValue?: MApp | null) => {
|
||||
const rootChangeHandler = async (value: MApp | null, preValue?: MApp | null) => {
|
||||
const nodeId = editorService.get('node')?.id || props.defaultSelected;
|
||||
let node;
|
||||
if (nodeId) {
|
||||
@ -268,6 +272,8 @@ export const initServiceEvents = (
|
||||
emit('update:modelValue', value);
|
||||
}
|
||||
|
||||
if (!value) return;
|
||||
|
||||
value.codeBlocks = value.codeBlocks || {};
|
||||
value.dataSources = value.dataSources || [];
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user