@tmagic/editor 1.4.3 → 1.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/style.css +17 -3
- package/dist/tmagic-editor.js +1309 -1208
- package/dist/tmagic-editor.umd.cjs +1327 -1224
- package/package.json +19 -24
- package/src/Editor.vue +6 -1
- package/src/editorProps.ts +3 -0
- package/src/fields/CodeSelectCol.vue +26 -18
- package/src/fields/DataSourceFieldSelect.vue +23 -61
- package/src/fields/DataSourceMethodSelect.vue +25 -31
- package/src/fields/DataSourceSelect.vue +49 -13
- package/src/fields/EventSelect.vue +37 -14
- package/src/hooks/use-editor-content-height.ts +11 -5
- package/src/layouts/PropsPanel.vue +3 -1
- package/src/layouts/sidebar/Sidebar.vue +24 -8
- package/src/layouts/sidebar/code-block/CodeBlockListPanel.vue +6 -1
- package/src/layouts/sidebar/data-source/DataSourceListPanel.vue +6 -1
- package/src/layouts/workspace/viewer/Stage.vue +7 -6
- package/src/services/editor.ts +2 -2
- package/src/services/ui.ts +1 -0
- package/src/theme/data-source-field.scss +12 -0
- package/src/theme/props-panel.scss +1 -1
- package/src/theme/theme.scss +1 -0
- package/src/type.ts +31 -2
- package/src/utils/content-menu.ts +7 -3
- package/src/utils/data-source/index.ts +39 -3
- package/src/utils/editor.ts +14 -7
- package/types/components/CodeBlockEditor.vue.d.ts +21 -34
- package/types/components/CodeParams.vue.d.ts +2 -2
- package/types/components/ContentMenu.vue.d.ts +4 -4
- package/types/components/FloatingBox.vue.d.ts +41 -38
- package/types/components/ScrollViewer.vue.d.ts +1 -1
- package/types/components/ToolButton.vue.d.ts +6 -6
- package/types/components/Tree.vue.d.ts +2 -2
- package/types/editorProps.d.ts +3 -0
- package/types/fields/CodeLink.vue.d.ts +2 -2
- package/types/fields/DataSourceFields.vue.d.ts +32 -78
- package/types/fields/DataSourceInput.vue.d.ts +2 -2
- package/types/fields/DataSourceMethods.vue.d.ts +2 -2
- package/types/fields/DataSourceMocks.vue.d.ts +31 -76
- package/types/fields/KeyValue.vue.d.ts +2 -2
- package/types/fields/UISelect.vue.d.ts +2 -2
- package/types/hooks/use-code-block-edit.d.ts +18 -6
- package/types/hooks/use-data-source-edit.d.ts +18 -6
- package/types/hooks/use-data-source-method.d.ts +18 -6
- package/types/layouts/CodeEditor.vue.d.ts +1 -1
- package/types/layouts/PropsPanel.vue.d.ts +40 -38
- package/types/layouts/sidebar/Sidebar.vue.d.ts +7 -7
- package/types/layouts/sidebar/code-block/CodeBlockList.vue.d.ts +1 -1
- package/types/layouts/sidebar/data-source/DataSourceConfigPanel.vue.d.ts +20 -30
- package/types/layouts/sidebar/data-source/DataSourceList.vue.d.ts +1 -1
- package/types/layouts/sidebar/layer/LayerMenu.vue.d.ts +8 -8
- package/types/layouts/sidebar/layer/LayerPanel.vue.d.ts +4 -4
- package/types/layouts/sidebar/layer/use-click.d.ts +13 -13
- package/types/layouts/workspace/Workspace.vue.d.ts +4 -4
- package/types/layouts/workspace/viewer/Stage.vue.d.ts +4 -4
- package/types/layouts/workspace/viewer/ViewerMenu.vue.d.ts +8 -8
- package/types/services/dataSource.d.ts +1 -0
- package/types/services/ui.d.ts +19 -1
- package/types/type.d.ts +26 -2
- package/types/utils/data-source/index.d.ts +3 -2
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
<TMagicButton class="create-button" type="primary" :size="size" :disabled="disabled" @click="addEvent()"
|
|
16
16
|
>添加事件</TMagicButton
|
|
17
17
|
>
|
|
18
|
-
<
|
|
18
|
+
<MPanel
|
|
19
19
|
v-for="(cardItem, index) in model[name]"
|
|
20
20
|
:key="index"
|
|
21
21
|
:disabled="disabled"
|
|
@@ -26,14 +26,14 @@
|
|
|
26
26
|
@change="onChangeHandler"
|
|
27
27
|
>
|
|
28
28
|
<template #header>
|
|
29
|
-
<
|
|
29
|
+
<MContainer
|
|
30
30
|
class="fullWidth"
|
|
31
31
|
:config="eventNameConfig"
|
|
32
32
|
:model="cardItem"
|
|
33
33
|
:disabled="disabled"
|
|
34
34
|
:size="size"
|
|
35
35
|
@change="onChangeHandler"
|
|
36
|
-
></
|
|
36
|
+
></MContainer>
|
|
37
37
|
<TMagicButton
|
|
38
38
|
style="color: #f56c6c"
|
|
39
39
|
link
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
@click="removeEvent(index)"
|
|
44
44
|
></TMagicButton>
|
|
45
45
|
</template>
|
|
46
|
-
</
|
|
46
|
+
</MPanel>
|
|
47
47
|
</div>
|
|
48
48
|
</div>
|
|
49
49
|
</template>
|
|
@@ -55,10 +55,13 @@ import { has } from 'lodash-es';
|
|
|
55
55
|
|
|
56
56
|
import type { EventOption } from '@tmagic/core';
|
|
57
57
|
import { TMagicButton } from '@tmagic/design';
|
|
58
|
-
import type { FieldProps, FormState } from '@tmagic/form';
|
|
58
|
+
import type { CascaderOption, FieldProps, FormState, PanelConfig } from '@tmagic/form';
|
|
59
|
+
import { MContainer, MPanel } from '@tmagic/form';
|
|
59
60
|
import { ActionType } from '@tmagic/schema';
|
|
61
|
+
import { DATA_SOURCE_FIELDS_CHANGE_EVENT_PREFIX } from '@tmagic/utils';
|
|
60
62
|
|
|
61
63
|
import type { CodeSelectColConfig, DataSourceMethodSelectConfig, EventSelectConfig, Services } from '@editor/type';
|
|
64
|
+
import { getCascaderOptionsFromFields } from '@editor/utils';
|
|
62
65
|
|
|
63
66
|
defineOptions({
|
|
64
67
|
name: 'MFieldsEventSelect',
|
|
@@ -77,26 +80,45 @@ const codeBlockService = services?.codeBlockService;
|
|
|
77
80
|
|
|
78
81
|
// 事件名称下拉框表单配置
|
|
79
82
|
const eventNameConfig = computed(() => {
|
|
83
|
+
const fieldType = props.config.src === 'component' ? 'select' : 'cascader';
|
|
80
84
|
const defaultEventNameConfig = {
|
|
81
85
|
name: 'name',
|
|
82
86
|
text: '事件',
|
|
83
|
-
type:
|
|
87
|
+
type: fieldType,
|
|
84
88
|
labelWidth: '40px',
|
|
89
|
+
checkStrictly: true,
|
|
90
|
+
valueSeparator: '.',
|
|
85
91
|
options: (mForm: FormState, { formValue }: any) => {
|
|
86
|
-
let events: EventOption[] = [];
|
|
92
|
+
let events: EventOption[] | CascaderOption[] = [];
|
|
87
93
|
|
|
88
94
|
if (!eventsService || !dataSourceService) return events;
|
|
89
95
|
|
|
90
96
|
if (props.config.src === 'component') {
|
|
91
97
|
events = eventsService.getEvent(formValue.type);
|
|
92
|
-
|
|
93
|
-
|
|
98
|
+
return events.map((option) => ({
|
|
99
|
+
text: option.label,
|
|
100
|
+
value: option.value,
|
|
101
|
+
}));
|
|
94
102
|
}
|
|
103
|
+
if (props.config.src === 'datasource') {
|
|
104
|
+
// 从数据源类型中获取到相关事件
|
|
105
|
+
events = dataSourceService.getFormEvent(formValue.type);
|
|
106
|
+
// 从数据源类型和实例中分别获取数据以追加数据变化的事件
|
|
107
|
+
const dataSource = dataSourceService.getDataSourceById(formValue.id);
|
|
108
|
+
const fields = dataSource?.fields || [];
|
|
109
|
+
if (fields.length > 0) {
|
|
110
|
+
return [
|
|
111
|
+
...events,
|
|
112
|
+
{
|
|
113
|
+
label: '数据变化',
|
|
114
|
+
value: DATA_SOURCE_FIELDS_CHANGE_EVENT_PREFIX,
|
|
115
|
+
children: getCascaderOptionsFromFields(fields),
|
|
116
|
+
},
|
|
117
|
+
];
|
|
118
|
+
}
|
|
95
119
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
value: option.value,
|
|
99
|
-
}));
|
|
120
|
+
return events;
|
|
121
|
+
}
|
|
100
122
|
},
|
|
101
123
|
};
|
|
102
124
|
return { ...defaultEventNameConfig, ...props.config.eventNameConfig };
|
|
@@ -227,7 +249,8 @@ const tableConfig = computed(() => ({
|
|
|
227
249
|
}));
|
|
228
250
|
|
|
229
251
|
// 组件动作组表单配置
|
|
230
|
-
const actionsConfig = computed(() => ({
|
|
252
|
+
const actionsConfig = computed<PanelConfig>(() => ({
|
|
253
|
+
type: 'panel',
|
|
231
254
|
items: [
|
|
232
255
|
{
|
|
233
256
|
type: 'group-list',
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { computed, inject, ref,
|
|
1
|
+
import { computed, inject, ref, watch } from 'vue';
|
|
2
2
|
|
|
3
3
|
import type { Services } from '@editor/type';
|
|
4
4
|
|
|
@@ -9,10 +9,16 @@ export const useEditorContentHeight = () => {
|
|
|
9
9
|
const editorContentHeight = computed(() => frameworkHeight.value - navMenuHeight.value);
|
|
10
10
|
|
|
11
11
|
const height = ref(0);
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
watch(
|
|
13
|
+
editorContentHeight,
|
|
14
|
+
() => {
|
|
15
|
+
if (height.value > 0 && height.value === editorContentHeight.value) return;
|
|
16
|
+
height.value = editorContentHeight.value;
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
immediate: true,
|
|
20
|
+
},
|
|
21
|
+
);
|
|
16
22
|
|
|
17
23
|
return {
|
|
18
24
|
height,
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<slot name="props-panel-header"></slot>
|
|
4
4
|
<MForm
|
|
5
5
|
ref="configForm"
|
|
6
|
-
:class="
|
|
6
|
+
:class="propsPanelSize"
|
|
7
7
|
:popper-class="`m-editor-props-panel-popper ${propsPanelSize}`"
|
|
8
8
|
:size="propsPanelSize"
|
|
9
9
|
:init-values="values"
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
></MForm>
|
|
15
15
|
|
|
16
16
|
<TMagicButton
|
|
17
|
+
v-if="!disabledShowSrc"
|
|
17
18
|
class="m-editor-props-panel-src-icon"
|
|
18
19
|
circle
|
|
19
20
|
size="large"
|
|
@@ -57,6 +58,7 @@ defineOptions({
|
|
|
57
58
|
});
|
|
58
59
|
|
|
59
60
|
defineProps<{
|
|
61
|
+
disabledShowSrc?: boolean;
|
|
60
62
|
extendState?: (state: FormState) => Record<string, any> | Promise<Record<string, any>>;
|
|
61
63
|
}>();
|
|
62
64
|
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
draggable="true"
|
|
9
9
|
:key="config.$key ?? index"
|
|
10
10
|
:class="{ 'is-active': activeTabName === config.text }"
|
|
11
|
-
|
|
11
|
+
:style="config.tabStyle || {}"
|
|
12
|
+
@click="activeTabName = config.text || config.$key || `${index}`"
|
|
12
13
|
@dragstart="dragstartHandler"
|
|
13
14
|
@dragend="dragendHandler(config.$key, $event)"
|
|
14
15
|
>
|
|
@@ -20,7 +21,7 @@
|
|
|
20
21
|
class="m-editor-sidebar-content"
|
|
21
22
|
v-for="(config, index) in sideBarItems"
|
|
22
23
|
:key="config.$key ?? index"
|
|
23
|
-
v-show="
|
|
24
|
+
v-show="[config.text, config.$key, `${index}`].includes(activeTabName)"
|
|
24
25
|
>
|
|
25
26
|
<component
|
|
26
27
|
v-if="config && !floatBoxStates[config.$key]?.status"
|
|
@@ -151,6 +152,7 @@ import {
|
|
|
151
152
|
type SidebarSlots,
|
|
152
153
|
type SideComponent,
|
|
153
154
|
type SideItem,
|
|
155
|
+
SideItemKey,
|
|
154
156
|
} from '@editor/type';
|
|
155
157
|
|
|
156
158
|
import CodeBlockListPanel from './code-block/CodeBlockListPanel.vue';
|
|
@@ -171,7 +173,11 @@ const props = withDefaults(
|
|
|
171
173
|
customContentMenu?: (menus: (MenuButton | MenuComponent)[], type: string) => (MenuButton | MenuComponent)[];
|
|
172
174
|
}>(),
|
|
173
175
|
{
|
|
174
|
-
data: () => ({
|
|
176
|
+
data: () => ({
|
|
177
|
+
type: 'tabs',
|
|
178
|
+
status: '组件',
|
|
179
|
+
items: [SideItemKey.COMPONENT_LIST, SideItemKey.LAYER, SideItemKey.CODE_BLOCK, SideItemKey.DATA_SOURCE],
|
|
180
|
+
}),
|
|
175
181
|
},
|
|
176
182
|
);
|
|
177
183
|
|
|
@@ -184,8 +190,8 @@ const activeTabName = ref(props.data?.status);
|
|
|
184
190
|
|
|
185
191
|
const getItemConfig = (data: SideItem): SideComponent => {
|
|
186
192
|
const map: Record<string, SideComponent> = {
|
|
187
|
-
|
|
188
|
-
$key:
|
|
193
|
+
[SideItemKey.COMPONENT_LIST]: {
|
|
194
|
+
$key: SideItemKey.COMPONENT_LIST,
|
|
189
195
|
type: 'component',
|
|
190
196
|
icon: Goods,
|
|
191
197
|
text: '组件',
|
|
@@ -204,7 +210,7 @@ const getItemConfig = (data: SideItem): SideComponent => {
|
|
|
204
210
|
component: LayerPanel,
|
|
205
211
|
slots: {},
|
|
206
212
|
},
|
|
207
|
-
|
|
213
|
+
[SideItemKey.CODE_BLOCK]: {
|
|
208
214
|
$key: 'code-block',
|
|
209
215
|
type: 'component',
|
|
210
216
|
icon: EditPen,
|
|
@@ -212,8 +218,8 @@ const getItemConfig = (data: SideItem): SideComponent => {
|
|
|
212
218
|
component: CodeBlockListPanel,
|
|
213
219
|
slots: {},
|
|
214
220
|
},
|
|
215
|
-
|
|
216
|
-
$key:
|
|
221
|
+
[SideItemKey.DATA_SOURCE]: {
|
|
222
|
+
$key: SideItemKey.DATA_SOURCE,
|
|
217
223
|
type: 'component',
|
|
218
224
|
icon: Coin,
|
|
219
225
|
text: '数据源',
|
|
@@ -227,6 +233,16 @@ const getItemConfig = (data: SideItem): SideComponent => {
|
|
|
227
233
|
|
|
228
234
|
const sideBarItems = computed(() => props.data.items.map((item) => getItemConfig(item)));
|
|
229
235
|
|
|
236
|
+
watch(
|
|
237
|
+
sideBarItems,
|
|
238
|
+
(items) => {
|
|
239
|
+
services?.uiService.set('sideBarItems', items);
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
immediate: true,
|
|
243
|
+
},
|
|
244
|
+
);
|
|
245
|
+
|
|
230
246
|
watch(
|
|
231
247
|
() => props.data.status,
|
|
232
248
|
(status) => {
|
|
@@ -36,7 +36,7 @@ import type { Id } from '@tmagic/schema';
|
|
|
36
36
|
import CodeBlockEditor from '@editor/components/CodeBlockEditor.vue';
|
|
37
37
|
import SearchInput from '@editor/components/SearchInput.vue';
|
|
38
38
|
import { useCodeBlockEdit } from '@editor/hooks/use-code-block-edit';
|
|
39
|
-
import type { CodeBlockListPanelSlots, CodeDeleteErrorType, Services } from '@editor/type';
|
|
39
|
+
import type { CodeBlockListPanelSlots, CodeDeleteErrorType, EventBus, Services } from '@editor/type';
|
|
40
40
|
|
|
41
41
|
import CodeBlockList from './CodeBlockList.vue';
|
|
42
42
|
|
|
@@ -50,6 +50,7 @@ defineProps<{
|
|
|
50
50
|
customError?: (id: Id, errorType: CodeDeleteErrorType) => any;
|
|
51
51
|
}>();
|
|
52
52
|
|
|
53
|
+
const eventBus = inject<EventBus>('eventBus');
|
|
53
54
|
const { codeBlockService } = inject<Services>('services') || {};
|
|
54
55
|
|
|
55
56
|
const editable = computed(() => codeBlockService?.getEditStatus());
|
|
@@ -62,4 +63,8 @@ const codeBlockList = ref<InstanceType<typeof CodeBlockList>>();
|
|
|
62
63
|
const filterTextChangeHandler = (val: string) => {
|
|
63
64
|
codeBlockList.value?.filter(val);
|
|
64
65
|
};
|
|
66
|
+
|
|
67
|
+
eventBus?.on('edit-code', (id: string) => {
|
|
68
|
+
editCode(id);
|
|
69
|
+
});
|
|
65
70
|
</script>
|
|
@@ -46,7 +46,7 @@ import { TMagicButton, TMagicPopover, TMagicScrollbar } from '@tmagic/design';
|
|
|
46
46
|
import SearchInput from '@editor/components/SearchInput.vue';
|
|
47
47
|
import ToolButton from '@editor/components/ToolButton.vue';
|
|
48
48
|
import { useDataSourceEdit } from '@editor/hooks/use-data-source-edit';
|
|
49
|
-
import type { DataSourceListSlots, Services } from '@editor/type';
|
|
49
|
+
import type { DataSourceListSlots, EventBus, Services } from '@editor/type';
|
|
50
50
|
|
|
51
51
|
import DataSourceConfigPanel from './DataSourceConfigPanel.vue';
|
|
52
52
|
import DataSourceList from './DataSourceList.vue';
|
|
@@ -57,6 +57,7 @@ defineOptions({
|
|
|
57
57
|
name: 'MEditorDataSourceListPanel',
|
|
58
58
|
});
|
|
59
59
|
|
|
60
|
+
const eventBus = inject<EventBus>('eventBus');
|
|
60
61
|
const { dataSourceService } = inject<Services>('services') || {};
|
|
61
62
|
|
|
62
63
|
const { editDialog, dataSourceValues, dialogTitle, editable, editHandler, submitDataSourceHandler } =
|
|
@@ -98,4 +99,8 @@ const dataSourceList = ref<InstanceType<typeof DataSourceList>>();
|
|
|
98
99
|
const filterTextChangeHandler = (val: string) => {
|
|
99
100
|
dataSourceList.value?.filter(val);
|
|
100
101
|
};
|
|
102
|
+
|
|
103
|
+
eventBus?.on('edit-data-source', (id: string) => {
|
|
104
|
+
editHandler(id);
|
|
105
|
+
});
|
|
101
106
|
</script>
|
|
@@ -45,7 +45,8 @@ import { computed, inject, markRaw, nextTick, onBeforeUnmount, onMounted, ref, t
|
|
|
45
45
|
import { cloneDeep } from 'lodash-es';
|
|
46
46
|
|
|
47
47
|
import type { MApp, MContainer } from '@tmagic/schema';
|
|
48
|
-
import StageCore, {
|
|
48
|
+
import StageCore, { getOffset, Runtime } from '@tmagic/stage';
|
|
49
|
+
import { calcValueByFontsize } from '@tmagic/utils';
|
|
49
50
|
|
|
50
51
|
import ScrollViewer from '@editor/components/ScrollViewer.vue';
|
|
51
52
|
import { useStage } from '@editor/hooks/use-stage';
|
|
@@ -223,18 +224,18 @@ const dropHandler = async (e: DragEvent) => {
|
|
|
223
224
|
top = e.clientY - containerRect.top + scrollTop;
|
|
224
225
|
left = e.clientX - containerRect.left + scrollLeft;
|
|
225
226
|
|
|
226
|
-
if (parentEl
|
|
227
|
+
if (parentEl) {
|
|
227
228
|
const { left: parentLeft, top: parentTop } = getOffset(parentEl);
|
|
228
|
-
left = left -
|
|
229
|
-
top = top -
|
|
229
|
+
left = left - parentLeft * zoom.value;
|
|
230
|
+
top = top - parentTop * zoom.value;
|
|
230
231
|
}
|
|
231
232
|
}
|
|
232
233
|
|
|
233
234
|
config.data.style = {
|
|
234
235
|
...style,
|
|
235
236
|
position,
|
|
236
|
-
top: top / zoom.value,
|
|
237
|
-
left: left / zoom.value,
|
|
237
|
+
top: calcValueByFontsize(doc, top / zoom.value),
|
|
238
|
+
left: calcValueByFontsize(doc, left / zoom.value),
|
|
238
239
|
};
|
|
239
240
|
|
|
240
241
|
config.data.inputEvent = e;
|
package/src/services/editor.ts
CHANGED
|
@@ -23,7 +23,7 @@ import { Writable } from 'type-fest';
|
|
|
23
23
|
import { DepTargetType } from '@tmagic/dep';
|
|
24
24
|
import type { Id, MApp, MComponent, MContainer, MNode, MPage, MPageFragment } from '@tmagic/schema';
|
|
25
25
|
import { NodeType } from '@tmagic/schema';
|
|
26
|
-
import { getNodePath, isNumber, isPage, isPageFragment, isPop } from '@tmagic/utils';
|
|
26
|
+
import { calcValueByFontsize, getNodePath, isNumber, isPage, isPageFragment, isPop } from '@tmagic/utils';
|
|
27
27
|
|
|
28
28
|
import BaseService from '@editor/services//BaseService';
|
|
29
29
|
import propsService from '@editor/services//props';
|
|
@@ -741,7 +741,7 @@ class Editor extends BaseService {
|
|
|
741
741
|
const el = doc.getElementById(`${node.id}`);
|
|
742
742
|
const parentEl = layout === Layout.FIXED ? doc.body : el?.offsetParent;
|
|
743
743
|
if (parentEl && el) {
|
|
744
|
-
node.style.left = (parentEl.clientWidth - el.clientWidth) / 2;
|
|
744
|
+
node.style.left = calcValueByFontsize(doc, (parentEl.clientWidth - el.clientWidth) / 2);
|
|
745
745
|
node.style.right = '';
|
|
746
746
|
}
|
|
747
747
|
} else if (parent.style && isNumber(parent.style?.width) && isNumber(node.style?.width)) {
|
package/src/services/ui.ts
CHANGED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
.m-fields-data-source-select,
|
|
2
|
+
.m-fields-data-source-field-select,
|
|
3
|
+
.m-fields-data-source-method-select .data-source-method-select-container,
|
|
4
|
+
.m-fields-code-select-col .code-select-container {
|
|
5
|
+
width: 100%;
|
|
6
|
+
display: flex;
|
|
7
|
+
align-items: center;
|
|
8
|
+
|
|
9
|
+
.m-fields-select-action-button {
|
|
10
|
+
margin-left: 5px;
|
|
11
|
+
}
|
|
12
|
+
}
|
package/src/theme/theme.scss
CHANGED
package/src/type.ts
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import type { Component } from 'vue';
|
|
20
|
+
import type EventEmitter from 'events';
|
|
20
21
|
import type { PascalCasedProperties } from 'type-fest';
|
|
21
22
|
|
|
22
23
|
import type { ChildConfig, ColumnConfig, FilterFunction, FormConfig, FormItem, Input } from '@tmagic/form';
|
|
@@ -238,6 +239,8 @@ export interface UiState {
|
|
|
238
239
|
showAddPageButton: boolean;
|
|
239
240
|
/** 是否隐藏侧边栏 */
|
|
240
241
|
hideSlideBar: boolean;
|
|
242
|
+
/** 侧边栏面板配置 */
|
|
243
|
+
sideBarItems: SideComponent[];
|
|
241
244
|
|
|
242
245
|
// navMenu 的宽高
|
|
243
246
|
navMenuRect: {
|
|
@@ -370,8 +373,10 @@ export interface MenuBarData {
|
|
|
370
373
|
export interface SideComponent extends MenuComponent {
|
|
371
374
|
/** 显示文案 */
|
|
372
375
|
text: string;
|
|
376
|
+
/** tab样式 */
|
|
377
|
+
tabStyle?: string | Record<string, any>;
|
|
373
378
|
/** vue组件或url */
|
|
374
|
-
icon
|
|
379
|
+
icon?: any;
|
|
375
380
|
/** slide 唯一标识 key */
|
|
376
381
|
$key: string;
|
|
377
382
|
|
|
@@ -384,12 +389,19 @@ export interface SideComponent extends MenuComponent {
|
|
|
384
389
|
};
|
|
385
390
|
}
|
|
386
391
|
|
|
392
|
+
export enum SideItemKey {
|
|
393
|
+
COMPONENT_LIST = 'component-list',
|
|
394
|
+
LAYER = 'layer',
|
|
395
|
+
CODE_BLOCK = 'code-block',
|
|
396
|
+
DATA_SOURCE = 'data-source',
|
|
397
|
+
}
|
|
398
|
+
|
|
387
399
|
/**
|
|
388
400
|
* component-list: 组件列表
|
|
389
401
|
* layer: 已选组件树
|
|
390
402
|
* code-block: 代码块
|
|
391
403
|
*/
|
|
392
|
-
export type SideItem =
|
|
404
|
+
export type SideItem = `${SideItemKey}` | SideComponent;
|
|
393
405
|
|
|
394
406
|
/** 工具栏 */
|
|
395
407
|
export interface SideBarData {
|
|
@@ -621,6 +633,8 @@ export interface DataSourceSelect extends FormItem, Input {
|
|
|
621
633
|
* value: 要编译(数据源data)
|
|
622
634
|
* */
|
|
623
635
|
value?: 'id' | 'value';
|
|
636
|
+
/** 是否可以编辑数据源,disable表示的是是否可以选择数据源 */
|
|
637
|
+
notEditable?: boolean | FilterFunction;
|
|
624
638
|
}
|
|
625
639
|
|
|
626
640
|
export interface DataSourceMethodSelectConfig extends FormItem {
|
|
@@ -640,6 +654,8 @@ export interface DataSourceFieldSelectConfig extends FormItem {
|
|
|
640
654
|
checkStrictly?: boolean;
|
|
641
655
|
dataSourceFieldType?: DataSourceFieldType[];
|
|
642
656
|
fieldConfig?: ChildConfig;
|
|
657
|
+
/** 是否可以编辑数据源,disable表示的是是否可以选择数据源 */
|
|
658
|
+
notEditable?: boolean | FilterFunction;
|
|
643
659
|
}
|
|
644
660
|
|
|
645
661
|
/** 可新增的数据源类型选项 */
|
|
@@ -714,3 +730,16 @@ export type SyncHookPlugin<
|
|
|
714
730
|
C extends Record<T[number], (...args: any) => any>,
|
|
715
731
|
> = AddPrefixToObject<PascalCasedProperties<SyncBeforeHook<T, C>>, 'before'> &
|
|
716
732
|
AddPrefixToObject<PascalCasedProperties<SyncAfterHook<T, C>>, 'after'>;
|
|
733
|
+
|
|
734
|
+
export interface EventBusEvent {
|
|
735
|
+
'edit-data-source': [id: string];
|
|
736
|
+
'edit-code': [id: string];
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
export interface EventBus extends EventEmitter {
|
|
740
|
+
on<Name extends keyof EventBusEvent, Param extends EventBusEvent[Name]>(
|
|
741
|
+
eventName: Name,
|
|
742
|
+
listener: (...args: Param) => void,
|
|
743
|
+
): this;
|
|
744
|
+
emit<Name extends keyof EventBusEvent, Param extends EventBusEvent[Name]>(eventName: Name, ...args: Param): boolean;
|
|
745
|
+
}
|
|
@@ -2,7 +2,7 @@ import { computed, markRaw, Ref } from 'vue';
|
|
|
2
2
|
import { CopyDocument, Delete, DocumentCopy } from '@element-plus/icons-vue';
|
|
3
3
|
|
|
4
4
|
import { Id, MContainer, NodeType } from '@tmagic/schema';
|
|
5
|
-
import { isPage, isPageFragment } from '@tmagic/utils';
|
|
5
|
+
import { calcValueByFontsize, isPage, isPageFragment } from '@tmagic/utils';
|
|
6
6
|
|
|
7
7
|
import ContentMenu from '@editor/components/ContentMenu.vue';
|
|
8
8
|
import type { MenuButton, Services } from '@editor/type';
|
|
@@ -46,8 +46,12 @@ export const usePasteMenu = (menu?: Ref<InstanceType<typeof ContentMenu> | undef
|
|
|
46
46
|
const stage = services?.editorService?.get('stage');
|
|
47
47
|
const rect = menu.value.$el.getBoundingClientRect();
|
|
48
48
|
const parentRect = stage?.container?.getBoundingClientRect();
|
|
49
|
-
const initialLeft =
|
|
50
|
-
|
|
49
|
+
const initialLeft =
|
|
50
|
+
calcValueByFontsize(stage?.renderer.getDocument(), (rect.left || 0) - (parentRect?.left || 0)) /
|
|
51
|
+
services.uiService.get('zoom');
|
|
52
|
+
const initialTop =
|
|
53
|
+
calcValueByFontsize(stage?.renderer.getDocument(), (rect.top || 0) - (parentRect?.top || 0)) /
|
|
54
|
+
services.uiService.get('zoom');
|
|
51
55
|
services?.editorService?.paste({ left: initialLeft, top: initialTop });
|
|
52
56
|
} else {
|
|
53
57
|
services?.editorService?.paste();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { FormConfig, FormState } from '@tmagic/form';
|
|
2
|
-
import { DataSchema, DataSourceSchema } from '@tmagic/schema';
|
|
1
|
+
import { CascaderOption, FormConfig, FormState } from '@tmagic/form';
|
|
2
|
+
import { DataSchema, DataSourceFieldType, DataSourceSchema } from '@tmagic/schema';
|
|
3
3
|
|
|
4
4
|
import BaseFormConfig from './formConfigs/base';
|
|
5
5
|
import HttpFormConfig from './formConfigs/http';
|
|
@@ -32,7 +32,6 @@ const fillConfig = (config: FormConfig): FormConfig => [
|
|
|
32
32
|
},
|
|
33
33
|
{
|
|
34
34
|
title: '事件配置',
|
|
35
|
-
display: false,
|
|
36
35
|
items: [
|
|
37
36
|
{
|
|
38
37
|
name: 'events',
|
|
@@ -198,3 +197,40 @@ export const getDisplayField = (dataSources: DataSourceSchema[], key: string) =>
|
|
|
198
197
|
|
|
199
198
|
return displayState;
|
|
200
199
|
};
|
|
200
|
+
|
|
201
|
+
export const getCascaderOptionsFromFields = (
|
|
202
|
+
fields: DataSchema[] = [],
|
|
203
|
+
dataSourceFieldType: DataSourceFieldType[] = ['any'],
|
|
204
|
+
): CascaderOption[] => {
|
|
205
|
+
const child: CascaderOption[] = [];
|
|
206
|
+
fields.forEach((field) => {
|
|
207
|
+
if (!dataSourceFieldType.length) {
|
|
208
|
+
dataSourceFieldType.push('any');
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const children = getCascaderOptionsFromFields(field.fields, dataSourceFieldType);
|
|
212
|
+
|
|
213
|
+
const item = {
|
|
214
|
+
label: field.title || field.name,
|
|
215
|
+
value: field.name,
|
|
216
|
+
children,
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
const fieldType = field.type || 'any';
|
|
220
|
+
if (dataSourceFieldType.includes('any') || dataSourceFieldType.includes(fieldType)) {
|
|
221
|
+
child.push(item);
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (!dataSourceFieldType.includes(fieldType) && !['array', 'object', 'any'].includes(fieldType)) {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (!children.length && ['object', 'array', 'any'].includes(field.type || '')) {
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
child.push(item);
|
|
234
|
+
});
|
|
235
|
+
return child;
|
|
236
|
+
};
|
package/src/utils/editor.ts
CHANGED
|
@@ -21,7 +21,7 @@ import serialize from 'serialize-javascript';
|
|
|
21
21
|
import type { Id, MApp, MContainer, MNode, MPage, MPageFragment } from '@tmagic/schema';
|
|
22
22
|
import { NodeType } from '@tmagic/schema';
|
|
23
23
|
import type StageCore from '@tmagic/stage';
|
|
24
|
-
import { getNodePath, isNumber, isPage, isPageFragment, isPop } from '@tmagic/utils';
|
|
24
|
+
import { calcValueByFontsize, getNodePath, isNumber, isPage, isPageFragment, isPop } from '@tmagic/utils';
|
|
25
25
|
|
|
26
26
|
import { Layout } from '@editor/type';
|
|
27
27
|
export const COPY_STORAGE_KEY = '$MagicEditorCopyData';
|
|
@@ -106,13 +106,16 @@ const getMiddleTop = (node: MNode, parentNode: MNode, stage: StageCore | null) =
|
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
const { height: parentHeight } = parentNode.style;
|
|
109
|
-
|
|
109
|
+
// wrapperHeight 是未 calcValue的高度, 所以要将其calcValueByFontsize一下, 否则在pad or pc端计算的结果有误
|
|
110
|
+
const { scrollTop = 0, wrapperHeight } = stage.mask;
|
|
111
|
+
const wrapperHeightDeal = calcValueByFontsize(stage.renderer.getDocument()!, wrapperHeight);
|
|
112
|
+
const scrollTopDeal = calcValueByFontsize(stage.renderer.getDocument()!, scrollTop);
|
|
110
113
|
if (isPage(parentNode)) {
|
|
111
|
-
|
|
112
|
-
return (wrapperHeight - height) / 2 + scrollTop;
|
|
114
|
+
return (wrapperHeightDeal - height) / 2 + scrollTopDeal;
|
|
113
115
|
}
|
|
114
116
|
|
|
115
|
-
|
|
117
|
+
// 如果容器的元素高度大于当前视口高度的2倍, 添加的元素居中位置也会看不见, 所以要取最小值计算
|
|
118
|
+
return (Math.min(parentHeight, wrapperHeightDeal) - height) / 2;
|
|
116
119
|
};
|
|
117
120
|
|
|
118
121
|
export const getInitPositionStyle = (style: Record<string, any> = {}, layout: Layout) => {
|
|
@@ -238,8 +241,12 @@ export const fixNodeLeft = (config: MNode, parent: MContainer, doc?: Document) =
|
|
|
238
241
|
const parentEl = doc.getElementById(`${parent.id}`);
|
|
239
242
|
|
|
240
243
|
const left = Number(config.style?.left) || 0;
|
|
241
|
-
if (el && parentEl
|
|
242
|
-
|
|
244
|
+
if (el && parentEl) {
|
|
245
|
+
const calcParentOffsetWidth = calcValueByFontsize(doc, parentEl.offsetWidth);
|
|
246
|
+
const calcElOffsetWidth = calcValueByFontsize(doc, el.offsetWidth);
|
|
247
|
+
if (calcElOffsetWidth + left > calcParentOffsetWidth) {
|
|
248
|
+
return calcParentOffsetWidth - calcElOffsetWidth;
|
|
249
|
+
}
|
|
243
250
|
}
|
|
244
251
|
|
|
245
252
|
return config.style.left;
|
|
@@ -1,46 +1,33 @@
|
|
|
1
1
|
import type { CodeBlockContent } from '@tmagic/schema';
|
|
2
|
-
declare
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
type: import("vue").PropType<boolean>;
|
|
14
|
-
};
|
|
15
|
-
dataSourceType: {
|
|
16
|
-
type: import("vue").PropType<string>;
|
|
17
|
-
};
|
|
18
|
-
}, {
|
|
2
|
+
declare let __VLS_typeProps: {
|
|
3
|
+
content: CodeBlockContent;
|
|
4
|
+
disabled?: boolean;
|
|
5
|
+
isDataSource?: boolean;
|
|
6
|
+
dataSourceType?: string;
|
|
7
|
+
};
|
|
8
|
+
type __VLS_PublicProps = {
|
|
9
|
+
'width'?: number;
|
|
10
|
+
'visible'?: boolean;
|
|
11
|
+
} & typeof __VLS_typeProps;
|
|
12
|
+
declare const _default: import("vue").DefineComponent<__VLS_TypePropsToOption<__VLS_PublicProps>, {
|
|
19
13
|
show(): Promise<void>;
|
|
20
14
|
hide(): Promise<void>;
|
|
21
15
|
}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
22
16
|
"update:width": (width: number) => void;
|
|
23
17
|
"update:visible": (visible: boolean) => void;
|
|
24
18
|
submit: (values: CodeBlockContent) => void;
|
|
25
|
-
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
26
|
-
width: import("vue").PropType<number>;
|
|
27
|
-
visible: import("vue").PropType<boolean>;
|
|
28
|
-
content: {
|
|
29
|
-
type: import("vue").PropType<CodeBlockContent>;
|
|
30
|
-
required: true;
|
|
31
|
-
};
|
|
32
|
-
disabled: {
|
|
33
|
-
type: import("vue").PropType<boolean>;
|
|
34
|
-
};
|
|
35
|
-
isDataSource: {
|
|
36
|
-
type: import("vue").PropType<boolean>;
|
|
37
|
-
};
|
|
38
|
-
dataSourceType: {
|
|
39
|
-
type: import("vue").PropType<string>;
|
|
40
|
-
};
|
|
41
|
-
}>> & {
|
|
19
|
+
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<__VLS_TypePropsToOption<__VLS_PublicProps>>> & {
|
|
42
20
|
onSubmit?: ((values: CodeBlockContent) => any) | undefined;
|
|
43
21
|
"onUpdate:width"?: ((width: number) => any) | undefined;
|
|
44
22
|
"onUpdate:visible"?: ((visible: boolean) => any) | undefined;
|
|
45
23
|
}, {}, {}>;
|
|
46
24
|
export default _default;
|
|
25
|
+
type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
|
|
26
|
+
type __VLS_TypePropsToOption<T> = {
|
|
27
|
+
[K in keyof T]-?: {} extends Pick<T, K> ? {
|
|
28
|
+
type: import('vue').PropType<__VLS_NonUndefinedable<T[K]>>;
|
|
29
|
+
} : {
|
|
30
|
+
type: import('vue').PropType<T[K]>;
|
|
31
|
+
required: true;
|
|
32
|
+
};
|
|
33
|
+
};
|