@tmagic/editor 1.0.0-beta.1 → 1.0.0-beta.12

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 (53) hide show
  1. package/LICENSE +5432 -0
  2. package/README.md +1 -0
  3. package/dist/style.css +53 -24
  4. package/dist/tmagic-editor.es.js +901 -412
  5. package/dist/tmagic-editor.es.js.map +1 -1
  6. package/dist/tmagic-editor.umd.js +918 -412
  7. package/dist/tmagic-editor.umd.js.map +1 -1
  8. package/dist/types/src/Editor.vue.d.ts +5 -5
  9. package/dist/types/src/components/ScrollViewer.vue.d.ts +23 -0
  10. package/dist/types/src/layouts/CodeEditor.vue.d.ts +5 -4
  11. package/dist/types/src/layouts/NavMenu.vue.d.ts +2 -1
  12. package/dist/types/src/layouts/sidebar/ComponentListPanel.vue.d.ts +1 -1
  13. package/dist/types/src/layouts/sidebar/LayerPanel.vue.d.ts +10 -3
  14. package/dist/types/src/layouts/workspace/PageBar.vue.d.ts +8 -3
  15. package/dist/types/src/layouts/workspace/Stage.vue.d.ts +77 -42
  16. package/dist/types/src/layouts/workspace/Workspace.vue.d.ts +4 -10
  17. package/dist/types/src/services/BaseService.d.ts +4 -1
  18. package/dist/types/src/services/editor.d.ts +11 -4
  19. package/dist/types/src/services/props.d.ts +1 -1
  20. package/dist/types/src/services/ui.d.ts +10 -3
  21. package/dist/types/src/type.d.ts +23 -7
  22. package/dist/types/src/utils/editor.d.ts +3 -3
  23. package/dist/types/src/utils/scroll-viewer.d.ts +35 -0
  24. package/package.json +25 -12
  25. package/src/Editor.vue +5 -5
  26. package/src/components/ScrollViewer.vue +66 -0
  27. package/src/components/ToolButton.vue +5 -3
  28. package/src/layouts/AddPageBox.vue +3 -1
  29. package/src/layouts/CodeEditor.vue +35 -59
  30. package/src/layouts/NavMenu.vue +7 -3
  31. package/src/layouts/PropsPanel.vue +6 -10
  32. package/src/layouts/sidebar/ComponentListPanel.vue +2 -2
  33. package/src/layouts/sidebar/LayerMenu.vue +15 -39
  34. package/src/layouts/sidebar/LayerPanel.vue +63 -16
  35. package/src/layouts/workspace/PageBar.vue +113 -14
  36. package/src/layouts/workspace/Stage.vue +67 -61
  37. package/src/layouts/workspace/ViewerMenu.vue +5 -3
  38. package/src/layouts/workspace/Workspace.vue +45 -34
  39. package/src/services/BaseService.ts +70 -22
  40. package/src/services/editor.ts +111 -55
  41. package/src/services/props.ts +2 -1
  42. package/src/services/ui.ts +42 -5
  43. package/src/theme/common/var.scss +2 -2
  44. package/src/theme/layer-panel.scss +9 -0
  45. package/src/theme/nav-menu.scss +3 -3
  46. package/src/theme/page-bar.scss +21 -2
  47. package/src/theme/props-panel.scss +8 -0
  48. package/src/theme/stage.scss +8 -7
  49. package/src/type.ts +26 -7
  50. package/src/utils/editor.ts +30 -27
  51. package/src/utils/props.ts +1 -1
  52. package/src/utils/scroll-viewer.ts +216 -0
  53. package/dist/types/src/layouts/sidebar/LayerMenu.vue.d.ts +0 -31
@@ -16,10 +16,12 @@
16
16
  * limitations under the License.
17
17
  */
18
18
 
19
- import { cloneDeep, random } from 'lodash-es';
19
+ import { random } from 'lodash-es';
20
20
 
21
- import { Id, MApp, MContainer, MNode, MPage } from '@tmagic/schema';
22
- import { getNodePath, isPop } from '@tmagic/utils';
21
+ import type { Id, MApp, MContainer, MNode, MPage } from '@tmagic/schema';
22
+ import { NodeType } from '@tmagic/schema';
23
+ import type StageCore from '@tmagic/stage';
24
+ import { getNodePath, isNumber, isPage, isPop } from '@tmagic/utils';
23
25
 
24
26
  import { Layout } from '@editor/type';
25
27
 
@@ -34,7 +36,7 @@ export const generateId = (type: string | number): string => `${type}_${random(1
34
36
  */
35
37
  export const getPageList = (app: MApp): MPage[] => {
36
38
  if (app.items && Array.isArray(app.items)) {
37
- return app.items.filter((item: MPage) => item.type === 'page');
39
+ return app.items.filter((item: MPage) => item.type === NodeType.PAGE);
38
40
  }
39
41
  return [];
40
42
  };
@@ -104,11 +106,11 @@ const updatePopId = (oldId: Id, popId: Id, pageConfig: MPage) => {
104
106
  export const setNewItemId = (config: MNode, parent?: MPage) => {
105
107
  const oldId = config.id;
106
108
 
107
- config.id = generateId(config.type);
109
+ config.id = generateId(config.type || 'component');
108
110
  config.name = `${config.name?.replace(/_(\d+)$/, '')}_${config.id}`;
109
111
 
110
112
  // 只有弹窗在页面下的一级子元素才有效
111
- if (isPop(config) && parent?.type === 'page') {
113
+ if (isPop(config) && parent?.type === NodeType.PAGE) {
112
114
  updatePopId(oldId, config.id, parent);
113
115
  }
114
116
 
@@ -138,11 +140,29 @@ export const toRelative = (node: MNode) => {
138
140
  return node;
139
141
  };
140
142
 
141
- export const initPosition = (node: MNode, layout: Layout) => {
143
+ const setTop2Middle = (node: MNode, parentNode: MNode, stage: StageCore) => {
144
+ const style = node.style || {};
145
+ const height = style.height || 0;
146
+
147
+ if (!stage || style.top || !parentNode.style || !isNumber(height)) return style;
148
+
149
+ const { height: parentHeight } = parentNode.style;
150
+
151
+ if (isPage(parentNode)) {
152
+ const { scrollTop = 0, wrapperHeight } = stage.mask;
153
+ style.top = (wrapperHeight - height) / 2 + scrollTop;
154
+ } else {
155
+ style.top = (parentHeight - height) / 2;
156
+ }
157
+
158
+ return style;
159
+ };
160
+
161
+ export const initPosition = (node: MNode, layout: Layout, parentNode: MNode, stage: StageCore) => {
142
162
  if (layout === Layout.ABSOLUTE) {
143
163
  node.style = {
144
164
  position: 'absolute',
145
- ...(node.style || {}),
165
+ ...setTop2Middle(node, parentNode, stage),
146
166
  };
147
167
  return node;
148
168
  }
@@ -199,6 +219,8 @@ export const Fixed2Other = async (node: MNode, root: MApp, getLayout: (node: MNo
199
219
  const offset = {
200
220
  left: cur?.style?.left || 0,
201
221
  top: cur?.style?.top || 0,
222
+ right: '',
223
+ bottom: '',
202
224
  };
203
225
 
204
226
  path.forEach((value) => {
@@ -223,22 +245,3 @@ export const Fixed2Other = async (node: MNode, root: MApp, getLayout: (node: MNo
223
245
 
224
246
  return toRelative(node);
225
247
  };
226
-
227
- export const defaults = (object: any, source: any) => {
228
- let o = source;
229
- if (Array.isArray(object)) {
230
- o = object;
231
- }
232
-
233
- Object.entries(o).forEach(([key, value]: [string, any]) => {
234
- if (typeof object[key] === 'undefined') {
235
- object[key] = value;
236
- return;
237
- }
238
-
239
- if (value && typeof value !== 'string' && Object.keys(value).length) {
240
- object[key] = defaults(cloneDeep(object[key]), value);
241
- }
242
- });
243
- return object;
244
- };
@@ -174,7 +174,7 @@ export const fillConfig = (config: FormConfig = []) => [
174
174
  type: 'select',
175
175
  options: (mForm: FormState, { model }: any) => {
176
176
  const node = editorService.getNodeById(model.to);
177
- if (!node) return [];
177
+ if (!node?.type) return [];
178
178
 
179
179
  return eventsService.getMethod(node.type).map((option) => ({
180
180
  text: option.label,
@@ -0,0 +1,216 @@
1
+ import { Keys } from '@editor/type';
2
+
3
+ interface ScrollViewerOptions {
4
+ container: HTMLDivElement;
5
+ target: HTMLDivElement;
6
+ zoom: number;
7
+ }
8
+
9
+ export class ScrollViewer {
10
+ private enter = false;
11
+ private targetEnter = false;
12
+ private keydown = false;
13
+ private container: HTMLDivElement;
14
+ private target: HTMLDivElement;
15
+ private zoom = 1;
16
+
17
+ private scrollLeft = 0;
18
+ private scrollTop = 0;
19
+
20
+ private x = 0;
21
+ private y = 0;
22
+
23
+ private resizeObserver = new ResizeObserver((entries) => {
24
+ for (const { contentRect } of entries) {
25
+ const { width, height } = contentRect;
26
+ const targetRect = this.target.getBoundingClientRect();
27
+ const targetWidth = targetRect.width * this.zoom;
28
+ const targetMarginTop = Number(this.target.style.marginTop) || 0;
29
+ const targetHeight = (targetRect.height + targetMarginTop) * this.zoom;
30
+
31
+ if (targetWidth < width) {
32
+ (this.target as any)._left = 0;
33
+ }
34
+ if (targetHeight < height) {
35
+ (this.target as any)._top = 0;
36
+ }
37
+
38
+ this.scroll();
39
+ }
40
+ });
41
+
42
+ constructor(options: ScrollViewerOptions) {
43
+ this.container = options.container;
44
+ this.target = options.target;
45
+ this.zoom = options.zoom;
46
+
47
+ globalThis.addEventListener('keydown', this.keydownHandler);
48
+ globalThis.addEventListener('keyup', this.keyupHandler);
49
+
50
+ this.container.addEventListener('mouseenter', this.mouseEnterHandler);
51
+ this.container.addEventListener('mouseleave', this.mouseLeaveHandler);
52
+ this.target.addEventListener('mouseenter', this.targetMouseEnterHandler);
53
+ this.target.addEventListener('mouseleave', this.targetMouseLeaveHandler);
54
+
55
+ this.container.addEventListener('wheel', this.wheelHandler);
56
+
57
+ this.resizeObserver.observe(this.container);
58
+ }
59
+
60
+ public destroy() {
61
+ this.resizeObserver.disconnect();
62
+
63
+ this.container.removeEventListener('mouseenter', this.mouseEnterHandler);
64
+ this.container.removeEventListener('mouseleave', this.mouseLeaveHandler);
65
+ this.target.removeEventListener('mouseenter', this.targetMouseEnterHandler);
66
+ this.target.removeEventListener('mouseleave', this.targetMouseLeaveHandler);
67
+ globalThis.removeEventListener('keydown', this.keydownHandler);
68
+ globalThis.removeEventListener('keyup', this.keyupHandler);
69
+ }
70
+
71
+ public setZoom(zoom: number) {
72
+ this.zoom = zoom;
73
+ }
74
+
75
+ private scroll() {
76
+ const scrollLeft = (this.target as any)._left;
77
+ const scrollTop = (this.target as any)._top;
78
+
79
+ this.target.style.transform = `translate(${scrollLeft}px, ${scrollTop}px)`;
80
+ }
81
+
82
+ private removeHandler() {
83
+ this.target.style.cursor = '';
84
+ this.target.removeEventListener('mousedown', this.mousedownHandler);
85
+ document.removeEventListener('mousemove', this.mousemoveHandler);
86
+ document.removeEventListener('mouseup', this.mouseupHandler);
87
+ }
88
+
89
+ private wheelHandler = (event: WheelEvent) => {
90
+ if (this.targetEnter) return;
91
+
92
+ const { deltaX, deltaY, currentTarget } = event;
93
+
94
+ if (currentTarget !== this.container) return;
95
+
96
+ this.setScrollOffset(deltaX, deltaY);
97
+ this.scroll();
98
+ this.scrollLeft = (this.target as any)._left;
99
+ this.scrollTop = (this.target as any)._top;
100
+ };
101
+
102
+ private mouseEnterHandler = () => {
103
+ this.enter = true;
104
+ };
105
+
106
+ private mouseLeaveHandler = () => {
107
+ this.enter = false;
108
+ };
109
+
110
+ private targetMouseEnterHandler = () => {
111
+ this.targetEnter = true;
112
+ };
113
+
114
+ private targetMouseLeaveHandler = () => {
115
+ this.targetEnter = false;
116
+ };
117
+
118
+ private mousedownHandler = (event: MouseEvent) => {
119
+ if (!this.keydown) return;
120
+
121
+ event.stopImmediatePropagation();
122
+ event.stopPropagation();
123
+
124
+ this.target.style.cursor = 'grabbing';
125
+
126
+ this.x = event.clientX;
127
+ this.y = event.clientY;
128
+
129
+ document.addEventListener('mousemove', this.mousemoveHandler);
130
+ document.addEventListener('mouseup', this.mouseupHandler);
131
+ };
132
+
133
+ private mouseupHandler = () => {
134
+ this.x = 0;
135
+ this.y = 0;
136
+
137
+ this.scrollLeft = (this.target as any)._left;
138
+ this.scrollTop = (this.target as any)._top;
139
+ this.removeHandler();
140
+ };
141
+
142
+ private mousemoveHandler = (event: MouseEvent) => {
143
+ event.stopImmediatePropagation();
144
+ event.stopPropagation();
145
+
146
+ const deltaX = event.clientX - this.x;
147
+ const deltaY = event.clientY - this.y;
148
+
149
+ this.setScrollOffset(deltaX, deltaY);
150
+ this.scroll();
151
+ };
152
+
153
+ private keydownHandler = (event: KeyboardEvent) => {
154
+ if (event.code === Keys.ESCAPE && this.enter) {
155
+ event.preventDefault();
156
+ event.stopImmediatePropagation();
157
+ event.stopPropagation();
158
+ }
159
+
160
+ if (event.code !== Keys.ESCAPE || !this.enter || this.keydown) {
161
+ return;
162
+ }
163
+
164
+ this.keydown = true;
165
+
166
+ this.target.style.cursor = 'grab';
167
+ this.container.addEventListener('mousedown', this.mousedownHandler);
168
+ };
169
+
170
+ private keyupHandler = (event: KeyboardEvent) => {
171
+ if (event.code !== Keys.ESCAPE || !this.keydown) {
172
+ return;
173
+ }
174
+
175
+ event.preventDefault();
176
+ event.stopImmediatePropagation();
177
+ event.stopPropagation();
178
+
179
+ this.keydown = false;
180
+
181
+ event.preventDefault();
182
+
183
+ this.removeHandler();
184
+ };
185
+
186
+ private setScrollOffset(deltaX: number, deltaY: number) {
187
+ const { width, height } = this.container.getBoundingClientRect();
188
+ const targetRect = this.target.getBoundingClientRect();
189
+
190
+ const targetWidth = targetRect.width * this.zoom;
191
+ const targetHeight = targetRect.height * this.zoom;
192
+
193
+ let y = 0;
194
+
195
+ if (targetHeight > height) {
196
+ if (deltaY > 0) {
197
+ y = this.scrollTop + Math.min(targetHeight - height - this.scrollTop, deltaY);
198
+ } else {
199
+ y = this.scrollTop + Math.max(-(targetHeight - height + this.scrollTop), deltaY);
200
+ }
201
+ }
202
+
203
+ let x = 0;
204
+
205
+ if (targetWidth > width) {
206
+ if (deltaX > 0) {
207
+ x = this.scrollLeft + Math.min(targetWidth - width - this.scrollLeft, deltaX);
208
+ } else {
209
+ x = this.scrollLeft + Math.max(-(targetWidth - width + this.scrollLeft), deltaX);
210
+ }
211
+ }
212
+
213
+ (this.target as any)._left = x;
214
+ (this.target as any)._top = y;
215
+ }
216
+ }
@@ -1,31 +0,0 @@
1
- import type { MNode } from '@tmagic/schema';
2
- import type { DefineComponent, Ref, ComputedRef, ComponentOptionsMixin, VNodeProps, AllowedComponentProps, ComponentCustomProps, ExtractPropTypes, PropType } from 'vue';
3
- import type { ComponentGroup } from '../../type';
4
- declare const _default: DefineComponent<{
5
- componentGroupList: {
6
- type: PropType<ComponentGroup[]>;
7
- default: () => never[];
8
- };
9
- }, {
10
- subVisible: Ref<boolean>;
11
- node: ComputedRef<MNode | undefined>;
12
- menu: ComputedRef<{
13
- app: {
14
- type: string;
15
- text: string;
16
- }[];
17
- component: ComponentGroup[];
18
- }>;
19
- append(config: any): void;
20
- remove(): void;
21
- copy(node: any): void;
22
- setSubVisiable(v: any): void;
23
- }, unknown, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, Record<string, any>, string, VNodeProps & AllowedComponentProps & ComponentCustomProps, Readonly<ExtractPropTypes<{
24
- componentGroupList: {
25
- type: PropType<ComponentGroup[]>;
26
- default: () => never[];
27
- };
28
- }>>, {
29
- componentGroupList: ComponentGroup[];
30
- }>;
31
- export default _default;