@tmagic/editor 1.8.0-beta.11 → 1.8.0-beta.13
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/es/Editor.vue_vue_type_script_setup_true_lang.js +7 -4
- package/dist/es/components/CodeBlockEditor.vue_vue_type_script_setup_true_lang.js +5 -1
- package/dist/es/components/CodeParams.vue_vue_type_script_setup_true_lang.js +2 -1
- package/dist/es/components/CompareForm.vue_vue_type_script_setup_true_lang.js +18 -123
- package/dist/es/components/FloatingBox.vue_vue_type_script_setup_true_lang.js +60 -14
- package/dist/es/components/ScrollBar.js +0 -1
- package/dist/es/components/ViewForm.js +5 -0
- package/dist/es/components/ViewForm.vue_vue_type_script_setup_true_lang.js +58 -0
- package/dist/es/editorProps.js +6 -1
- package/dist/es/fields/CodeSelect.vue_vue_type_script_setup_true_lang.js +15 -3
- package/dist/es/fields/CondOpSelect.vue_vue_type_script_setup_true_lang.js +2 -17
- package/dist/es/fields/DataSourceFieldSelect/FieldSelect.vue_vue_type_script_setup_true_lang.js +2 -1
- package/dist/es/fields/DataSourceFields.vue_vue_type_script_setup_true_lang.js +7 -0
- package/dist/es/fields/DataSourceInput.vue_vue_type_script_setup_true_lang.js +5 -17
- package/dist/es/fields/DataSourceMocks.vue_vue_type_script_setup_true_lang.js +4 -0
- package/dist/es/fields/DisplayConds.vue_vue_type_script_setup_true_lang.js +29 -3
- package/dist/es/fields/EventSelect.vue_vue_type_script_setup_true_lang.js +50 -88
- package/dist/es/fields/StyleSetter/Index.vue_vue_type_script_setup_true_lang.js +2 -5
- package/dist/es/fields/StyleSetter/pro/Background.vue_vue_type_script_setup_true_lang.js +48 -23
- package/dist/es/fields/StyleSetter/pro/Border.vue_vue_type_script_setup_true_lang.js +6 -3
- package/dist/es/fields/StyleSetter/pro/Font.vue_vue_type_script_setup_true_lang.js +28 -22
- package/dist/es/fields/StyleSetter/pro/Layout.vue_vue_type_script_setup_true_lang.js +28 -22
- package/dist/es/fields/StyleSetter/pro/Position.vue_vue_type_script_setup_true_lang.js +28 -22
- package/dist/es/fields/StyleSetter/pro/Transform.vue_vue_type_script_setup_true_lang.js +6 -3
- package/dist/es/fields/UISelect.js +0 -1
- package/dist/es/hooks/use-compare-form.js +119 -0
- package/dist/es/index.js +13 -8
- package/dist/es/layouts/CodeEditor.vue_vue_type_script_setup_true_lang.js +21 -6
- package/dist/es/layouts/Framework.vue_vue_type_script_setup_true_lang.js +9 -6
- package/dist/es/layouts/history-list/HistoryDiffDialog.vue_vue_type_script_setup_true_lang.js +4 -1
- package/dist/es/layouts/history-list/composables.js +1 -1
- package/dist/es/layouts/history-list/useHistoryRevert.js +7 -3
- package/dist/es/layouts/props-panel/FormPanel.vue_vue_type_script_setup_true_lang.js +44 -5
- package/dist/es/layouts/props-panel/PropsPanel.vue_vue_type_script_setup_true_lang.js +15 -8
- package/dist/es/layouts/props-panel/use-style-panel.js +3 -2
- package/dist/es/layouts/sidebar/Sidebar.vue_vue_type_script_setup_true_lang.js +15 -31
- package/dist/es/layouts/sidebar/code-block/CodeBlockListPanel.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/es/layouts/sidebar/code-block/useContentMenu.js +18 -3
- package/dist/es/layouts/sidebar/data-source/DataSourceConfigPanel.vue_vue_type_script_setup_true_lang.js +4 -0
- package/dist/es/layouts/sidebar/data-source/DataSourceListPanel.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/es/layouts/sidebar/data-source/useContentMenu.js +18 -3
- package/dist/es/layouts/sidebar/layer/LayerNodeContent.js +5 -0
- package/dist/es/layouts/sidebar/layer/LayerNodeContent.vue_vue_type_script_setup_true_lang.js +46 -0
- package/dist/es/layouts/sidebar/layer/LayerPanel.vue_vue_type_script_setup_true_lang.js +2 -1
- package/dist/es/layouts/workspace/viewer/NodeListMenu.vue_vue_type_script_setup_true_lang.js +8 -2
- package/dist/es/plugin.js +3 -1
- package/dist/es/services/codeBlock.js +1 -1
- package/dist/es/services/editor.js +104 -5
- package/dist/es/services/history.js +1 -1
- package/dist/es/services/props.js +3 -2
- package/dist/es/services/storage.js +2 -2
- package/dist/es/services/ui.js +3 -0
- package/dist/es/style.css +104 -55
- package/dist/es/utils/data-source/index.js +30 -11
- package/dist/es/utils/event.js +123 -0
- package/dist/es/utils/monaco-editor.js +22 -6
- package/dist/es/utils/props.js +119 -8
- package/dist/es/utils/type-match-rules.js +360 -0
- package/dist/style.css +104 -55
- package/dist/tmagic-editor.umd.cjs +16996 -15806
- package/package.json +8 -8
- package/src/Editor.vue +3 -1
- package/src/components/CodeBlockEditor.vue +3 -0
- package/src/components/CompareForm.vue +16 -196
- package/src/components/FloatingBox.vue +77 -8
- package/src/components/ScrollBar.vue +0 -67
- package/src/components/ViewForm.vue +55 -0
- package/src/editorProps.ts +13 -0
- package/src/fields/CodeSelect.vue +4 -1
- package/src/fields/CondOpSelect.vue +2 -24
- package/src/fields/DataSourceFields.vue +5 -0
- package/src/fields/DataSourceInput.vue +7 -25
- package/src/fields/DataSourceMocks.vue +3 -0
- package/src/fields/DisplayConds.vue +14 -0
- package/src/fields/EventSelect.vue +84 -129
- package/src/fields/StyleSetter/Index.vue +2 -8
- package/src/fields/StyleSetter/pro/Background.vue +94 -55
- package/src/fields/StyleSetter/pro/Border.vue +9 -11
- package/src/fields/StyleSetter/pro/Font.vue +66 -64
- package/src/fields/StyleSetter/pro/Layout.vue +140 -138
- package/src/fields/StyleSetter/pro/Position.vue +69 -67
- package/src/fields/StyleSetter/pro/Transform.vue +23 -25
- package/src/fields/UISelect.vue +0 -12
- package/src/hooks/index.ts +1 -0
- package/src/hooks/use-compare-form.ts +187 -0
- package/src/index.ts +2 -0
- package/src/layouts/CodeEditor.vue +32 -6
- package/src/layouts/Framework.vue +7 -6
- package/src/layouts/history-list/HistoryDiffDialog.vue +11 -1
- package/src/layouts/history-list/useHistoryRevert.ts +4 -0
- package/src/layouts/props-panel/FormPanel.vue +66 -5
- package/src/layouts/props-panel/PropsPanel.vue +20 -6
- package/src/layouts/props-panel/use-style-panel.ts +4 -3
- package/src/layouts/sidebar/Sidebar.vue +2 -0
- package/src/layouts/sidebar/code-block/CodeBlockListPanel.vue +4 -1
- package/src/layouts/sidebar/code-block/useContentMenu.ts +13 -1
- package/src/layouts/sidebar/data-source/DataSourceConfigPanel.vue +3 -0
- package/src/layouts/sidebar/data-source/DataSourceListPanel.vue +2 -2
- package/src/layouts/sidebar/data-source/useContentMenu.ts +13 -1
- package/src/layouts/sidebar/layer/LayerNodeContent.vue +57 -0
- package/src/layouts/sidebar/layer/LayerPanel.vue +4 -1
- package/src/layouts/workspace/viewer/NodeListMenu.vue +4 -1
- package/src/plugin.ts +3 -1
- package/src/services/editor.ts +168 -3
- package/src/services/ui.ts +6 -0
- package/src/theme/event.scss +8 -0
- package/src/theme/floating-box.scss +9 -1
- package/src/theme/layer-node-content.scss +14 -0
- package/src/theme/scroll-bar.scss +64 -0
- package/src/theme/theme.scss +3 -0
- package/src/theme/ui-select.scss +9 -0
- package/src/type.ts +105 -2
- package/src/utils/data-source/index.ts +30 -12
- package/src/utils/event.ts +224 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/monaco-editor.ts +27 -0
- package/src/utils/props.ts +189 -2
- package/src/utils/type-match-rules.ts +678 -0
- package/types/index.d.ts +558 -213
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
:values="values"
|
|
10
10
|
:disabledShowSrc="disabledShowSrc"
|
|
11
11
|
:extendState="extendState"
|
|
12
|
-
@submit="submit"
|
|
12
|
+
@submit="(v, eventData, error) => submit(v, eventData, error, 'props')"
|
|
13
13
|
@submit-error="errorHandler"
|
|
14
14
|
@form-error="errorHandler"
|
|
15
15
|
@mounted="mountedHandler"
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
:values="values"
|
|
28
28
|
:disabledShowSrc="disabledShowSrc"
|
|
29
29
|
:extendState="extendState"
|
|
30
|
-
@submit="submit"
|
|
30
|
+
@submit="(v, eventData, error) => submit(v, eventData, error, 'style')"
|
|
31
31
|
@submit-error="errorHandler"
|
|
32
32
|
@form-error="errorHandler"
|
|
33
33
|
>
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
</template>
|
|
56
56
|
|
|
57
57
|
<script lang="ts" setup>
|
|
58
|
-
import { computed, onBeforeUnmount, onMounted, ref, useTemplateRef, watch, watchEffect } from 'vue';
|
|
58
|
+
import { computed, inject, onBeforeUnmount, onMounted, ref, useTemplateRef, watch, watchEffect } from 'vue';
|
|
59
59
|
import { Close, Sugar } from '@element-plus/icons-vue';
|
|
60
60
|
import type { OnDrag } from 'gesto';
|
|
61
61
|
|
|
@@ -66,9 +66,10 @@ import { setValueByKeyPath } from '@tmagic/utils';
|
|
|
66
66
|
|
|
67
67
|
import MIcon from '@editor/components/Icon.vue';
|
|
68
68
|
import Resizer from '@editor/components/Resizer.vue';
|
|
69
|
+
import { ENABLE_PROPS_FORM_VALIDATE } from '@editor/editorProps';
|
|
69
70
|
import { useServices } from '@editor/hooks/use-services';
|
|
70
71
|
import { Protocol } from '@editor/services/storage';
|
|
71
|
-
import type { PropsPanelSlots } from '@editor/type';
|
|
72
|
+
import type { NodeInvalidSource, PropsPanelSlots } from '@editor/type';
|
|
72
73
|
import { styleTabConfig } from '@editor/utils';
|
|
73
74
|
import { PROPS_PANEL_WIDTH_STORAGE_KEY } from '@editor/utils/const';
|
|
74
75
|
|
|
@@ -95,6 +96,8 @@ const emit = defineEmits<{
|
|
|
95
96
|
|
|
96
97
|
const { editorService, uiService, propsService, storageService } = useServices();
|
|
97
98
|
|
|
99
|
+
const enablePropsFormValidate = inject(ENABLE_PROPS_FORM_VALIDATE, false);
|
|
100
|
+
|
|
98
101
|
const values = ref<FormValue>({});
|
|
99
102
|
// ts类型应该是FormConfig, 但是打包时会出错,所以暂时用any
|
|
100
103
|
const curFormConfig = ref<any>([]);
|
|
@@ -126,7 +129,12 @@ onBeforeUnmount(() => {
|
|
|
126
129
|
propsService.off('props-configs-change', init);
|
|
127
130
|
});
|
|
128
131
|
|
|
129
|
-
const submit = async (
|
|
132
|
+
const submit = async (
|
|
133
|
+
v: MNode,
|
|
134
|
+
eventData?: ContainerChangeEventData,
|
|
135
|
+
error?: any,
|
|
136
|
+
source: NodeInvalidSource = 'props',
|
|
137
|
+
) => {
|
|
130
138
|
try {
|
|
131
139
|
if (!v.id) {
|
|
132
140
|
v.id = values.value.id;
|
|
@@ -155,7 +163,13 @@ const submit = async (v: MNode, eventData?: ContainerChangeEventData) => {
|
|
|
155
163
|
// 源码编辑器(CodeEditor @save → saveCode)保存时不带 eventData,据此标记为「源码编辑器」。
|
|
156
164
|
const historySource = eventData ? 'props' : 'code';
|
|
157
165
|
|
|
158
|
-
editorService.update(newValue, {
|
|
166
|
+
editorService.update(newValue, {
|
|
167
|
+
changeRecords: eventData?.changeRecords,
|
|
168
|
+
historySource,
|
|
169
|
+
// 启用校验联动时,仅校验失败(error 存在)才把错误信息随更新传入 editorService 记录;
|
|
170
|
+
// 其余情况(含表单校验成功、CodeEditor 源码保存)不携带 invalidInfo,由 editorService 在执行 update 时统一清除该节点错误。
|
|
171
|
+
...(enablePropsFormValidate && error ? { invalidInfo: { id: newValue.id, source, error: error?.message } } : {}),
|
|
172
|
+
});
|
|
159
173
|
} catch (e: any) {
|
|
160
174
|
emit('submit-error', e);
|
|
161
175
|
}
|
|
@@ -2,7 +2,7 @@ import { computed, type Ref, watch } from 'vue';
|
|
|
2
2
|
|
|
3
3
|
import { Protocol } from '@editor/services/storage';
|
|
4
4
|
import { Services } from '@editor/type';
|
|
5
|
-
import {
|
|
5
|
+
import { RIGHT_COLUMN_WIDTH_STORAGE_KEY } from '@editor/utils/const';
|
|
6
6
|
|
|
7
7
|
export const useStylePanel = (
|
|
8
8
|
{ uiService, storageService }: Pick<Services, 'uiService' | 'storageService'>,
|
|
@@ -47,8 +47,9 @@ export const useStylePanel = (
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
if (columnWidth.center < 0) {
|
|
50
|
-
|
|
51
|
-
columnWidth.
|
|
50
|
+
const minCenterColumnWidth = uiService.get('minCenterColumnWidth');
|
|
51
|
+
columnWidth.right = columnWidth.right + columnWidth.center - minCenterColumnWidth;
|
|
52
|
+
columnWidth.center = minCenterColumnWidth;
|
|
52
53
|
|
|
53
54
|
propsPanelWidth.value = columnWidth.right / 2;
|
|
54
55
|
}
|
|
@@ -132,6 +132,7 @@
|
|
|
132
132
|
v-model:height="columnLeftHeight"
|
|
133
133
|
:width="columnLeftWidth"
|
|
134
134
|
:title="config.text"
|
|
135
|
+
:framework-width="frameworkWidth"
|
|
135
136
|
:position="{
|
|
136
137
|
left: floatBoxStates[config.$key].left,
|
|
137
138
|
top: floatBoxStates[config.$key].top,
|
|
@@ -221,6 +222,7 @@ const taskLength = computed(() => depService.get('taskLength'));
|
|
|
221
222
|
const tipsBarVisible = ref(true);
|
|
222
223
|
|
|
223
224
|
const columnLeftWidth = computed(() => uiService.get('columnWidth')[ColumnLayout.LEFT]);
|
|
225
|
+
const frameworkWidth = computed(() => uiService.get('frameworkRect')?.width || 0);
|
|
224
226
|
const { height: editorContentHeight } = useEditorContentHeight();
|
|
225
227
|
const columnLeftHeight = ref(0);
|
|
226
228
|
|
|
@@ -121,8 +121,11 @@ const {
|
|
|
121
121
|
nodeContentMenuHandler,
|
|
122
122
|
menuData: contentMenuData,
|
|
123
123
|
contentMenuHideHandler,
|
|
124
|
+
getTarget,
|
|
124
125
|
} = useContentMenu((id: string) => {
|
|
125
126
|
codeBlockListRef.value?.deleteCode(id, { historySource: 'tree-contextmenu' });
|
|
126
127
|
});
|
|
127
|
-
const menuData = computed<(MenuButton | MenuComponent)[]>(() =>
|
|
128
|
+
const menuData = computed<(MenuButton | MenuComponent)[]>(() =>
|
|
129
|
+
props.customContentMenu(contentMenuData, 'code-block', getTarget),
|
|
130
|
+
);
|
|
128
131
|
</script>
|
|
@@ -3,13 +3,21 @@ import { CopyDocument, Delete, Edit } from '@element-plus/icons-vue';
|
|
|
3
3
|
import { cloneDeep } from 'lodash-es';
|
|
4
4
|
|
|
5
5
|
import ContentMenu from '@editor/components/ContentMenu.vue';
|
|
6
|
-
import type { EventBus, MenuButton, MenuComponent, TreeNodeData } from '@editor/type';
|
|
6
|
+
import type { ContentMenuTarget, EventBus, MenuButton, MenuComponent, TreeNodeData } from '@editor/type';
|
|
7
7
|
|
|
8
8
|
export const useContentMenu = (deleteCode: (id: string) => void) => {
|
|
9
9
|
const eventBus = inject<EventBus>('eventBus');
|
|
10
10
|
const menuRef = useTemplateRef<InstanceType<typeof ContentMenu>>('menu');
|
|
11
11
|
|
|
12
12
|
let selectId = '';
|
|
13
|
+
let selectData: TreeNodeData | null = null;
|
|
14
|
+
|
|
15
|
+
const getTarget = (): ContentMenuTarget | null => {
|
|
16
|
+
if (!selectId) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
return { id: selectId, data: selectData ?? undefined };
|
|
20
|
+
};
|
|
13
21
|
|
|
14
22
|
const menuData: (MenuButton | MenuComponent)[] = [
|
|
15
23
|
{
|
|
@@ -65,19 +73,23 @@ export const useContentMenu = (deleteCode: (id: string) => void) => {
|
|
|
65
73
|
menuRef.value?.show(event);
|
|
66
74
|
if (data.id) {
|
|
67
75
|
selectId = `${data.id}`;
|
|
76
|
+
selectData = data;
|
|
68
77
|
} else {
|
|
69
78
|
selectId = '';
|
|
79
|
+
selectData = null;
|
|
70
80
|
}
|
|
71
81
|
}
|
|
72
82
|
};
|
|
73
83
|
|
|
74
84
|
const contentMenuHideHandler = () => {
|
|
75
85
|
selectId = '';
|
|
86
|
+
selectData = null;
|
|
76
87
|
};
|
|
77
88
|
|
|
78
89
|
return {
|
|
79
90
|
menuData,
|
|
80
91
|
nodeContentMenuHandler,
|
|
81
92
|
contentMenuHideHandler,
|
|
93
|
+
getTarget,
|
|
82
94
|
};
|
|
83
95
|
};
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<FloatingBox
|
|
3
|
+
:body-style="{ padding: '0 16px' }"
|
|
3
4
|
v-model:visible="boxVisible"
|
|
4
5
|
v-model:width="width"
|
|
5
6
|
v-model:height="editorHeight"
|
|
6
7
|
:title="title"
|
|
8
|
+
:framework-width="frameworkWidth"
|
|
7
9
|
:position="boxPosition"
|
|
8
10
|
>
|
|
9
11
|
<template #body>
|
|
@@ -65,6 +67,7 @@ const { height: editorHeight } = useEditorContentHeight();
|
|
|
65
67
|
|
|
66
68
|
const parentFloating = inject<Ref<HTMLDivElement | null>>('parentFloating', ref(null));
|
|
67
69
|
const { boxPosition, calcBoxPosition } = useNextFloatBoxPosition(uiService, parentFloating);
|
|
70
|
+
const frameworkWidth = computed(() => uiService.get('frameworkRect')?.width || 0);
|
|
68
71
|
|
|
69
72
|
/** 供「方法定义」tab 内的字段消费,用于打开数据源详情后自动打开指定方法 */
|
|
70
73
|
provide(
|
|
@@ -171,8 +171,8 @@ eventBus?.on('remove-data-source', (id: string) => {
|
|
|
171
171
|
removeHandler(id);
|
|
172
172
|
});
|
|
173
173
|
|
|
174
|
-
const { nodeContentMenuHandler, menuData: contentMenuData, contentMenuHideHandler } = useContentMenu();
|
|
174
|
+
const { nodeContentMenuHandler, menuData: contentMenuData, contentMenuHideHandler, getTarget } = useContentMenu();
|
|
175
175
|
const menuData = computed<(MenuButton | MenuComponent)[]>(() =>
|
|
176
|
-
props.customContentMenu(contentMenuData, 'data-source'),
|
|
176
|
+
props.customContentMenu(contentMenuData, 'data-source', getTarget),
|
|
177
177
|
);
|
|
178
178
|
</script>
|
|
@@ -3,13 +3,21 @@ import { CopyDocument, Delete, Edit } from '@element-plus/icons-vue';
|
|
|
3
3
|
import { cloneDeep } from 'lodash-es';
|
|
4
4
|
|
|
5
5
|
import ContentMenu from '@editor/components/ContentMenu.vue';
|
|
6
|
-
import type { EventBus, MenuButton, MenuComponent, TreeNodeData } from '@editor/type';
|
|
6
|
+
import type { ContentMenuTarget, EventBus, MenuButton, MenuComponent, TreeNodeData } from '@editor/type';
|
|
7
7
|
|
|
8
8
|
export const useContentMenu = () => {
|
|
9
9
|
const eventBus = inject<EventBus>('eventBus');
|
|
10
10
|
const menuRef = useTemplateRef<InstanceType<typeof ContentMenu>>('menu');
|
|
11
11
|
|
|
12
12
|
let selectId = '';
|
|
13
|
+
let selectData: TreeNodeData | null = null;
|
|
14
|
+
|
|
15
|
+
const getTarget = (): ContentMenuTarget | null => {
|
|
16
|
+
if (!selectId) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
return { id: selectId, data: selectData ?? undefined };
|
|
20
|
+
};
|
|
13
21
|
|
|
14
22
|
const menuData: (MenuButton | MenuComponent)[] = [
|
|
15
23
|
{
|
|
@@ -63,19 +71,23 @@ export const useContentMenu = () => {
|
|
|
63
71
|
menuRef.value?.show(event);
|
|
64
72
|
if (data.id) {
|
|
65
73
|
selectId = `${data.id}`;
|
|
74
|
+
selectData = data;
|
|
66
75
|
} else {
|
|
67
76
|
selectId = '';
|
|
77
|
+
selectData = null;
|
|
68
78
|
}
|
|
69
79
|
}
|
|
70
80
|
};
|
|
71
81
|
|
|
72
82
|
const contentMenuHideHandler = () => {
|
|
73
83
|
selectId = '';
|
|
84
|
+
selectData = null;
|
|
74
85
|
};
|
|
75
86
|
|
|
76
87
|
return {
|
|
77
88
|
menuData,
|
|
78
89
|
nodeContentMenuHandler,
|
|
79
90
|
contentMenuHideHandler,
|
|
91
|
+
getTarget,
|
|
80
92
|
};
|
|
81
93
|
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<span class="m-editor-layer-node-content" :class="{ 'is-invalid': hasError }">
|
|
3
|
+
<span class="m-editor-layer-node-label">{{ label }}</span>
|
|
4
|
+
<TMagicTooltip v-if="hasError" placement="top">
|
|
5
|
+
<template #content>
|
|
6
|
+
<span v-html="errorMessage"></span>
|
|
7
|
+
</template>
|
|
8
|
+
<MIcon class="m-editor-layer-node-error-icon" :icon="WarningFilled"></MIcon>
|
|
9
|
+
</TMagicTooltip>
|
|
10
|
+
</span>
|
|
11
|
+
</template>
|
|
12
|
+
|
|
13
|
+
<script setup lang="ts">
|
|
14
|
+
import { computed } from 'vue';
|
|
15
|
+
import { WarningFilled } from '@element-plus/icons-vue';
|
|
16
|
+
|
|
17
|
+
import { stripValidateSuggestion, TMagicTooltip } from '@tmagic/design';
|
|
18
|
+
|
|
19
|
+
import MIcon from '@editor/components/Icon.vue';
|
|
20
|
+
import { useServices } from '@editor/hooks/use-services';
|
|
21
|
+
import type { TreeNodeData } from '@editor/type';
|
|
22
|
+
|
|
23
|
+
defineOptions({
|
|
24
|
+
name: 'MEditorLayerNodeContent',
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const props = defineProps<{
|
|
28
|
+
data: TreeNodeData;
|
|
29
|
+
}>();
|
|
30
|
+
|
|
31
|
+
const { editorService } = useServices();
|
|
32
|
+
|
|
33
|
+
const label = computed(() => `${props.data.name} (${props.data.id})`);
|
|
34
|
+
|
|
35
|
+
/** 读取集中存储的校验错误状态,建立响应式依赖 */
|
|
36
|
+
const invalidInfo = computed(() => editorService.get('invalidNodeIds').get(props.data.id));
|
|
37
|
+
|
|
38
|
+
const hasError = computed(() => Boolean(invalidInfo.value?.props || invalidInfo.value?.style));
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* 去掉单条校验文案中的「修改建议」部分。
|
|
42
|
+
*
|
|
43
|
+
* 错误文案可能是多条错误以 `<br>` 拼接的 HTML,每条本身形如 `主文案\n\n建议`。
|
|
44
|
+
* 组件树 tooltip 仅展示错误描述,不展示修改建议(建议仅在错误汇总面板展示),
|
|
45
|
+
* 故先按 `<br>` 拆分,每段用 `stripValidateSuggestion` 截断建议后再拼回。
|
|
46
|
+
*/
|
|
47
|
+
const stripSuggestion = (text?: string): string =>
|
|
48
|
+
String(text ?? '')
|
|
49
|
+
.split(/<br\s*\/?>/i)
|
|
50
|
+
.map((segment) => stripValidateSuggestion(segment))
|
|
51
|
+
.join('<br>');
|
|
52
|
+
|
|
53
|
+
/** 合并属性表单与样式表单的错误文案(去掉建议,本身可能仍是含 <br> 的 HTML) */
|
|
54
|
+
const errorMessage = computed(() =>
|
|
55
|
+
[stripSuggestion(invalidInfo.value?.props), stripSuggestion(invalidInfo.value?.style)].filter(Boolean).join('<br>'),
|
|
56
|
+
);
|
|
57
|
+
</script>
|
|
@@ -33,7 +33,9 @@
|
|
|
33
33
|
</template>
|
|
34
34
|
|
|
35
35
|
<template #tree-node-label="{ data: nodeData }">
|
|
36
|
-
<slot name="layer-node-label" :data="nodeData"
|
|
36
|
+
<slot name="layer-node-label" :data="nodeData">
|
|
37
|
+
<LayerNodeContent :data="nodeData"></LayerNodeContent>
|
|
38
|
+
</slot>
|
|
37
39
|
</template>
|
|
38
40
|
</Tree>
|
|
39
41
|
|
|
@@ -69,6 +71,7 @@ import type {
|
|
|
69
71
|
} from '@editor/type';
|
|
70
72
|
|
|
71
73
|
import LayerMenu from './LayerMenu.vue';
|
|
74
|
+
import LayerNodeContent from './LayerNodeContent.vue';
|
|
72
75
|
import LayerNodeTool from './LayerNodeTool.vue';
|
|
73
76
|
import { useClick } from './use-click';
|
|
74
77
|
import { useDrag } from './use-drag';
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
ref="box"
|
|
9
9
|
v-model:visible="visible"
|
|
10
10
|
title="当前位置下的组件"
|
|
11
|
+
:framework-width="frameworkWidth"
|
|
11
12
|
:position="menuPosition"
|
|
12
13
|
>
|
|
13
14
|
<template #body>
|
|
@@ -36,7 +37,9 @@ import { useNodeStatus } from '@editor/layouts/sidebar/layer/use-node-status';
|
|
|
36
37
|
import type { TreeNodeData } from '@editor/type';
|
|
37
38
|
|
|
38
39
|
const services = useServices();
|
|
39
|
-
const { editorService } = services;
|
|
40
|
+
const { editorService, uiService } = services;
|
|
41
|
+
|
|
42
|
+
const frameworkWidth = computed(() => uiService.get('frameworkRect')?.width || 0);
|
|
40
43
|
|
|
41
44
|
const visible = ref(false);
|
|
42
45
|
const buttonVisible = ref(false);
|
package/src/plugin.ts
CHANGED
|
@@ -21,7 +21,7 @@ import type { App } from 'vue';
|
|
|
21
21
|
import type { DesignPluginOptions } from '@tmagic/design';
|
|
22
22
|
import designPlugin from '@tmagic/design';
|
|
23
23
|
import type { FormInstallOptions } from '@tmagic/form';
|
|
24
|
-
import formPlugin from '@tmagic/form';
|
|
24
|
+
import formPlugin, { registerTypeMatchRules } from '@tmagic/form';
|
|
25
25
|
import tablePlugin from '@tmagic/table';
|
|
26
26
|
|
|
27
27
|
import Code from './fields/Code.vue';
|
|
@@ -44,6 +44,7 @@ import StyleSetter from './fields/StyleSetter/Index.vue';
|
|
|
44
44
|
import uiSelect from './fields/UISelect.vue';
|
|
45
45
|
import CodeEditor from './layouts/CodeEditor.vue';
|
|
46
46
|
import { setEditorConfig } from './utils/config';
|
|
47
|
+
import { editorTypeMatchRules } from './utils/type-match-rules';
|
|
47
48
|
import Editor from './Editor.vue';
|
|
48
49
|
import type { EditorInstallOptions } from './type';
|
|
49
50
|
|
|
@@ -64,6 +65,7 @@ export default {
|
|
|
64
65
|
app.use(designPlugin, opt || {});
|
|
65
66
|
app.use(formPlugin, opt || {});
|
|
66
67
|
app.use(tablePlugin);
|
|
68
|
+
registerTypeMatchRules(editorTypeMatchRules);
|
|
67
69
|
|
|
68
70
|
app.config.globalProperties.$TMAGIC_EDITOR = option;
|
|
69
71
|
setEditorConfig(option);
|
package/src/services/editor.ts
CHANGED
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
isPage,
|
|
32
32
|
isPageFragment,
|
|
33
33
|
setValueByKeyPath,
|
|
34
|
+
traverseNode,
|
|
34
35
|
} from '@tmagic/utils';
|
|
35
36
|
|
|
36
37
|
import BaseService from '@editor/services//BaseService';
|
|
@@ -47,6 +48,8 @@ import type {
|
|
|
47
48
|
EditorNodeInfo,
|
|
48
49
|
HistoryOpSource,
|
|
49
50
|
HistoryOpType,
|
|
51
|
+
NodeInvalidInfo,
|
|
52
|
+
NodeInvalidSource,
|
|
50
53
|
PastePosition,
|
|
51
54
|
StepDiffItem,
|
|
52
55
|
StepValue,
|
|
@@ -104,12 +107,18 @@ class Editor extends BaseService {
|
|
|
104
107
|
stageLoading: true,
|
|
105
108
|
highlightNode: null,
|
|
106
109
|
modifiedNodeIds: new Map(),
|
|
110
|
+
invalidNodeIds: new Map(),
|
|
107
111
|
pageLength: 0,
|
|
108
112
|
pageFragmentLength: 0,
|
|
109
113
|
disabledMultiSelect: false,
|
|
110
114
|
alwaysMultiSelect: false,
|
|
111
115
|
});
|
|
112
116
|
private selectionBeforeOp: Id[] | null = null;
|
|
117
|
+
/**
|
|
118
|
+
* 操作前的节点校验错误快照,与 selectionBeforeOp 同时在 captureSelectionBeforeOp 中捕获,
|
|
119
|
+
* 供 pushOpHistory 写入 step.extra.invalidNodeIdsBefore,用于撤销时还原到「操作前」的错误状态。
|
|
120
|
+
*/
|
|
121
|
+
private invalidNodeIdsBeforeOp: Map<Id, NodeInvalidInfo> | null = null;
|
|
113
122
|
/**
|
|
114
123
|
* 最近一次 pushOpHistory 写入的历史记录 uuid。
|
|
115
124
|
* 供 *AndGetHistoryId 系列方法在调用普通操作后取回本次产生的历史记录 id;
|
|
@@ -127,7 +136,7 @@ class Editor extends BaseService {
|
|
|
127
136
|
|
|
128
137
|
/**
|
|
129
138
|
* 设置当前指点节点配置
|
|
130
|
-
* @param name 'root' | 'page' | 'parent' | 'node' | 'highlightNode' | 'nodes' | 'stage' | 'modifiedNodeIds' | 'pageLength' | 'pageFragmentLength
|
|
139
|
+
* @param name 'root' | 'page' | 'parent' | 'node' | 'highlightNode' | 'nodes' | 'stage' | 'modifiedNodeIds' | 'invalidNodeIds' | 'pageLength' | 'pageFragmentLength
|
|
131
140
|
* @param value MNode
|
|
132
141
|
* @param options.historySource 设置 root 时,本次变更写入历史记录的「操作来源」(仅 name === 'root' 时生效)
|
|
133
142
|
*/
|
|
@@ -180,12 +189,15 @@ class Editor extends BaseService {
|
|
|
180
189
|
}
|
|
181
190
|
|
|
182
191
|
this.emit('root-change', value as StoreState['root'], preValue as StoreState['root'], options);
|
|
192
|
+
|
|
193
|
+
// 整体替换 DSL 后,清理不再存在于新 DSL 中的失效节点错误记录,避免残留误报。
|
|
194
|
+
this.pruneInvalidNodeIds();
|
|
183
195
|
}
|
|
184
196
|
}
|
|
185
197
|
|
|
186
198
|
/**
|
|
187
199
|
* 获取当前指点节点配置
|
|
188
|
-
* @param name 'root' | 'page' | 'parent' | 'node' | 'highlightNode' | 'nodes' | 'stage' | 'modifiedNodeIds' | 'pageLength' | 'pageFragmentLength'
|
|
200
|
+
* @param name 'root' | 'page' | 'parent' | 'node' | 'highlightNode' | 'nodes' | 'stage' | 'modifiedNodeIds' | 'invalidNodeIds' | 'pageLength' | 'pageFragmentLength'
|
|
189
201
|
* @returns MNode
|
|
190
202
|
*/
|
|
191
203
|
public get<K extends StoreStateKey>(name: K): StoreState[K] {
|
|
@@ -663,6 +675,9 @@ class Editor extends BaseService {
|
|
|
663
675
|
|
|
664
676
|
await Promise.all(nodes.map((node) => this.doRemove(node, { doNotSelect, doNotSwitchPage })));
|
|
665
677
|
|
|
678
|
+
// 删除节点时同步清理其(含子树)的校验错误记录;置于 pushOpHistory 之前,使历史快照与本次删除对齐。
|
|
679
|
+
this.removeInvalidNodesBySubtree(nodes);
|
|
680
|
+
|
|
666
681
|
if (removedItems.length > 0 && pageForOp) {
|
|
667
682
|
if (!doNotPushHistory) {
|
|
668
683
|
this.pushOpHistory('remove', {
|
|
@@ -770,11 +785,23 @@ class Editor extends BaseService {
|
|
|
770
785
|
doNotPushHistory?: boolean;
|
|
771
786
|
historyDescription?: string;
|
|
772
787
|
historySource?: HistoryOpSource;
|
|
788
|
+
/**
|
|
789
|
+
* 属性面板提交时携带的校验错误信息,在写入历史记录之前落库,
|
|
790
|
+
* 使历史快照与本次变更对齐,从而 undo/redo 能正确还原错误标记。
|
|
791
|
+
*/
|
|
792
|
+
invalidInfo?: { id: Id; source: NodeInvalidSource; error?: string };
|
|
773
793
|
} = {},
|
|
774
794
|
): Promise<MNode | MNode[]> {
|
|
775
795
|
this.captureSelectionBeforeOp();
|
|
776
796
|
|
|
777
|
-
const {
|
|
797
|
+
const {
|
|
798
|
+
doNotPushHistory = false,
|
|
799
|
+
changeRecordList,
|
|
800
|
+
changeRecords,
|
|
801
|
+
historyDescription,
|
|
802
|
+
historySource,
|
|
803
|
+
invalidInfo,
|
|
804
|
+
} = data;
|
|
778
805
|
|
|
779
806
|
const nodes = Array.isArray(config) ? config : [config];
|
|
780
807
|
|
|
@@ -787,6 +814,9 @@ class Editor extends BaseService {
|
|
|
787
814
|
}),
|
|
788
815
|
);
|
|
789
816
|
|
|
817
|
+
// 校验错误信息在 pushOpHistory 之前落库,保证历史快照包含本次变更对应的错误状态。
|
|
818
|
+
this.applyInvalidInfo(config, invalidInfo);
|
|
819
|
+
|
|
790
820
|
if (updateData[0].oldNode?.type !== NodeType.ROOT) {
|
|
791
821
|
const curNodes = this.get('nodes');
|
|
792
822
|
if (curNodes.length) {
|
|
@@ -1542,6 +1572,7 @@ class Editor extends BaseService {
|
|
|
1542
1572
|
this.set('stage', null);
|
|
1543
1573
|
this.set('highlightNode', null);
|
|
1544
1574
|
this.set('modifiedNodeIds', new Map());
|
|
1575
|
+
this.set('invalidNodeIds', new Map());
|
|
1545
1576
|
this.set('pageLength', 0);
|
|
1546
1577
|
}
|
|
1547
1578
|
|
|
@@ -1555,6 +1586,62 @@ class Editor extends BaseService {
|
|
|
1555
1586
|
this.get('modifiedNodeIds').clear();
|
|
1556
1587
|
}
|
|
1557
1588
|
|
|
1589
|
+
/**
|
|
1590
|
+
* 记录(或覆盖)某个节点在指定来源(属性表单 / 样式表单)上的校验错误信息。
|
|
1591
|
+
* @param id 节点 id
|
|
1592
|
+
* @param source 错误来源:'props'(属性表单)| 'style'(样式表单)
|
|
1593
|
+
* @param message 错误文案(可能是包含 <br> 的 HTML)
|
|
1594
|
+
*/
|
|
1595
|
+
public setInvalidNode(id: Id, source: NodeInvalidSource, message: string) {
|
|
1596
|
+
const map = this.get('invalidNodeIds');
|
|
1597
|
+
const info: NodeInvalidInfo = { ...(map.get(id) || {}) };
|
|
1598
|
+
info[source] = message;
|
|
1599
|
+
map.set(id, info);
|
|
1600
|
+
this.emit('invalid-node-change', map);
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
/**
|
|
1604
|
+
* 删除节点的校验错误记录。
|
|
1605
|
+
* @param id 节点 id
|
|
1606
|
+
* @param source 指定来源则仅删除该来源;不传则删除该节点全部来源的错误
|
|
1607
|
+
*/
|
|
1608
|
+
public deleteInvalidNode(id: Id, source?: NodeInvalidSource) {
|
|
1609
|
+
const map = this.get('invalidNodeIds');
|
|
1610
|
+
if (!map.has(id)) return;
|
|
1611
|
+
|
|
1612
|
+
if (!source) {
|
|
1613
|
+
map.delete(id);
|
|
1614
|
+
} else {
|
|
1615
|
+
const info: NodeInvalidInfo = { ...(map.get(id) || {}) };
|
|
1616
|
+
delete info[source];
|
|
1617
|
+
if (info.props || info.style) {
|
|
1618
|
+
map.set(id, info);
|
|
1619
|
+
} else {
|
|
1620
|
+
map.delete(id);
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1624
|
+
this.emit('invalid-node-change', map);
|
|
1625
|
+
}
|
|
1626
|
+
|
|
1627
|
+
/** 获取当前存在校验错误的节点错误 Map(key 为节点 id) */
|
|
1628
|
+
public getInvalidNodeIds(): Map<Id, NodeInvalidInfo> {
|
|
1629
|
+
return this.get('invalidNodeIds');
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
/** 获取指定节点的校验错误信息 */
|
|
1633
|
+
public getInvalidNodeInfo(id: Id): NodeInvalidInfo | undefined {
|
|
1634
|
+
return this.get('invalidNodeIds').get(id);
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1637
|
+
/** 清空全部校验错误记录 */
|
|
1638
|
+
public resetInvalidNodeId() {
|
|
1639
|
+
const map = this.get('invalidNodeIds');
|
|
1640
|
+
if (map.size === 0) return;
|
|
1641
|
+
map.clear();
|
|
1642
|
+
this.emit('invalid-node-change', map);
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1558
1645
|
public usePlugin(options: AsyncHookPlugin<AsyncMethodName, Editor>): void {
|
|
1559
1646
|
super.usePlugin(options);
|
|
1560
1647
|
}
|
|
@@ -1577,6 +1664,68 @@ class Editor extends BaseService {
|
|
|
1577
1664
|
return super.emit(eventName, ...args);
|
|
1578
1665
|
}
|
|
1579
1666
|
|
|
1667
|
+
/**
|
|
1668
|
+
* 应用一次属性面板提交携带的校验错误信息(在写入历史记录之前调用,使历史快照与本次变更对齐)。
|
|
1669
|
+
* - invalidInfo 为空(调用方未携带):认为本次更新对应的节点已无校验错误,清除其全部来源的错误;
|
|
1670
|
+
* - error 非空则记录错误,为空则清除对应来源的错误。
|
|
1671
|
+
*/
|
|
1672
|
+
private applyInvalidInfo(
|
|
1673
|
+
config: MNode | MNode[],
|
|
1674
|
+
invalidInfo?: { id: Id; source: NodeInvalidSource; error?: string },
|
|
1675
|
+
) {
|
|
1676
|
+
if (!invalidInfo) {
|
|
1677
|
+
// 调用方未携带 invalidInfo:本次更新对应节点不应再保留校验错误,清除其全部来源。
|
|
1678
|
+
const ids = (Array.isArray(config) ? config : [config])
|
|
1679
|
+
.map((node) => node.id)
|
|
1680
|
+
.filter((id): id is Id => id !== undefined);
|
|
1681
|
+
ids.forEach((id) => this.deleteInvalidNode(id));
|
|
1682
|
+
return;
|
|
1683
|
+
}
|
|
1684
|
+
const { id, source, error } = invalidInfo;
|
|
1685
|
+
if (error) {
|
|
1686
|
+
this.setInvalidNode(id, source, error);
|
|
1687
|
+
} else {
|
|
1688
|
+
this.deleteInvalidNode(id, source);
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1691
|
+
|
|
1692
|
+
/** 删除被移除节点(含其子树)的校验错误记录,避免残留误报 */
|
|
1693
|
+
private removeInvalidNodesBySubtree(nodes: MNode[]) {
|
|
1694
|
+
const map = this.get('invalidNodeIds');
|
|
1695
|
+
if (map.size === 0) return;
|
|
1696
|
+
|
|
1697
|
+
let changed = false;
|
|
1698
|
+
nodes.forEach((node) => {
|
|
1699
|
+
traverseNode(node, (n) => {
|
|
1700
|
+
if (n.id !== undefined && map.delete(n.id)) {
|
|
1701
|
+
changed = true;
|
|
1702
|
+
}
|
|
1703
|
+
});
|
|
1704
|
+
});
|
|
1705
|
+
|
|
1706
|
+
if (changed) {
|
|
1707
|
+
this.emit('invalid-node-change', map);
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
|
|
1711
|
+
/** 清理不在当前 DSL 中的失效节点错误记录(用于整体替换 root 后) */
|
|
1712
|
+
private pruneInvalidNodeIds() {
|
|
1713
|
+
const map = this.get('invalidNodeIds');
|
|
1714
|
+
if (map.size === 0) return;
|
|
1715
|
+
|
|
1716
|
+
let changed = false;
|
|
1717
|
+
for (const id of [...map.keys()]) {
|
|
1718
|
+
if (!this.getNodeById(id, false)) {
|
|
1719
|
+
map.delete(id);
|
|
1720
|
+
changed = true;
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
|
|
1724
|
+
if (changed) {
|
|
1725
|
+
this.emit('invalid-node-change', map);
|
|
1726
|
+
}
|
|
1727
|
+
}
|
|
1728
|
+
|
|
1580
1729
|
private addModifiedNodeId(id: Id) {
|
|
1581
1730
|
this.get('modifiedNodeIds').set(id, id);
|
|
1582
1731
|
}
|
|
@@ -1598,6 +1747,9 @@ class Editor extends BaseService {
|
|
|
1598
1747
|
private captureSelectionBeforeOp() {
|
|
1599
1748
|
if (this.selectionBeforeOp) return;
|
|
1600
1749
|
this.selectionBeforeOp = this.get('nodes').map((n) => n.id);
|
|
1750
|
+
// 与选区快照同步捕获「操作前」的校验错误状态;因 applyInvalidInfo 会在 pushOpHistory 前修改 invalidNodeIds,
|
|
1751
|
+
// 必须在此(操作最开始)留存操作前快照,供 undo 还原。
|
|
1752
|
+
this.invalidNodeIdsBeforeOp = new Map(this.get('invalidNodeIds'));
|
|
1601
1753
|
}
|
|
1602
1754
|
|
|
1603
1755
|
/**
|
|
@@ -1704,6 +1856,9 @@ class Editor extends BaseService {
|
|
|
1704
1856
|
selectedBefore: this.selectionBeforeOp ?? [],
|
|
1705
1857
|
selectedAfter: this.get('nodes').map((n) => n.id),
|
|
1706
1858
|
modifiedNodeIds: new Map(this.get('modifiedNodeIds')),
|
|
1859
|
+
// 方向性双快照:undo 还原「操作前」错误状态,redo 还原「操作后」错误状态。
|
|
1860
|
+
invalidNodeIdsBefore: new Map(this.invalidNodeIdsBeforeOp ?? this.get('invalidNodeIds')),
|
|
1861
|
+
invalidNodeIdsAfter: new Map(this.get('invalidNodeIds')),
|
|
1707
1862
|
},
|
|
1708
1863
|
diff,
|
|
1709
1864
|
};
|
|
@@ -1716,6 +1871,7 @@ class Editor extends BaseService {
|
|
|
1716
1871
|
const historyId = pushed ? step.uuid : null;
|
|
1717
1872
|
this.lastPushedHistoryId = historyId;
|
|
1718
1873
|
this.selectionBeforeOp = null;
|
|
1874
|
+
this.invalidNodeIdsBeforeOp = null;
|
|
1719
1875
|
return historyId;
|
|
1720
1876
|
}
|
|
1721
1877
|
|
|
@@ -1841,6 +1997,15 @@ class Editor extends BaseService {
|
|
|
1841
1997
|
|
|
1842
1998
|
this.set('modifiedNodeIds', step.extra?.modifiedNodeIds ?? new Map());
|
|
1843
1999
|
|
|
2000
|
+
// 还原校验错误标记:因 undo/redo 复用同一 step,需按方向取「操作前 / 操作后」快照——
|
|
2001
|
+
// undo(reverse=true) 还原到操作前的错误状态(撤销一个「校验失败」的改动后错误消失),
|
|
2002
|
+
// redo(reverse=false) 还原到操作后的错误状态(重做后错误恢复)。
|
|
2003
|
+
// 浅拷贝一份以隔离历史快照,避免后续 set/deleteInvalidNode 反向污染 step.extra。
|
|
2004
|
+
const invalidToRestore =
|
|
2005
|
+
(reverse ? step.extra?.invalidNodeIdsBefore : step.extra?.invalidNodeIdsAfter) ?? new Map();
|
|
2006
|
+
this.set('invalidNodeIds', new Map(invalidToRestore));
|
|
2007
|
+
this.emit('invalid-node-change', this.get('invalidNodeIds'));
|
|
2008
|
+
|
|
1844
2009
|
const page = toRaw(this.get('page'));
|
|
1845
2010
|
if (page) {
|
|
1846
2011
|
const selectIds = (reverse ? step.extra?.selectedBefore : step.extra?.selectedAfter) ?? [];
|