@tmagic/editor 1.5.2 → 1.5.4

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.
Files changed (89) hide show
  1. package/dist/style.css +366 -6
  2. package/dist/tmagic-editor.js +1749 -829
  3. package/dist/tmagic-editor.umd.cjs +1764 -843
  4. package/package.json +7 -7
  5. package/src/components/CodeBlockEditor.vue +3 -3
  6. package/src/components/CodeParams.vue +2 -2
  7. package/src/components/ContentMenu.vue +13 -13
  8. package/src/components/FloatingBox.vue +9 -9
  9. package/src/components/Resizer.vue +2 -2
  10. package/src/components/ScrollBar.vue +6 -7
  11. package/src/components/ScrollViewer.vue +6 -6
  12. package/src/components/SplitView.vue +3 -3
  13. package/src/fields/DataSourceInput.vue +3 -3
  14. package/src/fields/DataSourceMethods.vue +4 -4
  15. package/src/fields/DisplayConds.vue +2 -1
  16. package/src/fields/StyleSetter/Index.vue +69 -0
  17. package/src/fields/StyleSetter/components/BackgroundPosition.vue +71 -0
  18. package/src/fields/StyleSetter/components/Border.vue +104 -0
  19. package/src/fields/StyleSetter/components/Box.vue +73 -0
  20. package/src/fields/StyleSetter/components/Position.vue +54 -0
  21. package/src/fields/StyleSetter/icons/background-position/LeftBottom.vue +7 -0
  22. package/src/fields/StyleSetter/icons/background-position/LeftCenter.vue +7 -0
  23. package/src/fields/StyleSetter/icons/background-position/LeftTop.vue +12 -0
  24. package/src/fields/StyleSetter/icons/background-position/index.ts +3 -0
  25. package/src/fields/StyleSetter/icons/background-repeat/NoRepeat.vue +8 -0
  26. package/src/fields/StyleSetter/icons/background-repeat/Repeat.vue +31 -0
  27. package/src/fields/StyleSetter/icons/background-repeat/RepeatX.vue +8 -0
  28. package/src/fields/StyleSetter/icons/background-repeat/RepeatY.vue +8 -0
  29. package/src/fields/StyleSetter/icons/background-repeat/index.ts +4 -0
  30. package/src/fields/StyleSetter/icons/display/Block.vue +7 -0
  31. package/src/fields/StyleSetter/icons/display/Flex.vue +7 -0
  32. package/src/fields/StyleSetter/icons/display/Inline.vue +7 -0
  33. package/src/fields/StyleSetter/icons/display/InlineBlock.vue +7 -0
  34. package/src/fields/StyleSetter/icons/display/None.vue +7 -0
  35. package/src/fields/StyleSetter/icons/display/index.ts +5 -0
  36. package/src/fields/StyleSetter/icons/flex-direction/Column.vue +7 -0
  37. package/src/fields/StyleSetter/icons/flex-direction/ColumnReverse.vue +7 -0
  38. package/src/fields/StyleSetter/icons/flex-direction/Row.vue +7 -0
  39. package/src/fields/StyleSetter/icons/flex-direction/RowReverse.vue +7 -0
  40. package/src/fields/StyleSetter/icons/flex-direction/index.ts +4 -0
  41. package/src/fields/StyleSetter/icons/justify-content/Center.vue +5 -0
  42. package/src/fields/StyleSetter/icons/justify-content/FlexEnd.vue +5 -0
  43. package/src/fields/StyleSetter/icons/justify-content/FlexStart.vue +5 -0
  44. package/src/fields/StyleSetter/icons/justify-content/SpaceAround.vue +7 -0
  45. package/src/fields/StyleSetter/icons/justify-content/SpaceBetween.vue +5 -0
  46. package/src/fields/StyleSetter/icons/justify-content/index.ts +5 -0
  47. package/src/fields/StyleSetter/icons/text-align/Center.vue +7 -0
  48. package/src/fields/StyleSetter/icons/text-align/Left.vue +7 -0
  49. package/src/fields/StyleSetter/icons/text-align/Right.vue +7 -0
  50. package/src/fields/StyleSetter/icons/text-align/index.ts +3 -0
  51. package/src/fields/StyleSetter/pro/Background.vue +78 -0
  52. package/src/fields/StyleSetter/pro/Border.vue +35 -0
  53. package/src/fields/StyleSetter/pro/Font.vue +90 -0
  54. package/src/fields/StyleSetter/pro/Layout.vue +164 -0
  55. package/src/fields/StyleSetter/pro/Position.vue +48 -0
  56. package/src/fields/StyleSetter/pro/index.ts +5 -0
  57. package/src/hooks/use-code-block-edit.ts +5 -5
  58. package/src/index.ts +3 -0
  59. package/src/initService.ts +104 -66
  60. package/src/layouts/CodeEditor.vue +6 -6
  61. package/src/layouts/Framework.vue +5 -5
  62. package/src/layouts/NavMenu.vue +6 -3
  63. package/src/layouts/page-bar/PageBar.vue +13 -13
  64. package/src/layouts/page-bar/PageBarScrollContainer.vue +12 -11
  65. package/src/layouts/props-panel/FormPanel.vue +7 -7
  66. package/src/layouts/props-panel/PropsPanel.vue +36 -4
  67. package/src/layouts/sidebar/code-block/CodeBlockListPanel.vue +3 -3
  68. package/src/layouts/sidebar/layer/LayerMenu.vue +2 -2
  69. package/src/layouts/sidebar/layer/LayerPanel.vue +5 -4
  70. package/src/layouts/sidebar/layer/use-click.ts +4 -6
  71. package/src/layouts/workspace/viewer/NodeListMenu.vue +5 -5
  72. package/src/layouts/workspace/viewer/Stage.vue +13 -13
  73. package/src/layouts/workspace/viewer/StageOverlay.vue +2 -2
  74. package/src/layouts/workspace/viewer/ViewerMenu.vue +3 -3
  75. package/src/services/componentList.ts +2 -2
  76. package/src/services/dep.ts +8 -2
  77. package/src/services/editor.ts +2 -2
  78. package/src/services/stageOverlay.ts +2 -2
  79. package/src/services/ui.ts +2 -2
  80. package/src/theme/props-panel.scss +13 -0
  81. package/src/theme/resizer.scss +2 -2
  82. package/src/theme/style-setter/background.scss +113 -0
  83. package/src/theme/style-setter/border.scss +53 -0
  84. package/src/theme/style-setter/index.scss +28 -0
  85. package/src/theme/style-setter/layout.scss +199 -0
  86. package/src/theme/theme.scss +1 -0
  87. package/src/utils/idle-task.ts +26 -10
  88. package/src/utils/props.ts +52 -297
  89. package/types/index.d.ts +432 -170
@@ -144,40 +144,40 @@ const remove = (node: MPage | MPageFragment) => {
144
144
  editorService?.remove(node);
145
145
  };
146
146
 
147
- const pageBarScrollContainer = useTemplateRef<InstanceType<typeof PageBarScrollContainer>>('pageBarScrollContainer');
148
- const pageBarItems = useTemplateRef<HTMLDivElement[]>('pageBarItems');
147
+ const pageBarScrollContainerRef = useTemplateRef<InstanceType<typeof PageBarScrollContainer>>('pageBarScrollContainer');
148
+ const pageBarItemEls = useTemplateRef<HTMLDivElement[]>('pageBarItems');
149
149
  watch(page, (page) => {
150
150
  if (
151
151
  !page ||
152
- !pageBarScrollContainer.value?.itemsContainerWidth ||
153
- !pageBarItems.value ||
154
- pageBarItems.value.length < 2
152
+ !pageBarScrollContainerRef.value?.itemsContainerWidth ||
153
+ !pageBarItemEls.value ||
154
+ pageBarItemEls.value.length < 2
155
155
  ) {
156
156
  return;
157
157
  }
158
158
 
159
- const firstItem = pageBarItems.value[0];
160
- const lastItem = pageBarItems.value[pageBarItems.value.length - 1];
159
+ const firstItem = pageBarItemEls.value[0];
160
+ const lastItem = pageBarItemEls.value[pageBarItemEls.value.length - 1];
161
161
 
162
162
  if (page.id === firstItem.dataset.pageId) {
163
- pageBarScrollContainer.value.scroll('start');
163
+ pageBarScrollContainerRef.value.scroll('start');
164
164
  } else if (page.id === lastItem.dataset.pageId) {
165
- pageBarScrollContainer.value.scroll('end');
165
+ pageBarScrollContainerRef.value.scroll('end');
166
166
  } else {
167
- const pageItem = pageBarItems.value.find((item) => item.dataset.pageId === page.id);
167
+ const pageItem = pageBarItemEls.value.find((item) => item.dataset.pageId === page.id);
168
168
  if (!pageItem) {
169
169
  return;
170
170
  }
171
171
 
172
172
  const pageItemRect = pageItem.getBoundingClientRect();
173
173
  const offsetLeft = pageItemRect.left - firstItem.getBoundingClientRect().left;
174
- const { itemsContainerWidth } = pageBarScrollContainer.value;
174
+ const { itemsContainerWidth } = pageBarScrollContainerRef.value;
175
175
 
176
176
  const left = itemsContainerWidth - offsetLeft - pageItemRect.width;
177
177
 
178
- const translateLeft = pageBarScrollContainer.value.getTranslateLeft();
178
+ const translateLeft = pageBarScrollContainerRef.value.getTranslateLeft();
179
179
  if (offsetLeft + translateLeft < 0 || offsetLeft + pageItemRect.width > itemsContainerWidth - translateLeft) {
180
- pageBarScrollContainer.value.scrollTo(left);
180
+ pageBarScrollContainerRef.value.scrollTo(left);
181
181
  }
182
182
  }
183
183
  });
@@ -46,7 +46,7 @@ const services = inject<Services>('services');
46
46
  const editorService = services?.editorService;
47
47
  const uiService = services?.uiService;
48
48
 
49
- const itemsContainer = useTemplateRef<HTMLElement>('itemsContainer');
49
+ const itemsContainerEl = useTemplateRef<HTMLElement>('itemsContainer');
50
50
  const canScroll = ref(false);
51
51
 
52
52
  const showAddPageButton = computed(() => uiService?.get('showAddPageButton'));
@@ -54,19 +54,21 @@ const showPageListButton = computed(() => uiService?.get('showPageListButton'));
54
54
 
55
55
  const itemsContainerWidth = ref(0);
56
56
 
57
+ const pageBarEl = useTemplateRef<HTMLDivElement>('pageBar');
58
+
57
59
  const setCanScroll = () => {
58
60
  // 减去新增、搜索、页面列表、左移、右移5个按钮的宽度
59
61
  // 37 = icon width 16 + padding 10 * 2 + border-right 1
60
62
  itemsContainerWidth.value =
61
- (pageBar.value?.clientWidth || 0) -
63
+ (pageBarEl.value?.clientWidth || 0) -
62
64
  37 * 2 -
63
65
  37 -
64
66
  (showAddPageButton.value ? 37 : 21) -
65
67
  (showPageListButton.value ? 37 : 0);
66
68
 
67
69
  nextTick(() => {
68
- if (itemsContainer.value) {
69
- canScroll.value = itemsContainer.value.scrollWidth - itemsContainerWidth.value > 1;
70
+ if (itemsContainerEl.value) {
71
+ canScroll.value = itemsContainerEl.value.scrollWidth - itemsContainerWidth.value > 1;
70
72
  }
71
73
  });
72
74
  };
@@ -75,9 +77,8 @@ const resizeObserver = new ResizeObserver(() => {
75
77
  setCanScroll();
76
78
  });
77
79
 
78
- const pageBar = useTemplateRef<HTMLDivElement>('pageBar');
79
80
  onMounted(() => {
80
- pageBar.value && resizeObserver.observe(pageBar.value);
81
+ pageBarEl.value && resizeObserver.observe(pageBarEl.value);
81
82
  });
82
83
 
83
84
  onBeforeUnmount(() => {
@@ -87,9 +88,9 @@ onBeforeUnmount(() => {
87
88
  let translateLeft = 0;
88
89
 
89
90
  const scroll = (type: 'left' | 'right' | 'start' | 'end') => {
90
- if (!itemsContainer.value || !canScroll.value) return;
91
+ if (!itemsContainerEl.value || !canScroll.value) return;
91
92
 
92
- const maxScrollLeft = itemsContainer.value.scrollWidth - itemsContainerWidth.value;
93
+ const maxScrollLeft = itemsContainerEl.value.scrollWidth - itemsContainerWidth.value;
93
94
 
94
95
  if (type === 'left') {
95
96
  scrollTo(translateLeft + 200);
@@ -103,8 +104,8 @@ const scroll = (type: 'left' | 'right' | 'start' | 'end') => {
103
104
  };
104
105
 
105
106
  const scrollTo = (value: number) => {
106
- if (!itemsContainer.value || !canScroll.value) return;
107
- const maxScrollLeft = itemsContainer.value.scrollWidth - itemsContainerWidth.value;
107
+ if (!itemsContainerEl.value || !canScroll.value) return;
108
+ const maxScrollLeft = itemsContainerEl.value.scrollWidth - itemsContainerWidth.value;
108
109
 
109
110
  if (value >= 0) {
110
111
  value = 0;
@@ -116,7 +117,7 @@ const scrollTo = (value: number) => {
116
117
 
117
118
  translateLeft = value;
118
119
 
119
- itemsContainer.value.style.transform = `translate(${translateLeft}px, 0px)`;
120
+ itemsContainerEl.value.style.transform = `translate(${translateLeft}px, 0px)`;
120
121
  };
121
122
 
122
123
  watch(
@@ -88,23 +88,23 @@ const propsPanelSize = computed(() => services?.uiService.get('propsPanelSize')
88
88
  const { height: editorContentHeight } = useEditorContentHeight();
89
89
  const stage = computed(() => services?.editorService.get('stage'));
90
90
 
91
- const configForm = useTemplateRef<InstanceType<typeof MForm>>('configForm');
91
+ const configFormRef = useTemplateRef<InstanceType<typeof MForm>>('configForm');
92
92
 
93
93
  watchEffect(() => {
94
- if (configForm.value) {
95
- configForm.value.formState.stage = stage.value;
96
- configForm.value.formState.services = services;
94
+ if (configFormRef.value) {
95
+ configFormRef.value.formState.stage = stage.value;
96
+ configFormRef.value.formState.services = services;
97
97
  }
98
98
  });
99
99
 
100
100
  const internalInstance = getCurrentInstance();
101
101
  onMounted(() => {
102
- emit('mounted', internalInstance);
102
+ emit('mounted', internalInstance?.proxy);
103
103
  });
104
104
 
105
105
  const submit = async (v: FormValue, eventData: ContainerChangeEventData) => {
106
106
  try {
107
- const values = await configForm.value?.submitForm();
107
+ const values = await configFormRef.value?.submitForm();
108
108
  emit('submit', values, eventData);
109
109
  } catch (e: any) {
110
110
  emit('submit-error', e);
@@ -119,5 +119,5 @@ const saveCode = (values: any) => {
119
119
  emit('submit', props.codeValueKey ? { [props.codeValueKey]: values } : values);
120
120
  };
121
121
 
122
- defineExpose({ configForm, submit });
122
+ defineExpose({ configForm: configFormRef, submit });
123
123
  </script>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="m-editor-props-panel" v-show="nodes.length === 1">
2
+ <div ref="propsPanel" class="m-editor-props-panel" v-show="nodes.length === 1">
3
3
  <slot name="props-panel-header"></slot>
4
4
  <FormPanel
5
5
  ref="propertyFormPanel"
@@ -15,6 +15,8 @@
15
15
  @mounted="mountedHandler"
16
16
  ></FormPanel>
17
17
 
18
+ <Resizer v-if="showStylePanel" @change="widthChange"></Resizer>
19
+
18
20
  <FormPanel
19
21
  v-if="showStylePanel"
20
22
  class="m-editor-props-style-panel"
@@ -53,12 +55,14 @@
53
55
  <script lang="ts" setup>
54
56
  import { computed, inject, onBeforeUnmount, ref, useTemplateRef, watchEffect } from 'vue';
55
57
  import { Close, Sugar } from '@element-plus/icons-vue';
58
+ import type { OnDrag } from 'gesto';
56
59
 
57
60
  import type { MNode } from '@tmagic/core';
58
61
  import { TMagicButton } from '@tmagic/design';
59
62
  import type { ContainerChangeEventData, FormState, FormValue } from '@tmagic/form';
60
63
 
61
64
  import MIcon from '@editor/components/Icon.vue';
65
+ import Resizer from '@editor/components/Resizer.vue';
62
66
  import type { PropsPanelSlots, Services } from '@editor/type';
63
67
  import { styleTabConfig } from '@editor/utils';
64
68
 
@@ -120,7 +124,21 @@ const submit = async (v: MNode, eventData?: ContainerChangeEventData) => {
120
124
  if (!v.id) {
121
125
  v.id = values.value.id;
122
126
  }
123
- services?.editorService.update(v, { changeRecords: eventData?.changeRecords });
127
+
128
+ const newValue: MNode = {
129
+ ...v,
130
+ style: {},
131
+ };
132
+
133
+ if (v.style) {
134
+ Object.entries(v.style).forEach(([key, value]) => {
135
+ if (value !== '' && newValue.style) {
136
+ newValue.style[key] = value;
137
+ }
138
+ });
139
+ }
140
+
141
+ services?.editorService.update(newValue, { changeRecords: eventData?.changeRecords });
124
142
  } catch (e: any) {
125
143
  emit('submit-error', e);
126
144
  }
@@ -130,8 +148,22 @@ const errorHandler = (e: any) => {
130
148
  emit('form-error', e);
131
149
  };
132
150
 
133
- const mountedHandler = (e: InstanceType<typeof FormPanel>) => {
134
- emit('mounted', e);
151
+ const mountedHandler = () => {
152
+ if (propertyFormPanelRef.value) {
153
+ emit('mounted', propertyFormPanelRef.value);
154
+ }
155
+ };
156
+
157
+ const propsPanelEl = useTemplateRef('propsPanel');
158
+ const widthChange = ({ deltaX }: OnDrag) => {
159
+ if (!propsPanelEl.value) {
160
+ return;
161
+ }
162
+
163
+ const width = globalThis.parseFloat(
164
+ getComputedStyle(propsPanelEl.value).getPropertyValue('--props-style-panel-width'),
165
+ );
166
+ propsPanelEl.value.style.setProperty('--props-style-panel-width', `${width - deltaX}px`);
135
167
  };
136
168
 
137
169
  const { showStylePanel, showStylePanelHandler, closeStylePanelHandler } = useStylePanel(services);
@@ -89,10 +89,10 @@ const editable = computed(() => codeBlockService?.getEditStatus());
89
89
  const { codeBlockEditor, codeConfig, editCode, deleteCode, createCodeBlock, submitCodeBlockHandler } =
90
90
  useCodeBlockEdit(codeBlockService);
91
91
 
92
- const codeBlockList = useTemplateRef<InstanceType<typeof CodeBlockList>>('codeBlockList');
92
+ const codeBlockListRef = useTemplateRef<InstanceType<typeof CodeBlockList>>('codeBlockList');
93
93
 
94
94
  const filterTextChangeHandler = (val: string) => {
95
- codeBlockList.value?.filter(val);
95
+ codeBlockListRef.value?.filter(val);
96
96
  };
97
97
 
98
98
  eventBus?.on('edit-code', (id: string) => {
@@ -104,7 +104,7 @@ const {
104
104
  menuData: contentMenuData,
105
105
  contentMenuHideHandler,
106
106
  } = useContentMenu((id: string) => {
107
- codeBlockList.value?.deleteCode(id);
107
+ codeBlockListRef.value?.deleteCode(id);
108
108
  });
109
109
  const menuData = computed<(MenuButton | MenuComponent)[]>(() => props.customContentMenu(contentMenuData, 'code-block'));
110
110
  </script>
@@ -27,7 +27,7 @@ const emit = defineEmits<{
27
27
  }>();
28
28
 
29
29
  const services = inject<Services>('services');
30
- const menu = useTemplateRef<InstanceType<typeof ContentMenu>>('menu');
30
+ const menuRef = useTemplateRef<InstanceType<typeof ContentMenu>>('menu');
31
31
  const node = computed(() => services?.editorService.get('node'));
32
32
  const nodes = computed(() => services?.editorService.get('nodes'));
33
33
  const componentList = computed(() => services?.componentListService.getList() || []);
@@ -113,7 +113,7 @@ const menuData = computed<(MenuButton | MenuComponent)[]>(() =>
113
113
  );
114
114
 
115
115
  const show = (e: MouseEvent) => {
116
- menu.value?.show(e);
116
+ menuRef.value?.show(e);
117
117
  };
118
118
 
119
119
  defineExpose({
@@ -87,13 +87,13 @@ defineProps<{
87
87
  const services = inject<Services>('services');
88
88
  const editorService = services?.editorService;
89
89
 
90
- const tree = useTemplateRef<InstanceType<typeof Tree>>('tree');
90
+ const treeRef = useTemplateRef<InstanceType<typeof Tree>>('tree');
91
91
 
92
92
  const page = computed(() => editorService?.get('page'));
93
93
  const nodeData = computed<TreeNodeData[]>(() => (!page.value ? [] : [page.value]));
94
94
 
95
95
  const { nodeStatusMap } = useNodeStatus(services);
96
- const { isCtrlKeyDown } = useKeybinding(services, tree);
96
+ const { isCtrlKeyDown } = useKeybinding(services, treeRef);
97
97
 
98
98
  const filterNodeMethod = (v: string, data: MNode): boolean => {
99
99
  let name = '';
@@ -121,10 +121,11 @@ const collapseAllHandler = () => {
121
121
 
122
122
  const { handleDragStart, handleDragEnd, handleDragLeave, handleDragOver } = useDrag(services);
123
123
 
124
+ // 右键菜单
125
+ const menuRef = useTemplateRef<InstanceType<typeof LayerMenu>>('menu');
124
126
  const {
125
- menu,
126
127
  nodeClickHandler,
127
128
  nodeContentMenuHandler,
128
129
  highlightHandler: mouseenterHandler,
129
- } = useClick(services, isCtrlKeyDown, nodeStatusMap);
130
+ } = useClick(services, isCtrlKeyDown, nodeStatusMap, menuRef);
130
131
  </script>
@@ -1,4 +1,4 @@
1
- import { computed, type ComputedRef, nextTick, type Ref, useTemplateRef } from 'vue';
1
+ import { computed, type ComputedRef, nextTick, type Ref, type ShallowRef } from 'vue';
2
2
  import { throttle } from 'lodash-es';
3
3
 
4
4
  import { Id, MNode } from '@tmagic/core';
@@ -13,6 +13,7 @@ export const useClick = (
13
13
  services: Services | undefined,
14
14
  isCtrlKeyDown: Ref<boolean>,
15
15
  nodeStatusMap: ComputedRef<Map<Id, LayerNodeStatus> | undefined>,
16
+ menuRef: ShallowRef<InstanceType<typeof LayerMenu> | null>,
16
17
  ) => {
17
18
  const isMultiSelect = computed(() => isCtrlKeyDown.value && !services?.editorService.get('disabledMultiSelect'));
18
19
 
@@ -98,11 +99,8 @@ export const useClick = (
98
99
  });
99
100
  };
100
101
 
101
- // 右键菜单
102
- const menu = useTemplateRef<InstanceType<typeof LayerMenu>>('menu');
103
-
104
102
  return {
105
- menu,
103
+ menuRef,
106
104
 
107
105
  nodeClickHandler,
108
106
 
@@ -114,7 +112,7 @@ export const useClick = (
114
112
  nodeClickHandler(event, data);
115
113
  }
116
114
 
117
- menu.value?.show(event);
115
+ menuRef.value?.show(event);
118
116
  },
119
117
 
120
118
  highlightHandler,
@@ -39,8 +39,8 @@ const editorService = services?.editorService;
39
39
 
40
40
  const visible = ref(false);
41
41
  const buttonVisible = ref(false);
42
- const button = useTemplateRef<HTMLDivElement>('button');
43
- const box = useTemplateRef<InstanceType<typeof FloatingBox>>('box');
42
+ const buttonEl = useTemplateRef<HTMLDivElement>('button');
43
+ const boxRef = useTemplateRef<InstanceType<typeof FloatingBox>>('box');
44
44
 
45
45
  const stage = computed(() => editorService?.get('stage'));
46
46
  const page = computed(() => editorService?.get('page'));
@@ -99,14 +99,14 @@ const menuPosition = ref({
99
99
  });
100
100
 
101
101
  watch(visible, async (visible) => {
102
- if (!button.value || !visible) {
102
+ if (!buttonEl.value || !visible) {
103
103
  return;
104
104
  }
105
105
 
106
106
  await nextTick();
107
107
 
108
- const rect = button.value.getBoundingClientRect();
109
- const height = box.value?.target?.clientHeight || 0;
108
+ const rect = buttonEl.value.getBoundingClientRect();
109
+ const height = boxRef.value?.target?.clientHeight || 0;
110
110
 
111
111
  menuPosition.value = {
112
112
  left: rect.left + rect.width + 5,
@@ -14,7 +14,7 @@
14
14
  width: 60,
15
15
  height: 50,
16
16
  }"
17
- @click="stageWrap?.container?.focus()"
17
+ @click="stageWrapRef?.container?.focus()"
18
18
  >
19
19
  <div
20
20
  class="m-editor-stage-container"
@@ -95,9 +95,9 @@ const services = inject<Services>('services');
95
95
 
96
96
  const stageLoading = computed(() => services?.editorService.get('stageLoading') || false);
97
97
 
98
- const stageWrap = useTemplateRef<InstanceType<typeof ScrollViewer>>('stageWrap');
99
- const stageContainer = useTemplateRef<HTMLDivElement>('stageContainer');
100
- const menu = useTemplateRef<InstanceType<typeof ViewerMenu>>('menu');
98
+ const stageWrapRef = useTemplateRef<InstanceType<typeof ScrollViewer>>('stageWrap');
99
+ const stageContainerEl = useTemplateRef<HTMLDivElement>('stageContainer');
100
+ const menuRef = useTemplateRef<InstanceType<typeof ViewerMenu>>('menu');
101
101
 
102
102
  const nodes = computed(() => services?.editorService.get('nodes') || []);
103
103
  const isMultiSelect = computed(() => nodes.value.length > 1);
@@ -111,18 +111,18 @@ const node = computed(() => services?.editorService.get('node'));
111
111
  watchEffect(() => {
112
112
  if (stage || !page.value) return;
113
113
 
114
- if (!stageContainer.value) return;
114
+ if (!stageContainerEl.value) return;
115
115
  if (!(props.stageOptions?.runtimeUrl || props.stageOptions?.render) || !root.value) return;
116
116
 
117
117
  stage = useStage(props.stageOptions);
118
118
 
119
119
  stage.on('select', () => {
120
- stageWrap.value?.container?.focus();
120
+ stageWrapRef.value?.container?.focus();
121
121
  });
122
122
 
123
123
  services?.editorService.set('stage', markRaw(stage));
124
124
 
125
- stage.mount(stageContainer.value);
125
+ stage.mount(stageContainerEl.value);
126
126
 
127
127
  if (!node.value?.id) {
128
128
  return;
@@ -188,9 +188,9 @@ const resizeObserver = new ResizeObserver((entries) => {
188
188
  });
189
189
 
190
190
  onMounted(() => {
191
- if (stageWrap.value?.container) {
192
- resizeObserver.observe(stageWrap.value.container);
193
- services?.keybindingService.registerEl(KeyBindingContainerKey.STAGE, stageWrap.value.container);
191
+ if (stageWrapRef.value?.container) {
192
+ resizeObserver.observe(stageWrapRef.value.container);
193
+ services?.keybindingService.registerEl(KeyBindingContainerKey.STAGE, stageWrapRef.value.container);
194
194
  }
195
195
  });
196
196
 
@@ -206,7 +206,7 @@ const parseDSL = getEditorConfig('parseDSL');
206
206
 
207
207
  const contextmenuHandler = (e: MouseEvent) => {
208
208
  e.preventDefault();
209
- menu.value?.show(e);
209
+ menuRef.value?.show(e);
210
210
  };
211
211
 
212
212
  const dragoverHandler = (e: DragEvent) => {
@@ -239,10 +239,10 @@ const dropHandler = async (e: DragEvent) => {
239
239
  parent = services?.editorService.getNodeById(parentId, false) as MContainer;
240
240
  }
241
241
 
242
- if (parent && stageContainer.value && stage) {
242
+ if (parent && stageContainerEl.value && stage) {
243
243
  const layout = await services?.editorService.getLayout(parent);
244
244
 
245
- const containerRect = stageContainer.value.getBoundingClientRect();
245
+ const containerRect = stageContainerEl.value.getBoundingClientRect();
246
246
  const { scrollTop, scrollLeft } = stage.mask!;
247
247
  const { style = {} } = config.data;
248
248
 
@@ -19,7 +19,7 @@ const services = inject<Services>('services');
19
19
 
20
20
  const stageOptions = inject<StageOptions>('stageOptions');
21
21
 
22
- const stageOverlay = useTemplateRef<HTMLDivElement>('stageOverlay');
22
+ const stageOverlayEl = useTemplateRef<HTMLDivElement>('stageOverlay');
23
23
 
24
24
  const stageOverlayVisible = computed(() => services?.stageOverlayService.get('stageOverlayVisible'));
25
25
  const wrapWidth = computed(() => services?.stageOverlayService.get('wrapWidth') || 0);
@@ -42,7 +42,7 @@ watch(stage, (stage) => {
42
42
  }
43
43
  });
44
44
 
45
- watch(stageOverlay, (stageOverlay) => {
45
+ watch(stageOverlayEl, (stageOverlay) => {
46
46
  if (!services) return;
47
47
 
48
48
  const subStage = services.stageOverlayService.createStage(stageOptions);
@@ -31,7 +31,7 @@ const props = withDefaults(
31
31
 
32
32
  const services = inject<Services>('services');
33
33
  const editorService = services?.editorService;
34
- const menu = useTemplateRef<InstanceType<typeof ContentMenu>>('menu');
34
+ const menuRef = useTemplateRef<InstanceType<typeof ContentMenu>>('menu');
35
35
  const canCenter = ref(false);
36
36
 
37
37
  const node = computed(() => editorService?.get('node'));
@@ -52,7 +52,7 @@ const menuData = computed<(MenuButton | MenuComponent)[]>(() =>
52
52
  },
53
53
  },
54
54
  useCopyMenu(),
55
- usePasteMenu(menu),
55
+ usePasteMenu(menuRef),
56
56
  {
57
57
  type: 'divider',
58
58
  direction: 'horizontal',
@@ -136,7 +136,7 @@ watch(
136
136
  );
137
137
 
138
138
  const show = (e: MouseEvent) => {
139
- menu.value?.show(e);
139
+ menuRef.value?.show(e);
140
140
  };
141
141
 
142
142
  defineExpose({ show });
@@ -16,14 +16,14 @@
16
16
  * limitations under the License.
17
17
  */
18
18
 
19
- import { reactive } from 'vue';
19
+ import { shallowReactive } from 'vue';
20
20
 
21
21
  import type { ComponentGroup, ComponentGroupState } from '@editor/type';
22
22
 
23
23
  import BaseService from './BaseService';
24
24
 
25
25
  class ComponentList extends BaseService {
26
- private state = reactive<ComponentGroupState>({
26
+ private state = shallowReactive<ComponentGroupState>({
27
27
  list: [],
28
28
  });
29
29
 
@@ -15,7 +15,7 @@
15
15
  * See the License for the specific language governing permissions and
16
16
  * limitations under the License.
17
17
  */
18
- import { reactive } from 'vue';
18
+ import { reactive, shallowReactive } from 'vue';
19
19
 
20
20
  import type { DepExtendedData, Id, MNode, Target, TargetNode } from '@tmagic/core';
21
21
  import { DepTargetType, Watcher } from '@tmagic/core';
@@ -29,6 +29,7 @@ export interface DepEvents {
29
29
  'add-target': [target: Target];
30
30
  'remove-target': [id: string | number];
31
31
  collected: [nodes: MNode[], deep: boolean];
32
+ 'ds-collected': [nodes: MNode[], deep: boolean];
32
33
  }
33
34
 
34
35
  interface State {
@@ -40,7 +41,7 @@ type StateKey = keyof State;
40
41
  const idleTask = new IdleTask<{ node: TargetNode; deep: boolean; target: Target }>();
41
42
 
42
43
  class Dep extends BaseService {
43
- private state = reactive<State>({
44
+ private state = shallowReactive<State>({
44
45
  collecting: false,
45
46
  });
46
47
 
@@ -96,6 +97,7 @@ class Dep extends BaseService {
96
97
  this.set('collecting', false);
97
98
 
98
99
  this.emit('collected', nodes, deep);
100
+ this.emit('ds-collected', nodes, deep);
99
101
  }
100
102
 
101
103
  public collectIdle(nodes: MNode[], depExtendedData: DepExtendedData = {}, deep = false, type?: DepTargetType) {
@@ -119,6 +121,9 @@ class Dep extends BaseService {
119
121
  this.set('collecting', false);
120
122
  resolve();
121
123
  });
124
+ idleTask.once('hight-level-finish', () => {
125
+ this.emit('ds-collected', nodes, deep);
126
+ });
122
127
  });
123
128
  }
124
129
 
@@ -185,6 +190,7 @@ class Dep extends BaseService {
185
190
  deep: false,
186
191
  target,
187
192
  },
193
+ target.type === DepTargetType.DATA_SOURCE,
188
194
  );
189
195
 
190
196
  if (deep && Array.isArray(node.items) && node.items.length) {
@@ -527,8 +527,8 @@ class Editor extends BaseService {
527
527
 
528
528
  let newConfig = await this.toggleFixedPosition(toRaw(config), node, root);
529
529
 
530
- newConfig = mergeWith(cloneDeep(node), newConfig, (objValue, srcValue, key) => {
531
- if (typeof srcValue === 'undefined' && Object.hasOwn(newConfig, key)) {
530
+ newConfig = mergeWith(cloneDeep(node), newConfig, (objValue, srcValue, key, object: any, source: any) => {
531
+ if (typeof srcValue === 'undefined' && Object.hasOwn(source, key)) {
532
532
  return '';
533
533
  }
534
534
 
@@ -1,4 +1,4 @@
1
- import { reactive } from 'vue';
1
+ import { shallowReactive } from 'vue';
2
2
  import type { Writable } from 'type-fest';
3
3
 
4
4
  import StageCore from '@tmagic/stage';
@@ -17,7 +17,7 @@ const canUsePluginMethods = {
17
17
  type SyncMethodName = Writable<(typeof canUsePluginMethods)['sync']>;
18
18
 
19
19
  class StageOverlay extends BaseService {
20
- private state: StageOverlayState = reactive({
20
+ private state: StageOverlayState = shallowReactive({
21
21
  wrapDiv: document.createElement('div'),
22
22
  sourceEl: null,
23
23
  contentEl: null,
@@ -16,7 +16,7 @@
16
16
  * limitations under the License.
17
17
  */
18
18
 
19
- import { reactive } from 'vue';
19
+ import { shallowReactive } from 'vue';
20
20
  import type { Writable } from 'type-fest';
21
21
 
22
22
  import { convertToNumber } from '@tmagic/utils';
@@ -26,7 +26,7 @@ import type { AsyncHookPlugin, StageRect, UiState } from '@editor/type';
26
26
 
27
27
  import BaseService from './BaseService';
28
28
 
29
- const state = reactive<UiState>({
29
+ const state = shallowReactive<UiState>({
30
30
  uiSelectMode: false,
31
31
  showSrc: false,
32
32
  showStylePanel: true,
@@ -72,6 +72,11 @@
72
72
  align-items: center;
73
73
  border-bottom: 2px solid $border-color;
74
74
  }
75
+
76
+ .tmagic-design-form {
77
+ padding-right: 10px;
78
+ padding-left: 10px;
79
+ }
75
80
  }
76
81
 
77
82
  .m-editor-props-panel-src-icon {
@@ -95,6 +100,14 @@
95
100
  z-index: 10;
96
101
  }
97
102
 
103
+ .m-editor-resizer {
104
+ position: absolute;
105
+ display: block;
106
+ top: 0;
107
+ right: var(--props-style-panel-width);
108
+ z-index: 13;
109
+ }
110
+
98
111
  &.small {
99
112
  .el-form-item__label {
100
113
  font-size: 12px;
@@ -1,6 +1,6 @@
1
1
  .m-editor-resizer {
2
- border-left: 1px solid transparent;
3
- border-right: 1px solid transparent;
2
+ border-left: 2px solid transparent;
3
+ border-right: 2px solid transparent;
4
4
  width: 8px;
5
5
  margin: 0 -5px;
6
6
  height: 100%;