@tmagic/editor 1.0.6 → 1.1.0-beta.10

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 (105) hide show
  1. package/dist/style.css +5 -1
  2. package/dist/{tmagic-editor.es.js → tmagic-editor.mjs} +1522 -1177
  3. package/dist/tmagic-editor.mjs.map +1 -0
  4. package/dist/tmagic-editor.umd.js +1606 -1259
  5. package/dist/tmagic-editor.umd.js.map +1 -1
  6. package/package.json +22 -20
  7. package/src/Editor.vue +41 -15
  8. package/src/components/ContentMenu.vue +87 -99
  9. package/src/components/Icon.vue +2 -2
  10. package/src/components/ScrollViewer.vue +2 -2
  11. package/src/components/ToolButton.vue +151 -168
  12. package/src/fields/UISelect.vue +49 -70
  13. package/src/index.ts +2 -1
  14. package/src/layouts/AddPageBox.vue +3 -3
  15. package/src/layouts/Framework.vue +1 -1
  16. package/src/layouts/NavMenu.vue +2 -2
  17. package/src/layouts/PropsPanel.vue +1 -1
  18. package/src/layouts/Resizer.vue +1 -1
  19. package/src/layouts/sidebar/ComponentListPanel.vue +43 -2
  20. package/src/layouts/sidebar/LayerMenu.vue +3 -3
  21. package/src/layouts/sidebar/LayerPanel.vue +13 -4
  22. package/src/layouts/sidebar/Sidebar.vue +1 -1
  23. package/src/layouts/sidebar/TabPane.vue +3 -3
  24. package/src/layouts/workspace/PageBar.vue +63 -192
  25. package/src/layouts/workspace/PageBarScrollContainer.vue +111 -0
  26. package/src/layouts/workspace/Stage.vue +208 -188
  27. package/src/layouts/workspace/ViewerMenu.vue +141 -148
  28. package/src/layouts/workspace/Workspace.vue +11 -11
  29. package/src/services/BaseService.ts +5 -10
  30. package/src/services/componentList.ts +3 -3
  31. package/src/services/editor.ts +247 -140
  32. package/src/services/events.ts +1 -1
  33. package/src/services/history.ts +1 -1
  34. package/src/services/props.ts +63 -11
  35. package/src/services/storage.ts +133 -0
  36. package/src/services/ui.ts +10 -4
  37. package/src/theme/component-list-panel.scss +5 -0
  38. package/src/theme/framework.scss +1 -1
  39. package/src/theme/stage.scss +2 -2
  40. package/src/type.ts +28 -7
  41. package/src/utils/config.ts +1 -1
  42. package/src/utils/editor.ts +53 -35
  43. package/src/utils/operator.ts +109 -0
  44. package/src/utils/props.ts +2 -24
  45. package/src/utils/scroll-viewer.ts +1 -1
  46. package/tsconfig.build.json +13 -0
  47. package/{dist/types/src → types}/Editor.vue.d.ts +44 -9
  48. package/types/components/ContentMenu.vue.d.ts +116 -0
  49. package/types/components/Icon.vue.d.ts +13 -0
  50. package/types/components/ScrollViewer.vue.d.ts +22 -0
  51. package/types/components/ToolButton.vue.d.ts +109 -0
  52. package/types/fields/Code.vue.d.ts +23 -0
  53. package/{dist/types/src → types}/fields/CodeLink.vue.d.ts +4 -6
  54. package/types/fields/UISelect.vue.d.ts +83 -0
  55. package/{dist/types/src → types}/index.d.ts +4 -1
  56. package/types/layouts/AddPageBox.vue.d.ts +4 -0
  57. package/{dist/types/src → types}/layouts/CodeEditor.vue.d.ts +11 -13
  58. package/types/layouts/Framework.vue.d.ts +22 -0
  59. package/types/layouts/NavMenu.vue.d.ts +25 -0
  60. package/types/layouts/PropsPanel.vue.d.ts +245 -0
  61. package/types/layouts/Resizer.vue.d.ts +12 -0
  62. package/types/layouts/sidebar/ComponentListPanel.vue.d.ts +14 -0
  63. package/types/layouts/sidebar/LayerMenu.vue.d.ts +100 -0
  64. package/types/layouts/sidebar/LayerPanel.vue.d.ts +1099 -0
  65. package/{dist/types/src → types}/layouts/sidebar/Sidebar.vue.d.ts +3 -5
  66. package/types/layouts/sidebar/TabPane.vue.d.ts +14 -0
  67. package/types/layouts/workspace/PageBar.vue.d.ts +54 -0
  68. package/types/layouts/workspace/PageBarScrollContainer.vue.d.ts +48 -0
  69. package/types/layouts/workspace/Stage.vue.d.ts +46 -0
  70. package/types/layouts/workspace/ViewerMenu.vue.d.ts +88 -0
  71. package/types/layouts/workspace/Workspace.vue.d.ts +6 -0
  72. package/{dist/types/src → types}/services/BaseService.d.ts +0 -0
  73. package/types/services/componentList.d.ts +14 -0
  74. package/{dist/types/src → types}/services/editor.d.ts +27 -14
  75. package/{dist/types/src → types}/services/events.d.ts +0 -0
  76. package/{dist/types/src → types}/services/history.d.ts +0 -0
  77. package/{dist/types/src → types}/services/props.d.ts +26 -2
  78. package/types/services/storage.d.ts +56 -0
  79. package/{dist/types/src → types}/services/ui.d.ts +1 -1
  80. package/{dist/types/src → types}/type.d.ts +21 -1
  81. package/{dist/types/src → types}/utils/compose.d.ts +1 -1
  82. package/{dist/types/src → types}/utils/config.d.ts +0 -0
  83. package/{dist/types/src → types}/utils/editor.d.ts +11 -4
  84. package/{dist/types/src → types}/utils/index.d.ts +0 -0
  85. package/{dist/types/src → types}/utils/logger.d.ts +0 -0
  86. package/types/utils/operator.d.ts +21 -0
  87. package/{dist/types/src → types}/utils/polyfills.d.ts +0 -0
  88. package/{dist/types/src → types}/utils/props.d.ts +2 -22
  89. package/{dist/types/src → types}/utils/scroll-viewer.d.ts +0 -0
  90. package/{dist/types/src → types}/utils/undo-redo.d.ts +0 -0
  91. package/dist/tmagic-editor.es.js.map +0 -1
  92. package/dist/types/src/components/Icon.vue.d.ts +0 -14
  93. package/dist/types/src/components/ScrollViewer.vue.d.ts +0 -24
  94. package/dist/types/src/fields/Code.vue.d.ts +0 -25
  95. package/dist/types/src/layouts/AddPageBox.vue.d.ts +0 -5
  96. package/dist/types/src/layouts/Framework.vue.d.ts +0 -24
  97. package/dist/types/src/layouts/NavMenu.vue.d.ts +0 -27
  98. package/dist/types/src/layouts/PropsPanel.vue.d.ts +0 -13
  99. package/dist/types/src/layouts/Resizer.vue.d.ts +0 -14
  100. package/dist/types/src/layouts/sidebar/ComponentListPanel.vue.d.ts +0 -14
  101. package/dist/types/src/layouts/sidebar/TabPane.vue.d.ts +0 -16
  102. package/dist/types/src/layouts/workspace/Workspace.vue.d.ts +0 -8
  103. package/dist/types/src/shims-vue.d.ts +0 -6
  104. package/dist/types/src/vite-env.d.ts +0 -1
  105. package/src/vite-env.d.ts +0 -1
@@ -15,30 +15,26 @@
15
15
  @dragover="dragoverHandler"
16
16
  ></div>
17
17
  <teleport to="body">
18
- <viewer-menu ref="menu"></viewer-menu>
18
+ <viewer-menu ref="menu" :is-multi-select="isMultiSelect"></viewer-menu>
19
19
  </teleport>
20
20
  </scroll-viewer>
21
21
  </template>
22
22
 
23
- <script lang="ts">
24
- import {
25
- computed,
26
- defineComponent,
27
- inject,
28
- markRaw,
29
- onMounted,
30
- onUnmounted,
31
- ref,
32
- toRaw,
33
- watch,
34
- watchEffect,
35
- } from 'vue';
23
+ <script lang="ts" setup>
24
+ import { computed, inject, markRaw, onMounted, onUnmounted, ref, toRaw, watch, watchEffect } from 'vue';
36
25
  import { cloneDeep } from 'lodash-es';
37
26
 
38
- import type { MApp, MNode, MPage } from '@tmagic/schema';
39
- import StageCore, { GuidesType, Runtime, SortEventData, UpdateEventData } from '@tmagic/stage';
40
-
41
- import ScrollViewer from '@editor/components/ScrollViewer.vue';
27
+ import type { MApp, MContainer, MNode, MPage } from '@tmagic/schema';
28
+ import StageCore, {
29
+ calcValueByFontsize,
30
+ getOffset,
31
+ GuidesType,
32
+ Runtime,
33
+ SortEventData,
34
+ UpdateEventData,
35
+ } from '@tmagic/stage';
36
+
37
+ import ScrollViewer from '../../components/ScrollViewer.vue';
42
38
  import {
43
39
  H_GUIDE_LINE_STORAGE_KEY,
44
40
  Layout,
@@ -46,187 +42,211 @@ import {
46
42
  StageOptions,
47
43
  StageRect,
48
44
  V_GUIDE_LINE_STORAGE_KEY,
49
- } from '@editor/type';
50
- import { getGuideLineFromCache } from '@editor/utils';
45
+ } from '../../type';
46
+ import { getGuideLineFromCache } from '../../utils';
51
47
 
52
48
  import ViewerMenu from './ViewerMenu.vue';
53
49
 
54
- export default defineComponent({
55
- name: 'magic-stage',
56
-
57
- components: {
58
- ViewerMenu,
59
- ScrollViewer,
60
- },
61
-
62
- setup() {
63
- const services = inject<Services>('services');
64
- const stageOptions = inject<StageOptions>('stageOptions');
65
-
66
- const stageWrap = ref<InstanceType<typeof ScrollViewer>>();
67
- const stageContainer = ref<HTMLDivElement>();
68
- const menu = ref<InstanceType<typeof ViewerMenu>>();
69
-
70
- const stageRect = computed(() => services?.uiService.get<StageRect>('stageRect'));
71
- const uiSelectMode = computed(() => services?.uiService.get<boolean>('uiSelectMode'));
72
- const root = computed(() => services?.editorService.get<MApp>('root'));
73
- const page = computed(() => services?.editorService.get<MPage>('page'));
74
- const zoom = computed(() => services?.uiService.get<number>('zoom') || 1);
75
- const node = computed(() => services?.editorService.get<MNode>('node'));
76
-
77
- let stage: StageCore | null = null;
78
- let runtime: Runtime | null = null;
79
-
80
- const getGuideLineKey = (key: string) => `${key}_${root.value?.id}_${page.value?.id}`;
81
-
82
- watchEffect(() => {
83
- if (stage) return;
84
-
85
- if (!stageContainer.value) return;
86
- if (!(stageOptions?.runtimeUrl || stageOptions?.render) || !root.value) return;
87
-
88
- stage = new StageCore({
89
- render: stageOptions.render,
90
- runtimeUrl: stageOptions.runtimeUrl,
91
- zoom: zoom.value,
92
- autoScrollIntoView: stageOptions.autoScrollIntoView,
93
- canSelect: (el, event, stop) => {
94
- const elCanSelect = stageOptions.canSelect(el);
95
- // 在组件联动过程中不能再往下选择,返回并触发 ui-select
96
- if (uiSelectMode.value && elCanSelect && event.type === 'mousedown') {
97
- document.dispatchEvent(new CustomEvent('ui-select', { detail: el }));
98
- return stop();
99
- }
100
-
101
- return elCanSelect;
102
- },
103
- moveableOptions: stageOptions.moveableOptions,
104
- updateDragEl: stageOptions.updateDragEl,
105
- });
106
-
107
- services?.editorService.set('stage', markRaw(stage));
108
-
109
- stage?.mount(stageContainer.value);
110
-
111
- stage.mask.setGuides([
112
- getGuideLineFromCache(getGuideLineKey(H_GUIDE_LINE_STORAGE_KEY)),
113
- getGuideLineFromCache(getGuideLineKey(V_GUIDE_LINE_STORAGE_KEY)),
114
- ]);
115
-
116
- stage?.on('select', (el: HTMLElement) => {
117
- services?.editorService.select(el.id);
118
- });
119
-
120
- stage?.on('highlight', (el: HTMLElement) => {
121
- services?.editorService.highlight(el.id);
122
- });
123
-
124
- stage?.on('update', (ev: UpdateEventData) => {
125
- services?.editorService.update({ id: ev.el.id, style: ev.style });
126
- });
127
-
128
- stage?.on('sort', (ev: SortEventData) => {
129
- services?.editorService.sort(ev.src, ev.dist);
130
- });
131
-
132
- stage?.on('changeGuides', (e) => {
133
- services?.uiService.set('showGuides', true);
134
-
135
- if (!root.value || !page.value) return;
136
-
137
- const storageKey = getGuideLineKey(
138
- e.type === GuidesType.HORIZONTAL ? H_GUIDE_LINE_STORAGE_KEY : V_GUIDE_LINE_STORAGE_KEY,
139
- );
140
- if (e.guides.length) {
141
- globalThis.localStorage.setItem(storageKey, JSON.stringify(e.guides));
142
- } else {
143
- globalThis.localStorage.removeItem(storageKey);
144
- }
145
- });
146
-
147
- if (!node.value?.id) return;
148
- stage?.on('runtime-ready', (rt) => {
149
- runtime = rt;
150
- // toRaw返回的值是一个引用而非快照,需要cloneDeep
151
- root.value && runtime?.updateRootConfig?.(cloneDeep(toRaw(root.value)));
152
- page.value?.id && runtime?.updatePageId?.(page.value.id);
153
- setTimeout(() => {
154
- node.value && stage?.select(toRaw(node.value.id));
155
- });
156
- });
157
- });
50
+ let stage: StageCore | null = null;
51
+ let runtime: Runtime | null = null;
52
+
53
+ const services = inject<Services>('services');
54
+ const stageOptions = inject<StageOptions>('stageOptions');
55
+
56
+ const stageWrap = ref<InstanceType<typeof ScrollViewer>>();
57
+ const stageContainer = ref<HTMLDivElement>();
58
+ const menu = ref<InstanceType<typeof ViewerMenu>>();
59
+
60
+ const isMultiSelect = computed(() => services?.editorService.get('nodes')?.length > 1);
61
+ const stageRect = computed(() => services?.uiService.get<StageRect>('stageRect'));
62
+ const uiSelectMode = computed(() => services?.uiService.get<boolean>('uiSelectMode'));
63
+ const root = computed(() => services?.editorService.get<MApp>('root'));
64
+ const page = computed(() => services?.editorService.get<MPage>('page'));
65
+ const zoom = computed(() => services?.uiService.get<number>('zoom') || 1);
66
+ const node = computed(() => services?.editorService.get<MNode>('node'));
67
+
68
+ const getGuideLineKey = (key: string) => `${key}_${root.value?.id}_${page.value?.id}`;
69
+
70
+ watchEffect(() => {
71
+ if (stage) return;
72
+
73
+ if (!stageContainer.value) return;
74
+ if (!(stageOptions?.runtimeUrl || stageOptions?.render) || !root.value) return;
75
+
76
+ stage = new StageCore({
77
+ render: stageOptions.render,
78
+ runtimeUrl: stageOptions.runtimeUrl,
79
+ zoom: zoom.value,
80
+ autoScrollIntoView: stageOptions.autoScrollIntoView,
81
+ isContainer: stageOptions.isContainer,
82
+ containerHighlightClassName: stageOptions.containerHighlightClassName,
83
+ containerHighlightDuration: stageOptions.containerHighlightDuration,
84
+ containerHighlightType: stageOptions.containerHighlightType,
85
+ canSelect: (el, event, stop) => {
86
+ const elCanSelect = stageOptions.canSelect(el);
87
+ // 在组件联动过程中不能再往下选择,返回并触发 ui-select
88
+ if (uiSelectMode.value && elCanSelect && event.type === 'mousedown') {
89
+ document.dispatchEvent(new CustomEvent('ui-select', { detail: el }));
90
+ return stop();
91
+ }
158
92
 
159
- watch(zoom, (zoom) => {
160
- if (!stage || !zoom) return;
161
- stage.setZoom(zoom);
162
- });
93
+ return elCanSelect;
94
+ },
95
+ moveableOptions: stageOptions.moveableOptions,
96
+ updateDragEl: stageOptions.updateDragEl,
97
+ });
163
98
 
164
- watch(root, (root) => {
165
- if (runtime && root) {
166
- runtime.updateRootConfig?.(cloneDeep(toRaw(root)));
167
- }
168
- });
99
+ services?.editorService.set('stage', markRaw(stage));
169
100
 
170
- const resizeObserver = new ResizeObserver((entries) => {
171
- for (const { contentRect } of entries) {
172
- services?.uiService.set('stageContainerRect', {
173
- width: contentRect.width,
174
- height: contentRect.height,
175
- });
101
+ stage?.mount(stageContainer.value);
102
+
103
+ stage.mask.setGuides([
104
+ getGuideLineFromCache(getGuideLineKey(H_GUIDE_LINE_STORAGE_KEY)),
105
+ getGuideLineFromCache(getGuideLineKey(V_GUIDE_LINE_STORAGE_KEY)),
106
+ ]);
107
+
108
+ stage?.on('select', (el: HTMLElement) => {
109
+ services?.editorService.select(el.id);
110
+ });
111
+
112
+ stage?.on('highlight', (el: HTMLElement) => {
113
+ services?.editorService.highlight(el.id);
114
+ });
115
+
116
+ stage?.on('multiSelect', (els: HTMLElement[]) => {
117
+ services?.editorService.multiSelect(els.map((el) => el.id));
118
+ });
119
+
120
+ stage?.on('update', (ev: UpdateEventData) => {
121
+ if (ev.parentEl) {
122
+ for (const data of ev.data) {
123
+ services?.editorService.moveToContainer({ id: data.el.id, style: data.style }, ev.parentEl.id);
176
124
  }
125
+ return;
126
+ }
127
+
128
+ services?.editorService.update(ev.data.map((data) => ({ id: data.el.id, style: data.style })));
129
+ });
130
+
131
+ stage?.on('sort', (ev: SortEventData) => {
132
+ services?.editorService.sort(ev.src, ev.dist);
133
+ });
134
+
135
+ stage?.on('changeGuides', (e) => {
136
+ services?.uiService.set('showGuides', true);
137
+
138
+ if (!root.value || !page.value) return;
139
+
140
+ const storageKey = getGuideLineKey(
141
+ e.type === GuidesType.HORIZONTAL ? H_GUIDE_LINE_STORAGE_KEY : V_GUIDE_LINE_STORAGE_KEY,
142
+ );
143
+ if (e.guides.length) {
144
+ globalThis.localStorage.setItem(storageKey, JSON.stringify(e.guides));
145
+ } else {
146
+ globalThis.localStorage.removeItem(storageKey);
147
+ }
148
+ });
149
+
150
+ if (!node.value?.id) return;
151
+ stage?.on('runtime-ready', (rt) => {
152
+ runtime = rt;
153
+ // toRaw返回的值是一个引用而非快照,需要cloneDeep
154
+ root.value && runtime?.updateRootConfig?.(cloneDeep(toRaw(root.value)));
155
+ page.value?.id && runtime?.updatePageId?.(page.value.id);
156
+ setTimeout(() => {
157
+ node.value && stage?.select(toRaw(node.value.id));
177
158
  });
159
+ });
160
+ });
178
161
 
179
- onMounted(() => {
180
- stageWrap.value?.container && resizeObserver.observe(stageWrap.value.container);
181
- });
162
+ watch(zoom, (zoom) => {
163
+ if (!stage || !zoom) return;
164
+ stage.setZoom(zoom);
165
+ });
166
+
167
+ watch(root, (root) => {
168
+ if (runtime && root) {
169
+ runtime.updateRootConfig?.(cloneDeep(toRaw(root)));
170
+ }
171
+ });
182
172
 
183
- onUnmounted(() => {
184
- stage?.destroy();
185
- resizeObserver.disconnect();
186
- services?.editorService.set('stage', null);
173
+ const resizeObserver = new ResizeObserver((entries) => {
174
+ for (const { contentRect } of entries) {
175
+ services?.uiService.set('stageContainerRect', {
176
+ width: contentRect.width,
177
+ height: contentRect.height,
187
178
  });
179
+ }
180
+ });
188
181
 
189
- return {
190
- stageWrap,
191
- stageContainer,
192
- menu,
193
- stageRect,
194
- zoom,
195
-
196
- contextmenuHandler(e: MouseEvent) {
197
- e.preventDefault();
198
- menu.value?.show(e);
199
- },
200
-
201
- dragoverHandler(e: DragEvent) {
202
- e.preventDefault();
203
- if (e.dataTransfer) {
204
- e.dataTransfer.dropEffect = 'move';
205
- }
206
- },
207
-
208
- async dropHandler(e: DragEvent) {
209
- e.preventDefault();
210
- if (e.dataTransfer && page.value && stageContainer.value && stage) {
211
- // eslint-disable-next-line no-eval
212
- const config = eval(`(${e.dataTransfer.getData('data')})`);
213
- const layout = await services?.editorService.getLayout(page.value);
214
-
215
- const containerRect = stageContainer.value.getBoundingClientRect();
216
- const { scrollTop, scrollLeft } = stage.mask;
217
- if (layout === Layout.ABSOLUTE) {
218
- config.style = {
219
- ...(config.style || {}),
220
- position: 'absolute',
221
- top: e.clientY - containerRect.top + scrollTop,
222
- left: e.clientX - containerRect.left + scrollLeft,
223
- };
224
- }
225
-
226
- services?.editorService.add(config, page.value);
227
- }
228
- },
229
- };
230
- },
182
+ onMounted(() => {
183
+ stageWrap.value?.container && resizeObserver.observe(stageWrap.value.container);
184
+ });
185
+
186
+ onUnmounted(() => {
187
+ stage?.destroy();
188
+ resizeObserver.disconnect();
189
+ services?.editorService.set('stage', null);
231
190
  });
191
+
192
+ const contextmenuHandler = (e: MouseEvent) => {
193
+ e.preventDefault();
194
+ menu.value?.show(e);
195
+ };
196
+
197
+ const dragoverHandler = (e: DragEvent) => {
198
+ e.preventDefault();
199
+ if (e.dataTransfer) {
200
+ e.dataTransfer.dropEffect = 'move';
201
+ }
202
+ };
203
+
204
+ const dropHandler = async (e: DragEvent) => {
205
+ e.preventDefault();
206
+
207
+ const doc = stage?.renderer.contentWindow?.document;
208
+ const parentEl: HTMLElement | null | undefined = doc?.querySelector(`.${stageOptions?.containerHighlightClassName}`);
209
+
210
+ let parent: MContainer | undefined = page.value;
211
+ if (parentEl) {
212
+ parent = services?.editorService.getNodeById(parentEl.id, false) as MContainer;
213
+ }
214
+
215
+ if (e.dataTransfer && parent && stageContainer.value && stage) {
216
+ // eslint-disable-next-line no-eval
217
+ const config = eval(`(${e.dataTransfer.getData('data')})`);
218
+ const layout = await services?.editorService.getLayout(parent);
219
+
220
+ const containerRect = stageContainer.value.getBoundingClientRect();
221
+ const { scrollTop, scrollLeft } = stage.mask;
222
+ const { style = {} } = config;
223
+
224
+ let top = 0;
225
+ let left = 0;
226
+ let position = 'relative';
227
+
228
+ if (layout === Layout.ABSOLUTE) {
229
+ position = 'absolute';
230
+ top = e.clientY - containerRect.top + scrollTop;
231
+ left = e.clientX - containerRect.left + scrollLeft;
232
+
233
+ if (parentEl && doc) {
234
+ const { left: parentLeft, top: parentTop } = getOffset(parentEl);
235
+ left = left - calcValueByFontsize(doc, parentLeft);
236
+ top = top - calcValueByFontsize(doc, parentTop);
237
+ }
238
+ }
239
+
240
+ config.style = {
241
+ ...style,
242
+ position,
243
+ top,
244
+ left,
245
+ };
246
+
247
+ config.inputEvent = e;
248
+
249
+ services?.editorService.add(config, parent);
250
+ }
251
+ };
232
252
  </script>