@tmagic/editor 1.0.0-beta.9 → 1.0.0-rc.11

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 (72) hide show
  1. package/README.md +1 -0
  2. package/dist/style.css +72 -36
  3. package/dist/tmagic-editor.es.js +1555 -2080
  4. package/dist/tmagic-editor.es.js.map +1 -1
  5. package/dist/tmagic-editor.umd.js +1555 -2082
  6. package/dist/tmagic-editor.umd.js.map +1 -1
  7. package/dist/types/src/Editor.vue.d.ts +50 -2
  8. package/dist/types/src/fields/Code.vue.d.ts +4 -4
  9. package/dist/types/src/fields/CodeLink.vue.d.ts +1 -3
  10. package/dist/types/src/index.d.ts +1 -0
  11. package/dist/types/src/layouts/CodeEditor.vue.d.ts +13 -4
  12. package/dist/types/src/layouts/Framework.vue.d.ts +15 -3
  13. package/dist/types/src/layouts/PropsPanel.vue.d.ts +4 -5
  14. package/dist/types/src/layouts/sidebar/ComponentListPanel.vue.d.ts +2 -1
  15. package/dist/types/src/layouts/sidebar/Sidebar.vue.d.ts +2 -3
  16. package/dist/types/src/layouts/sidebar/TabPane.vue.d.ts +14 -0
  17. package/dist/types/src/layouts/workspace/Workspace.vue.d.ts +5 -32
  18. package/dist/types/src/services/BaseService.d.ts +5 -2
  19. package/dist/types/src/services/editor.d.ts +11 -5
  20. package/dist/types/src/services/history.d.ts +2 -18
  21. package/dist/types/src/services/props.d.ts +8 -2
  22. package/dist/types/src/services/ui.d.ts +2 -0
  23. package/dist/types/src/type.d.ts +24 -9
  24. package/dist/types/src/utils/editor.d.ts +4 -9
  25. package/dist/types/src/utils/polyfills.d.ts +0 -0
  26. package/dist/types/src/utils/props.d.ts +10 -1
  27. package/package.json +35 -12
  28. package/src/Editor.vue +44 -9
  29. package/src/components/ContentMenu.vue +140 -0
  30. package/src/components/ScrollViewer.vue +1 -1
  31. package/src/components/ToolButton.vue +69 -30
  32. package/src/fields/UISelect.vue +14 -6
  33. package/src/index.ts +2 -0
  34. package/src/layouts/CodeEditor.vue +20 -13
  35. package/src/layouts/Framework.vue +20 -7
  36. package/src/layouts/PropsPanel.vue +5 -4
  37. package/src/layouts/sidebar/ComponentListPanel.vue +25 -3
  38. package/src/layouts/sidebar/LayerMenu.vue +93 -95
  39. package/src/layouts/sidebar/LayerPanel.vue +31 -54
  40. package/src/layouts/sidebar/Sidebar.vue +13 -52
  41. package/src/layouts/sidebar/TabPane.vue +68 -0
  42. package/src/layouts/workspace/PageBar.vue +136 -13
  43. package/src/layouts/workspace/Stage.vue +62 -104
  44. package/src/layouts/workspace/ViewerMenu.vue +119 -67
  45. package/src/layouts/workspace/Workspace.vue +124 -46
  46. package/src/services/BaseService.ts +71 -23
  47. package/src/services/editor.ts +196 -52
  48. package/src/services/history.ts +7 -0
  49. package/src/services/props.ts +64 -9
  50. package/src/services/ui.ts +35 -5
  51. package/src/theme/common/var.scss +1 -0
  52. package/src/theme/component-list-panel.scss +2 -0
  53. package/src/theme/content-menu.scss +33 -26
  54. package/src/theme/layer-panel.scss +2 -1
  55. package/src/theme/nav-menu.scss +6 -2
  56. package/src/theme/page-bar.scss +36 -3
  57. package/src/theme/props-panel.scss +19 -17
  58. package/src/theme/workspace.scss +4 -0
  59. package/src/type.ts +26 -9
  60. package/src/utils/editor.ts +35 -55
  61. package/src/utils/polyfills.ts +8 -0
  62. package/src/utils/props.ts +51 -8
  63. package/LICENSE +0 -5432
  64. package/dist/types/src/components/ToolButton.vue.d.ts +0 -35
  65. package/dist/types/src/fields/UISelect.vue.d.ts +0 -32
  66. package/dist/types/src/layouts/sidebar/LayerMenu.vue.d.ts +0 -31
  67. package/dist/types/src/layouts/sidebar/LayerPanel.vue.d.ts +0 -979
  68. package/dist/types/src/layouts/workspace/PageBar.vue.d.ts +0 -11
  69. package/dist/types/src/layouts/workspace/Stage.vue.d.ts +0 -193
  70. package/dist/types/src/layouts/workspace/ViewerMenu.vue.d.ts +0 -18
  71. package/tsconfig.json +0 -9
  72. package/vite.config.ts +0 -30
@@ -2,38 +2,45 @@
2
2
  position: fixed;
3
3
  font-size: 12px;
4
4
  background: #fff;
5
- color: #333;
6
5
  box-shadow: 0 2px 8px 2px rgba(68, 73, 77, 0.16);
7
6
  z-index: 9999;
8
7
  transform-origin: 0% 0%;
9
8
  font-weight: 600;
10
9
  padding: 4px 0px;
10
+ overflow: auto;
11
+ max-height: 100%;
11
12
 
12
- .separation {
13
- width: 100%;
14
- height: 0;
15
- border-color: rgba(155, 155, 155, 0.1);
16
- }
17
-
18
- .subMenu {
19
- position: absolute;
20
- right: 0;
21
- transform: translate(100%, 0);
22
- background-color: #fff;
13
+ .menu-item {
23
14
  color: #333;
24
- box-shadow: 0 2px 8px 2px rgba(68, 73, 77, 0.16);
25
- top: 0;
26
- height: 223px;
27
- }
28
- }
15
+ display: flex;
16
+ -webkit-box-align: center;
17
+ align-items: center;
18
+ cursor: pointer;
19
+ min-width: 140px;
20
+ transition: all 0.2s ease 0s;
21
+ padding: 5px 14px;
22
+ border-left: 2px solid transparent;
23
+
24
+ .el-button {
25
+ width: 100%;
26
+ justify-content: flex-start;
27
+ }
29
28
 
30
- .magic-editor-content-menu-item {
31
- display: flex;
32
- -webkit-box-align: center;
33
- align-items: center;
34
- cursor: pointer;
35
- min-width: 140px;
36
- transition: all 0.2s ease 0s;
37
- padding: 10px 14px;
38
- border-left: 2px solid transparent;
29
+ .el-button--text,
30
+ i {
31
+ color: $--font-color;
32
+ }
33
+
34
+ &.divider {
35
+ padding: 0 14px;
36
+
37
+ .el-divider {
38
+ margin: 0;
39
+ }
40
+ }
41
+
42
+ &:hover {
43
+ background-color: $--hover-color;
44
+ }
45
+ }
39
46
  }
@@ -52,10 +52,11 @@
52
52
 
53
53
  .magic-editor-layer-panel .cus-tree-node {
54
54
  width: 100%;
55
+ overflow: hidden;
55
56
  }
56
57
 
57
58
  .magic-editor-layer-panel .cus-tree-node-hover {
58
- background-color: #f3f5f9;
59
+ background-color: $--hover-color;
59
60
  width: 100%;
60
61
  }
61
62
 
@@ -43,13 +43,17 @@
43
43
  display: flex !important;
44
44
  transition: all 0.3s ease 0s;
45
45
  border-bottom: 2px solid transparent;
46
- margin: 0 5px;
46
+ margin: 0;
47
47
 
48
48
  .is-disabled {
49
49
  opacity: 0.5;
50
50
  }
51
51
 
52
- .el-button--text,
52
+ .is-text {
53
+ padding: 5px;
54
+ }
55
+
56
+ .is-text,
53
57
  i {
54
58
  color: $--font-color;
55
59
  }
@@ -6,19 +6,26 @@
6
6
  width: 100%;
7
7
  height: $--page-bar-height;
8
8
  line-height: $--page-bar-height;
9
- background-color: #f3f3f3;
10
9
  color: $--font-color;
10
+ background-color: #f3f3f3;
11
11
  border-top: 1px solid $--border-color;
12
12
  z-index: 2;
13
13
  overflow: hidden;
14
14
 
15
- .m-editor-page-bar-item {
15
+ &-items {
16
+ display: flex;
17
+ transition: transform 0.3s;
18
+ }
19
+
20
+ &-item {
16
21
  padding: 0 10px;
17
22
  cursor: pointer;
18
23
  border-right: 1px solid $--border-color;
19
24
  display: flex;
20
25
  justify-items: center;
21
26
  align-items: center;
27
+ background-color: #f3f3f3;
28
+ white-space: nowrap;
22
29
 
23
30
  &.active {
24
31
  background-color: #fff;
@@ -29,7 +36,12 @@
29
36
  }
30
37
  }
31
38
 
32
- .m-editor-page-bar-title {
39
+ &-icon {
40
+ position: relative;
41
+ z-index: 1;
42
+ }
43
+
44
+ &-title {
33
45
  max-width: 150px;
34
46
  text-overflow: ellipsis;
35
47
  white-space: nowrap;
@@ -37,3 +49,24 @@
37
49
  }
38
50
  }
39
51
  }
52
+
53
+ .page-bar-popover {
54
+ &.el-popper.el-popover {
55
+ padding: 10px 0;
56
+ }
57
+
58
+ .menu-item {
59
+ cursor: pointer;
60
+ transition: all 0.2s ease 0s;
61
+ padding: 5px 14px;
62
+
63
+ .el-button--text,
64
+ i {
65
+ color: $--font-color;
66
+ }
67
+
68
+ &:hover {
69
+ background-color: $--hover-color;
70
+ }
71
+ }
72
+ }
@@ -1,31 +1,33 @@
1
1
  .m-editor-props-panel {
2
2
  padding: 0 10px;
3
3
 
4
- .el-form-item__label {
5
- font-size: 12px;
6
- }
7
-
8
- .m-fieldset {
9
- legend {
4
+ &.small {
5
+ .el-form-item__label {
10
6
  font-size: 12px;
11
7
  }
12
- }
13
8
 
14
- .el-tabs__item {
15
- font-size: 12px;
9
+ .m-fieldset {
10
+ legend {
11
+ font-size: 12px;
12
+ }
13
+ }
14
+
15
+ .el-tabs__item {
16
+ font-size: 12px;
17
+ }
16
18
  }
17
19
 
18
- span,
19
- a,
20
- p {
21
- font-size: 12px;
20
+ .el-input__wrapper {
21
+ border-radius: 0;
22
22
  }
23
23
  }
24
24
 
25
25
  .m-editor-props-panel-popper {
26
- span,
27
- a,
28
- p {
29
- font-size: 12px;
26
+ &.small {
27
+ span,
28
+ a,
29
+ p {
30
+ font-size: 12px;
31
+ }
30
32
  }
31
33
  }
@@ -2,4 +2,8 @@
2
2
  height: 100%;
3
3
  width: 100%;
4
4
  user-select: none;
5
+
6
+ &:focus-visible {
7
+ outline: 0;
8
+ }
5
9
  }
package/src/type.ts CHANGED
@@ -21,6 +21,7 @@ import type { Component } from 'vue';
21
21
  import type { FormConfig } from '@tmagic/form';
22
22
  import type { Id, MApp, MContainer, MNode, MPage } from '@tmagic/schema';
23
23
  import type StageCore from '@tmagic/stage';
24
+ import type { MoveableOptions } from '@tmagic/stage';
24
25
 
25
26
  import type { ComponentListService } from '@editor/services/componentList';
26
27
  import type { EditorService } from '@editor/services/editor';
@@ -45,6 +46,15 @@ export interface Services {
45
46
  uiService: UiService;
46
47
  }
47
48
 
49
+ export interface StageOptions {
50
+ runtimeUrl: string;
51
+ autoScrollIntoView: boolean;
52
+ render: () => HTMLDivElement;
53
+ moveableOptions: MoveableOptions | ((core?: StageCore) => MoveableOptions);
54
+ canSelect: (el: HTMLElement) => boolean | Promise<boolean>;
55
+ updateDragEl: (el: HTMLDivElement) => void;
56
+ }
57
+
48
58
  export interface StoreState {
49
59
  root: MApp | null;
50
60
  page: MPage | null;
@@ -53,6 +63,7 @@ export interface StoreState {
53
63
  highlightNode: MNode | null;
54
64
  stage: StageCore | null;
55
65
  modifiedNodeIds: Map<Id, Id>;
66
+ pageLength: number;
56
67
  }
57
68
 
58
69
  export interface PropsState {
@@ -98,6 +109,8 @@ export interface UiState {
98
109
  showGuides: boolean;
99
110
  /** 是否显示标尺,true: 显示,false: 不显示,默认为true */
100
111
  showRule: boolean;
112
+ /** 用于控制该属性配置表单内组件的尺寸 */
113
+ propsPanelSize: 'large' | 'default' | 'small';
101
114
  }
102
115
 
103
116
  export interface EditorNodeInfo {
@@ -125,6 +138,8 @@ export interface MenuButton {
125
138
  * zoom: 放大缩小
126
139
  */
127
140
  type: 'button' | 'dropdown' | 'text' | 'divider' | 'zoom';
141
+ /** 当type为divider时有效,分割线方向, 默认vertical */
142
+ direction?: 'horizontal' | 'vertical';
128
143
  /** 展示的文案 */
129
144
  text?: string;
130
145
  /** 鼠标悬浮是显示的气泡中的文案 */
@@ -136,14 +151,9 @@ export interface MenuButton {
136
151
  /** 是否显示,默认为true */
137
152
  display?: boolean | ((data?: Services) => boolean);
138
153
  /** type为button/dropdown时点击运行的方法 */
139
- handler?: (data?: Services) => Promise<any> | any;
140
- /** type为dropdown时,下拉的菜单列表 */
141
- items?: {
142
- /** 展示的文案 */
143
- text: string;
144
- /** 点击运行的方法 */
145
- handler(data: Services): any;
146
- }[];
154
+ handler?: (data: Services, event: MouseEvent) => Promise<any> | any;
155
+ /** type为dropdown时,下拉的菜单列表, 或者有子菜单时 */
156
+ items?: MenuButton[];
147
157
  }
148
158
 
149
159
  export interface MenuComponent {
@@ -220,7 +230,9 @@ export interface ComponentItem {
220
230
  type: string;
221
231
  /** element-plus icon class */
222
232
  icon?: string | Component;
223
- [key: string]: any;
233
+ data?: {
234
+ [key: string]: any;
235
+ };
224
236
  }
225
237
 
226
238
  export interface ComponentGroup {
@@ -230,6 +242,11 @@ export interface ComponentGroup {
230
242
  items: ComponentItem[];
231
243
  }
232
244
 
245
+ export interface UpdateData {
246
+ id: Id;
247
+ [key: string]: any;
248
+ }
249
+
233
250
  export enum LayerOffset {
234
251
  TOP = 'top',
235
252
  BOTTOM = 'bottom',
@@ -16,18 +16,15 @@
16
16
  * limitations under the License.
17
17
  */
18
18
 
19
- import { random } from 'lodash-es';
20
-
21
- import type { Id, MApp, MContainer, MNode, MPage } from '@tmagic/schema';
19
+ import type { MApp, MContainer, MNode, MPage } from '@tmagic/schema';
22
20
  import { NodeType } from '@tmagic/schema';
23
- import { getNodePath, isPop } from '@tmagic/utils';
21
+ import type StageCore from '@tmagic/stage';
22
+ import { getNodePath, isNumber, isPage, isPop } from '@tmagic/utils';
24
23
 
25
24
  import { Layout } from '@editor/type';
26
25
 
27
26
  export const COPY_STORAGE_KEY = '$MagicEditorCopyData';
28
27
 
29
- export const generateId = (type: string | number): string => `${type}_${random(10000, false)}`;
30
-
31
28
  /**
32
29
  * 获取所有页面配置
33
30
  * @param app DSL跟节点
@@ -73,58 +70,13 @@ export const generatePageName = (pageNameList: string[]): string => {
73
70
  */
74
71
  export const generatePageNameByApp = (app: MApp): string => generatePageName(getPageNameList(getPageList(app)));
75
72
 
76
- /**
77
- * 复制页面时,需要把组件下关联的弹窗id换测复制出来的弹窗的id
78
- * @param {number} oldId 复制的源弹窗id
79
- * @param {number} popId 新的弹窗id
80
- * @param {Object} pageConfig 页面配置
81
- */
82
- const updatePopId = (oldId: Id, popId: Id, pageConfig: MPage) => {
83
- pageConfig.items?.forEach((config) => {
84
- if (config.pop === oldId) {
85
- config.pop = popId;
86
- return;
87
- }
88
-
89
- if (config.popId === oldId) {
90
- config.popId = popId;
91
- return;
92
- }
93
-
94
- if (Array.isArray(config.items)) {
95
- updatePopId(oldId, popId, config as MPage);
96
- }
97
- });
98
- };
99
-
100
- /**
101
- * 将组件与组件的子元素配置中的id都设置成一个新的ID
102
- * @param {Object} config 组件配置
103
- */
104
- /* eslint no-param-reassign: ["error", { "props": false }] */
105
- export const setNewItemId = (config: MNode, parent?: MPage) => {
106
- const oldId = config.id;
107
-
108
- config.id = generateId(config.type);
109
- config.name = `${config.name?.replace(/_(\d+)$/, '')}_${config.id}`;
110
-
111
- // 只有弹窗在页面下的一级子元素才有效
112
- if (isPop(config) && parent?.type === NodeType.PAGE) {
113
- updatePopId(oldId, config.id, parent);
114
- }
115
-
116
- if (config.items && Array.isArray(config.items)) {
117
- config.items.forEach((item) => setNewItemId(item, config as MPage));
118
- }
119
- };
120
-
121
73
  /**
122
74
  * @param {Object} node
123
75
  * @returns {boolean}
124
76
  */
125
77
  export const isFixed = (node: MNode): boolean => node.style?.position === 'fixed';
126
78
 
127
- export const getNodeIndex = (node: MNode, parent: MContainer): number => {
79
+ export const getNodeIndex = (node: MNode, parent: MContainer | MApp): number => {
128
80
  const items = parent?.items || [];
129
81
  return items.findIndex((item: MNode) => `${item.id}` === `${node.id}`);
130
82
  };
@@ -139,11 +91,33 @@ export const toRelative = (node: MNode) => {
139
91
  return node;
140
92
  };
141
93
 
142
- export const initPosition = (node: MNode, layout: Layout) => {
94
+ const setTop2Middle = (node: MNode, parentNode: MNode, stage: StageCore) => {
95
+ const style = node.style || {};
96
+ let height = style.height || 0;
97
+
98
+ if (!stage || typeof style.top !== 'undefined' || !parentNode.style) return style;
99
+
100
+ if (!isNumber(height)) {
101
+ height = 0;
102
+ }
103
+
104
+ const { height: parentHeight } = parentNode.style;
105
+
106
+ if (isPage(parentNode)) {
107
+ const { scrollTop = 0, wrapperHeight } = stage.mask;
108
+ style.top = (wrapperHeight - height) / 2 + scrollTop;
109
+ } else {
110
+ style.top = (parentHeight - height) / 2;
111
+ }
112
+
113
+ return style;
114
+ };
115
+
116
+ export const initPosition = (node: MNode, layout: Layout, parentNode: MNode, stage: StageCore) => {
143
117
  if (layout === Layout.ABSOLUTE) {
144
118
  node.style = {
145
119
  position: 'absolute',
146
- ...(node.style || {}),
120
+ ...setTop2Middle(node, parentNode, stage),
147
121
  };
148
122
  return node;
149
123
  }
@@ -194,12 +168,18 @@ export const change2Fixed = (node: MNode, root: MApp) => {
194
168
  return node;
195
169
  };
196
170
 
197
- export const Fixed2Other = async (node: MNode, root: MApp, getLayout: (node: MNode) => Promise<Layout>) => {
171
+ export const Fixed2Other = async (
172
+ node: MNode,
173
+ root: MApp,
174
+ getLayout: (parent: MNode, node?: MNode) => Promise<Layout>,
175
+ ) => {
198
176
  const path = getNodePath(node.id, root.items);
199
177
  const cur = path.pop();
200
178
  const offset = {
201
179
  left: cur?.style?.left || 0,
202
180
  top: cur?.style?.top || 0,
181
+ right: '',
182
+ bottom: '',
203
183
  };
204
184
 
205
185
  path.forEach((value) => {
@@ -0,0 +1,8 @@
1
+ // serialize-javascript 依赖的 randombytes 依赖全局的 global 对象,因此此处需添加 global polyfill
2
+ if (typeof global === 'undefined') {
3
+ (window as any).global = window;
4
+ }
5
+
6
+ if (typeof globalThis === 'undefined') {
7
+ (window as any).globalThis = window;
8
+ }
@@ -20,7 +20,6 @@ import { FormConfig, FormState } from '@tmagic/form';
20
20
 
21
21
  import editorService from '@editor/services/editor';
22
22
  import eventsService from '@editor/services/events';
23
- import { generateId } from '@editor/utils/editor';
24
23
 
25
24
  /**
26
25
  * 统一为组件属性表单加上事件、高级、样式配置
@@ -142,6 +141,40 @@ export const fillConfig = (config: FormConfig = []) => [
142
141
  },
143
142
  ],
144
143
  },
144
+ {
145
+ type: 'fieldset',
146
+ legend: '字体',
147
+ items: [
148
+ {
149
+ name: 'color',
150
+ text: '颜色',
151
+ type: 'colorPicker',
152
+ },
153
+ {
154
+ name: 'fontSize',
155
+ text: '大小',
156
+ },
157
+ {
158
+ name: 'fontWeight',
159
+ text: '粗细',
160
+ },
161
+ ],
162
+ },
163
+ {
164
+ type: 'fieldset',
165
+ legend: '变形',
166
+ name: 'transform',
167
+ items: [
168
+ {
169
+ name: 'rotate',
170
+ text: '旋转角度',
171
+ },
172
+ {
173
+ name: 'scale',
174
+ text: '缩放',
175
+ },
176
+ ],
177
+ },
145
178
  ],
146
179
  },
147
180
  ],
@@ -174,7 +207,7 @@ export const fillConfig = (config: FormConfig = []) => [
174
207
  type: 'select',
175
208
  options: (mForm: FormState, { model }: any) => {
176
209
  const node = editorService.getNodeById(model.to);
177
- if (!node) return [];
210
+ if (!node?.type) return [];
178
211
 
179
212
  return eventsService.getMethod(node.type).map((option) => ({
180
213
  text: option.label,
@@ -210,9 +243,19 @@ export const DEFAULT_CONFIG: FormConfig = fillConfig([]);
210
243
  * @param type 组件类型
211
244
  * @returns Object
212
245
  */
213
- export const getDefaultPropsValue = (type: string) => ({
214
- type,
215
- id: generateId(type),
216
- style: {},
217
- name: type,
218
- });
246
+ export const getDefaultPropsValue = (type: string, id: string) =>
247
+ ['page', 'container'].includes(type)
248
+ ? {
249
+ type,
250
+ id,
251
+ layout: 'absolute',
252
+ style: {},
253
+ name: type,
254
+ items: [],
255
+ }
256
+ : {
257
+ type,
258
+ id,
259
+ style: {},
260
+ name: type,
261
+ };