@tmagic/editor 1.4.8 → 1.4.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 (166) hide show
  1. package/dist/style.css +26 -0
  2. package/dist/tmagic-editor.js +3213 -2820
  3. package/dist/tmagic-editor.umd.cjs +3237 -2839
  4. package/package.json +14 -12
  5. package/src/Editor.vue +212 -0
  6. package/src/components/CodeBlockEditor.vue +268 -0
  7. package/src/components/CodeParams.vue +60 -0
  8. package/src/components/ContentMenu.vue +193 -0
  9. package/src/components/FloatingBox.vue +178 -0
  10. package/src/components/Icon.vue +27 -0
  11. package/src/components/Resizer.vue +23 -0
  12. package/src/components/ScrollBar.vue +151 -0
  13. package/src/components/ScrollViewer.vue +128 -0
  14. package/src/components/SearchInput.vue +37 -0
  15. package/src/components/SplitView.vue +186 -0
  16. package/src/components/ToolButton.vue +138 -0
  17. package/src/components/Tree.vue +71 -0
  18. package/src/components/TreeNode.vue +150 -0
  19. package/src/editorProps.ts +120 -0
  20. package/src/fields/Code.vue +50 -0
  21. package/src/fields/CodeLink.vue +80 -0
  22. package/src/fields/CodeSelect.vue +132 -0
  23. package/src/fields/CodeSelectCol.vue +139 -0
  24. package/src/fields/CondOpSelect.vue +87 -0
  25. package/src/fields/DataSourceFieldSelect/FieldSelect.vue +152 -0
  26. package/src/fields/DataSourceFieldSelect/Index.vue +168 -0
  27. package/src/fields/DataSourceFields.vue +329 -0
  28. package/src/fields/DataSourceInput.vue +339 -0
  29. package/src/fields/DataSourceMethodSelect.vue +153 -0
  30. package/src/fields/DataSourceMethods.vue +104 -0
  31. package/src/fields/DataSourceMocks.vue +255 -0
  32. package/src/fields/DataSourceSelect.vue +98 -0
  33. package/src/fields/DisplayConds.vue +145 -0
  34. package/src/fields/EventSelect.vue +375 -0
  35. package/src/fields/KeyValue.vue +137 -0
  36. package/src/fields/PageFragmentSelect.vue +63 -0
  37. package/src/fields/UISelect.vue +135 -0
  38. package/src/hooks/index.ts +24 -0
  39. package/src/hooks/use-code-block-edit.ts +83 -0
  40. package/src/hooks/use-data-source-edit.ts +46 -0
  41. package/src/hooks/use-data-source-method.ts +100 -0
  42. package/src/hooks/use-editor-content-height.ts +26 -0
  43. package/src/hooks/use-filter.ts +55 -0
  44. package/src/hooks/use-float-box.ts +76 -0
  45. package/src/hooks/use-getso.ts +35 -0
  46. package/src/hooks/use-next-float-box-position.ts +29 -0
  47. package/src/hooks/use-node-status.ts +48 -0
  48. package/src/hooks/use-stage.ts +129 -0
  49. package/src/hooks/use-window-rect.ts +20 -0
  50. package/src/icons/AppManageIcon.vue +15 -0
  51. package/src/icons/CenterIcon.vue +13 -0
  52. package/src/icons/CodeIcon.vue +28 -0
  53. package/src/icons/FolderMinusIcon.vue +22 -0
  54. package/src/icons/PinIcon.vue +25 -0
  55. package/src/icons/PinnedIcon.vue +25 -0
  56. package/src/index.ts +124 -0
  57. package/src/initService.ts +448 -0
  58. package/src/layouts/AddPageBox.vue +55 -0
  59. package/src/layouts/CodeEditor.vue +226 -0
  60. package/src/layouts/Framework.vue +165 -0
  61. package/src/layouts/NavMenu.vue +200 -0
  62. package/src/layouts/PropsPanel.vue +131 -0
  63. package/src/layouts/page-bar/AddButton.vue +48 -0
  64. package/src/layouts/page-bar/PageBar.vue +165 -0
  65. package/src/layouts/page-bar/PageBarScrollContainer.vue +192 -0
  66. package/src/layouts/page-bar/PageList.vue +55 -0
  67. package/src/layouts/page-bar/SwitchTypeButton.vue +45 -0
  68. package/src/layouts/sidebar/ComponentListPanel.vue +134 -0
  69. package/src/layouts/sidebar/Sidebar.vue +278 -0
  70. package/src/layouts/sidebar/code-block/CodeBlockList.vue +160 -0
  71. package/src/layouts/sidebar/code-block/CodeBlockListPanel.vue +70 -0
  72. package/src/layouts/sidebar/data-source/DataSourceConfigPanel.vue +84 -0
  73. package/src/layouts/sidebar/data-source/DataSourceList.vue +172 -0
  74. package/src/layouts/sidebar/data-source/DataSourceListPanel.vue +106 -0
  75. package/src/layouts/sidebar/layer/LayerMenu.vue +128 -0
  76. package/src/layouts/sidebar/layer/LayerNodeTool.vue +32 -0
  77. package/src/layouts/sidebar/layer/LayerPanel.vue +119 -0
  78. package/src/layouts/sidebar/layer/use-click.ts +113 -0
  79. package/src/layouts/sidebar/layer/use-drag.ts +167 -0
  80. package/src/layouts/sidebar/layer/use-keybinding.ts +54 -0
  81. package/src/layouts/sidebar/layer/use-node-status.ts +114 -0
  82. package/src/layouts/workspace/Breadcrumb.vue +35 -0
  83. package/src/layouts/workspace/Workspace.vue +46 -0
  84. package/src/layouts/workspace/viewer/NodeListMenu.vue +115 -0
  85. package/src/layouts/workspace/viewer/Stage.vue +246 -0
  86. package/src/layouts/workspace/viewer/StageOverlay.vue +68 -0
  87. package/src/layouts/workspace/viewer/ViewerMenu.vue +145 -0
  88. package/src/services/BaseService.ts +230 -0
  89. package/src/services/codeBlock.ts +327 -0
  90. package/src/services/componentList.ts +58 -0
  91. package/src/services/dataSource.ts +216 -0
  92. package/src/services/dep.ts +152 -0
  93. package/src/services/editor.ts +1135 -0
  94. package/src/services/events.ts +93 -0
  95. package/src/services/history.ts +126 -0
  96. package/src/services/keybinding.ts +220 -0
  97. package/src/services/props.ts +286 -0
  98. package/src/services/stageOverlay.ts +212 -0
  99. package/src/services/storage.ts +155 -0
  100. package/src/services/ui.ts +157 -0
  101. package/src/shims-vue.d.ts +6 -0
  102. package/src/theme/breadcrumb.scss +6 -0
  103. package/src/theme/code-block.scss +6 -0
  104. package/src/theme/code-editor.scss +38 -0
  105. package/src/theme/common/var.scss +14 -0
  106. package/src/theme/component-list-panel.scss +95 -0
  107. package/src/theme/content-menu.scss +76 -0
  108. package/src/theme/data-source-field-select.scss +16 -0
  109. package/src/theme/data-source-field.scss +12 -0
  110. package/src/theme/data-source-fields.scss +13 -0
  111. package/src/theme/data-source-input.scss +18 -0
  112. package/src/theme/data-source-methods.scss +13 -0
  113. package/src/theme/data-source.scss +28 -0
  114. package/src/theme/event.scss +37 -0
  115. package/src/theme/floating-box.scss +32 -0
  116. package/src/theme/framework.scss +69 -0
  117. package/src/theme/icon.scss +12 -0
  118. package/src/theme/index.scss +10 -0
  119. package/src/theme/key-value.scss +20 -0
  120. package/src/theme/layer-panel.scss +26 -0
  121. package/src/theme/layout.scss +9 -0
  122. package/src/theme/nav-menu.scss +78 -0
  123. package/src/theme/page-bar.scss +102 -0
  124. package/src/theme/page-fragment-select.scss +14 -0
  125. package/src/theme/props-panel.scss +55 -0
  126. package/src/theme/resizer.scss +66 -0
  127. package/src/theme/ruler.scss +38 -0
  128. package/src/theme/search-input.scss +14 -0
  129. package/src/theme/sidebar.scss +79 -0
  130. package/src/theme/stage.scss +76 -0
  131. package/src/theme/theme.scss +28 -0
  132. package/src/theme/tree.scss +89 -0
  133. package/src/theme/workspace.scss +9 -0
  134. package/src/type.ts +780 -0
  135. package/src/utils/compose.ts +52 -0
  136. package/src/utils/config.ts +29 -0
  137. package/src/utils/content-menu.ts +95 -0
  138. package/src/utils/data-source/formConfigs/base.ts +30 -0
  139. package/src/utils/data-source/formConfigs/http.ts +60 -0
  140. package/src/utils/data-source/index.ts +249 -0
  141. package/src/utils/editor.ts +313 -0
  142. package/src/utils/idle-task.ts +72 -0
  143. package/src/utils/index.ts +24 -0
  144. package/src/utils/keybinding-config.ts +125 -0
  145. package/src/utils/logger.ts +47 -0
  146. package/src/utils/monaco-editor.ts +8 -0
  147. package/src/utils/operator.ts +106 -0
  148. package/src/utils/props.ts +407 -0
  149. package/src/utils/scroll-viewer.ts +165 -0
  150. package/src/utils/tree.ts +15 -0
  151. package/src/utils/undo-redo.ts +76 -0
  152. package/types/editorProps.d.ts +3 -1
  153. package/types/fields/CondOpSelect.vue.d.ts +17 -0
  154. package/types/fields/DataSourceFieldSelect/FieldSelect.vue.d.ts +36 -0
  155. package/types/fields/{DataSourceFieldSelect.vue.d.ts → DataSourceFieldSelect/Index.vue.d.ts} +1 -1
  156. package/types/fields/DisplayConds.vue.d.ts +32 -0
  157. package/types/index.d.ts +3 -1
  158. package/types/layouts/Framework.vue.d.ts +3 -1
  159. package/types/layouts/PropsPanel.vue.d.ts +21 -21
  160. package/types/layouts/page-bar/PageBar.vue.d.ts +6 -0
  161. package/types/layouts/page-bar/PageBarScrollContainer.vue.d.ts +3 -0
  162. package/types/layouts/page-bar/PageList.vue.d.ts +25 -0
  163. package/types/services/ui.d.ts +1 -0
  164. package/types/type.d.ts +30 -4
  165. package/types/utils/data-source/index.d.ts +1 -0
  166. package/types/utils/props.d.ts +12 -0
@@ -0,0 +1,407 @@
1
+ /* eslint-disable @typescript-eslint/naming-convention */
2
+ /*
3
+ * Tencent is pleased to support the open source community by making TMagicEditor available.
4
+ *
5
+ * Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
6
+ *
7
+ * Licensed under the Apache License, Version 2.0 (the "License");
8
+ * you may not use this file except in compliance with the License.
9
+ * You may obtain a copy of the License at
10
+ *
11
+ * http://www.apache.org/licenses/LICENSE-2.0
12
+ *
13
+ * Unless required by applicable law or agreed to in writing, software
14
+ * distributed under the License is distributed on an "AS IS" BASIS,
15
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ * See the License for the specific language governing permissions and
17
+ * limitations under the License.
18
+ */
19
+
20
+ import type { FormConfig, FormState, TabPaneConfig } from '@tmagic/form';
21
+
22
+ export const arrayOptions = [
23
+ { text: '包含', value: 'include' },
24
+ { text: '不包含', value: 'not_include' },
25
+ ];
26
+
27
+ export const eqOptions = [
28
+ { text: '等于', value: '=' },
29
+ { text: '不等于', value: '!=' },
30
+ ];
31
+
32
+ export const numberOptions = [
33
+ { text: '大于', value: '>' },
34
+ { text: '大于等于', value: '>=' },
35
+ { text: '小于', value: '<' },
36
+ { text: '小于等于', value: '<=' },
37
+ { text: '在范围内', value: 'between' },
38
+ { text: '不在范围内', value: 'not_between' },
39
+ ];
40
+
41
+ export const styleTabConfig: TabPaneConfig = {
42
+ title: '样式',
43
+ items: [
44
+ {
45
+ name: 'style',
46
+ items: [
47
+ {
48
+ type: 'fieldset',
49
+ legend: '位置',
50
+ items: [
51
+ {
52
+ type: 'data-source-field-select',
53
+ name: 'position',
54
+ text: '固定定位',
55
+ checkStrictly: false,
56
+ dataSourceFieldType: ['string'],
57
+ fieldConfig: {
58
+ type: 'checkbox',
59
+ activeValue: 'fixed',
60
+ inactiveValue: 'absolute',
61
+ defaultValue: 'absolute',
62
+ },
63
+ },
64
+ {
65
+ type: 'data-source-field-select',
66
+ name: 'left',
67
+ text: 'left',
68
+ checkStrictly: false,
69
+ dataSourceFieldType: ['string', 'number'],
70
+ fieldConfig: {
71
+ type: 'text',
72
+ },
73
+ },
74
+ {
75
+ type: 'data-source-field-select',
76
+ name: 'top',
77
+ text: 'top',
78
+ checkStrictly: false,
79
+ dataSourceFieldType: ['string', 'number'],
80
+ fieldConfig: {
81
+ type: 'text',
82
+ },
83
+ disabled: (vm: FormState, { model }: any) =>
84
+ model.position === 'fixed' && model._magic_position === 'fixedBottom',
85
+ },
86
+ {
87
+ type: 'data-source-field-select',
88
+ name: 'right',
89
+ text: 'right',
90
+ checkStrictly: false,
91
+ dataSourceFieldType: ['string', 'number'],
92
+ fieldConfig: {
93
+ type: 'text',
94
+ },
95
+ },
96
+ {
97
+ type: 'data-source-field-select',
98
+ name: 'bottom',
99
+ text: 'bottom',
100
+ checkStrictly: false,
101
+ dataSourceFieldType: ['string', 'number'],
102
+ fieldConfig: {
103
+ type: 'text',
104
+ },
105
+ disabled: (vm: FormState, { model }: any) =>
106
+ model.position === 'fixed' && model._magic_position === 'fixedTop',
107
+ },
108
+ ],
109
+ },
110
+ {
111
+ type: 'fieldset',
112
+ legend: '盒子',
113
+ items: [
114
+ {
115
+ type: 'data-source-field-select',
116
+ name: 'width',
117
+ text: '宽度',
118
+ checkStrictly: false,
119
+ dataSourceFieldType: ['string', 'number'],
120
+ fieldConfig: {
121
+ type: 'text',
122
+ },
123
+ },
124
+ {
125
+ type: 'data-source-field-select',
126
+ name: 'height',
127
+ text: '高度',
128
+ checkStrictly: false,
129
+ dataSourceFieldType: ['string', 'number'],
130
+ fieldConfig: {
131
+ type: 'text',
132
+ },
133
+ },
134
+ {
135
+ type: 'data-source-field-select',
136
+ text: 'overflow',
137
+ name: 'overflow',
138
+ checkStrictly: false,
139
+ dataSourceFieldType: ['string'],
140
+ fieldConfig: {
141
+ type: 'select',
142
+ options: [
143
+ { text: 'visible', value: 'visible' },
144
+ { text: 'hidden', value: 'hidden' },
145
+ { text: 'clip', value: 'clip' },
146
+ { text: 'scroll', value: 'scroll' },
147
+ { text: 'auto', value: 'auto' },
148
+ { text: 'overlay', value: 'overlay' },
149
+ ],
150
+ },
151
+ },
152
+ ],
153
+ },
154
+ {
155
+ type: 'fieldset',
156
+ legend: '边框',
157
+ items: [
158
+ {
159
+ type: 'data-source-field-select',
160
+ name: 'borderWidth',
161
+ text: '宽度',
162
+ defaultValue: '0',
163
+ checkStrictly: false,
164
+ dataSourceFieldType: ['string', 'number'],
165
+ fieldConfig: {
166
+ type: 'text',
167
+ },
168
+ },
169
+ {
170
+ type: 'data-source-field-select',
171
+ name: 'borderColor',
172
+ text: '颜色',
173
+ checkStrictly: false,
174
+ dataSourceFieldType: ['string'],
175
+ fieldConfig: {
176
+ type: 'text',
177
+ },
178
+ },
179
+ {
180
+ type: 'data-source-field-select',
181
+ name: 'borderStyle',
182
+ text: '样式',
183
+ defaultValue: 'none',
184
+ checkStrictly: false,
185
+ dataSourceFieldType: ['string'],
186
+ fieldConfig: {
187
+ type: 'select',
188
+ options: [
189
+ { text: 'none', value: 'none' },
190
+ { text: 'hidden', value: 'hidden' },
191
+ { text: 'dotted', value: 'dotted' },
192
+ { text: 'dashed', value: 'dashed' },
193
+ { text: 'solid', value: 'solid' },
194
+ { text: 'double', value: 'double' },
195
+ { text: 'groove', value: 'groove' },
196
+ { text: 'ridge', value: 'ridge' },
197
+ { text: 'inset', value: 'inset' },
198
+ { text: 'outset', value: 'outset' },
199
+ ],
200
+ },
201
+ },
202
+ ],
203
+ },
204
+ {
205
+ type: 'fieldset',
206
+ legend: '背景',
207
+ items: [
208
+ {
209
+ type: 'data-source-field-select',
210
+ name: 'backgroundImage',
211
+ text: '背景图',
212
+ checkStrictly: false,
213
+ dataSourceFieldType: ['string'],
214
+ fieldConfig: {
215
+ type: 'text',
216
+ },
217
+ },
218
+ {
219
+ type: 'data-source-field-select',
220
+ name: 'backgroundColor',
221
+ text: '背景颜色',
222
+ checkStrictly: false,
223
+ dataSourceFieldType: ['string'],
224
+ fieldConfig: {
225
+ type: 'colorPicker',
226
+ },
227
+ },
228
+ {
229
+ type: 'data-source-field-select',
230
+ name: 'backgroundRepeat',
231
+ text: '背景图重复',
232
+ defaultValue: 'no-repeat',
233
+ checkStrictly: false,
234
+ dataSourceFieldType: ['string'],
235
+ fieldConfig: {
236
+ type: 'select',
237
+ options: [
238
+ { text: 'repeat', value: 'repeat' },
239
+ { text: 'repeat-x', value: 'repeat-x' },
240
+ { text: 'repeat-y', value: 'repeat-y' },
241
+ { text: 'no-repeat', value: 'no-repeat' },
242
+ { text: 'inherit', value: 'inherit' },
243
+ ],
244
+ },
245
+ },
246
+ {
247
+ type: 'data-source-field-select',
248
+ name: 'backgroundSize',
249
+ text: '背景图大小',
250
+ defaultValue: '100% 100%',
251
+ checkStrictly: false,
252
+ dataSourceFieldType: ['string'],
253
+ fieldConfig: {
254
+ type: 'text',
255
+ },
256
+ },
257
+ ],
258
+ },
259
+ {
260
+ type: 'fieldset',
261
+ legend: '字体',
262
+ items: [
263
+ {
264
+ type: 'data-source-field-select',
265
+ name: 'color',
266
+ text: '颜色',
267
+ checkStrictly: false,
268
+ dataSourceFieldType: ['string'],
269
+ fieldConfig: {
270
+ type: 'colorPicker',
271
+ },
272
+ },
273
+ {
274
+ type: 'data-source-field-select',
275
+ name: 'fontSize',
276
+ text: '大小',
277
+ checkStrictly: false,
278
+ dataSourceFieldType: ['string', 'number'],
279
+ fieldConfig: {
280
+ type: 'text',
281
+ },
282
+ },
283
+ {
284
+ type: 'data-source-field-select',
285
+ name: 'fontWeight',
286
+ text: '粗细',
287
+ checkStrictly: false,
288
+ dataSourceFieldType: ['string', 'number'],
289
+ fieldConfig: {
290
+ type: 'text',
291
+ },
292
+ },
293
+ ],
294
+ },
295
+ {
296
+ type: 'fieldset',
297
+ legend: '变形',
298
+ name: 'transform',
299
+ items: [
300
+ {
301
+ type: 'data-source-field-select',
302
+ name: 'rotate',
303
+ text: '旋转角度',
304
+ checkStrictly: false,
305
+ dataSourceFieldType: ['string'],
306
+ fieldConfig: {
307
+ type: 'text',
308
+ },
309
+ },
310
+ {
311
+ type: 'data-source-field-select',
312
+ name: 'scale',
313
+ text: '缩放',
314
+ checkStrictly: false,
315
+ dataSourceFieldType: ['number', 'string'],
316
+ fieldConfig: {
317
+ type: 'text',
318
+ },
319
+ },
320
+ ],
321
+ },
322
+ ],
323
+ },
324
+ ],
325
+ };
326
+
327
+ export const eventTabConfig: TabPaneConfig = {
328
+ title: '事件',
329
+ items: [
330
+ {
331
+ name: 'events',
332
+ src: 'component',
333
+ labelWidth: '100px',
334
+ type: 'event-select',
335
+ },
336
+ ],
337
+ };
338
+
339
+ export const advancedTabConfig: TabPaneConfig = {
340
+ title: '高级',
341
+ lazy: true,
342
+ items: [
343
+ {
344
+ name: 'created',
345
+ text: 'created',
346
+ type: 'code-select',
347
+ },
348
+ {
349
+ name: 'mounted',
350
+ text: 'mounted',
351
+ type: 'code-select',
352
+ },
353
+ ],
354
+ };
355
+
356
+ export const displayTabConfig: TabPaneConfig = {
357
+ title: '显示条件',
358
+ display: (vm: FormState, { model }: any) => model.type !== 'page',
359
+ items: [
360
+ {
361
+ type: 'display-conds',
362
+ name: 'displayConds',
363
+ titlePrefix: '条件组',
364
+ defaultValue: [],
365
+ },
366
+ ],
367
+ };
368
+
369
+ /**
370
+ * 统一为组件属性表单加上事件、高级、样式配置
371
+ * @param config 组件属性配置
372
+ * @returns Object
373
+ */
374
+ export const fillConfig = (config: FormConfig = [], labelWidth = '80px'): FormConfig => [
375
+ {
376
+ type: 'tab',
377
+ labelWidth,
378
+ items: [
379
+ {
380
+ title: '属性',
381
+ items: [
382
+ // 组件类型,必须要有
383
+ {
384
+ text: 'type',
385
+ name: 'type',
386
+ type: 'hidden',
387
+ },
388
+ // 组件id,必须要有
389
+ {
390
+ name: 'id',
391
+ type: 'display',
392
+ text: 'id',
393
+ },
394
+ {
395
+ name: 'name',
396
+ text: '组件名称',
397
+ },
398
+ ...config,
399
+ ],
400
+ },
401
+ { ...styleTabConfig },
402
+ { ...eventTabConfig },
403
+ { ...advancedTabConfig },
404
+ { ...displayTabConfig },
405
+ ],
406
+ },
407
+ ];
@@ -0,0 +1,165 @@
1
+ import { EventEmitter } from 'events';
2
+
3
+ interface ScrollViewerOptions {
4
+ container: HTMLDivElement;
5
+ target: HTMLDivElement;
6
+ zoom: number;
7
+ correctionScrollSize?: {
8
+ width: number;
9
+ height: number;
10
+ };
11
+ }
12
+
13
+ export class ScrollViewer extends EventEmitter {
14
+ private container: HTMLDivElement;
15
+ private target: HTMLDivElement;
16
+ private zoom = 1;
17
+
18
+ private scrollLeft = 0;
19
+ private scrollTop = 0;
20
+
21
+ private scrollHeight = 0;
22
+ private scrollWidth = 0;
23
+
24
+ private width = 0;
25
+ private height = 0;
26
+
27
+ private translateXCorrectionValue = 0;
28
+ private translateYCorrectionValue = 0;
29
+
30
+ private correctionScrollSize = {
31
+ width: 0,
32
+ height: 0,
33
+ };
34
+
35
+ private resizeObserver = new ResizeObserver(() => {
36
+ this.setSize();
37
+ this.setScrollSize();
38
+ });
39
+
40
+ constructor(options: ScrollViewerOptions) {
41
+ super();
42
+
43
+ this.container = options.container;
44
+ this.target = options.target;
45
+ this.zoom = options.zoom;
46
+
47
+ if (this.correctionScrollSize) {
48
+ this.correctionScrollSize = {
49
+ ...this.correctionScrollSize,
50
+ ...options.correctionScrollSize,
51
+ };
52
+ }
53
+
54
+ this.container.addEventListener('wheel', this.wheelHandler, false);
55
+
56
+ this.setSize();
57
+ this.setScrollSize();
58
+ this.resizeObserver.observe(this.container);
59
+ this.resizeObserver.observe(this.target);
60
+ }
61
+
62
+ public destroy() {
63
+ this.resizeObserver.disconnect();
64
+ this.container.removeEventListener('wheel', this.wheelHandler, false);
65
+ this.removeAllListeners();
66
+ }
67
+
68
+ public setZoom(zoom: number) {
69
+ this.zoom = zoom;
70
+ this.setScrollSize();
71
+ }
72
+
73
+ public scrollTo({ left, top }: { left?: number; top?: number }) {
74
+ if (typeof left !== 'undefined') {
75
+ this.scrollLeft = left;
76
+ }
77
+
78
+ if (typeof top !== 'undefined') {
79
+ this.scrollTop = top;
80
+ }
81
+
82
+ const translateX = -this.scrollLeft + this.translateXCorrectionValue;
83
+ const translateY = -this.scrollTop + this.translateYCorrectionValue;
84
+ this.target.style.transform = `translate(${translateX}px, ${translateY}px)`;
85
+ }
86
+
87
+ private wheelHandler = (event: WheelEvent) => {
88
+ const { deltaX, deltaY, currentTarget } = event;
89
+
90
+ if (currentTarget !== this.container) return;
91
+
92
+ let top: number | undefined;
93
+ if (this.scrollHeight > this.height) {
94
+ top = this.scrollTop + this.getPos(deltaY, this.scrollTop, this.scrollHeight, this.height);
95
+ }
96
+
97
+ let left: number | undefined;
98
+ if (this.scrollWidth > this.width) {
99
+ left = this.scrollLeft + this.getPos(deltaX, this.scrollLeft, this.scrollWidth, this.width);
100
+ }
101
+
102
+ this.scrollTo({ left, top });
103
+ this.emit('scroll', {
104
+ scrollLeft: this.scrollLeft,
105
+ scrollTop: this.scrollTop,
106
+ scrollHeight: this.scrollHeight,
107
+ scrollWidth: this.scrollWidth,
108
+ });
109
+ };
110
+
111
+ private getPos(delta: number, scrollPos: number, scrollSize: number, size: number) {
112
+ let pos = 0;
113
+ if (delta < 0) {
114
+ if (scrollPos > 0) {
115
+ pos = Math.max(delta, -scrollPos);
116
+ }
117
+ } else {
118
+ const leftPos = scrollSize - size - scrollPos;
119
+ if (leftPos > 0) {
120
+ pos = Math.min(delta, leftPos);
121
+ }
122
+ }
123
+ return pos;
124
+ }
125
+
126
+ private setScrollSize = () => {
127
+ const targetRect = this.target.getBoundingClientRect();
128
+ this.scrollWidth = targetRect.width * this.zoom + this.correctionScrollSize.width;
129
+ const targetMarginTop = Number(this.target.style.marginTop) || 0;
130
+ this.scrollHeight = (targetRect.height + targetMarginTop) * this.zoom + this.correctionScrollSize.height;
131
+
132
+ let left: number | undefined;
133
+ let top: number | undefined;
134
+ if (this.scrollWidth < this.width) {
135
+ left = 0;
136
+ this.translateXCorrectionValue = 0;
137
+ } else {
138
+ this.translateXCorrectionValue = (this.scrollWidth - this.width) / 2;
139
+ }
140
+ if (this.scrollHeight < this.height) {
141
+ top = 0;
142
+ this.translateYCorrectionValue = 0;
143
+ } else {
144
+ this.translateYCorrectionValue = (this.scrollHeight - this.height) / 2;
145
+ }
146
+
147
+ this.scrollTo({
148
+ left,
149
+ top,
150
+ });
151
+
152
+ this.emit('scroll', {
153
+ scrollLeft: this.scrollLeft,
154
+ scrollTop: this.scrollTop,
155
+ scrollHeight: this.scrollHeight,
156
+ scrollWidth: this.scrollWidth,
157
+ });
158
+ };
159
+
160
+ private setSize = () => {
161
+ const { width, height } = this.container.getBoundingClientRect();
162
+ this.width = width;
163
+ this.height = height;
164
+ };
165
+ }
@@ -0,0 +1,15 @@
1
+ import type { Id } from '@tmagic/schema';
2
+ import { getKeys } from '@tmagic/utils';
3
+
4
+ import type { LayerNodeStatus } from '@editor/type';
5
+
6
+ export const updateStatus = (nodeStatusMap: Map<Id, LayerNodeStatus>, id: Id, status: Partial<LayerNodeStatus>) => {
7
+ const nodeStatus = nodeStatusMap.get(id);
8
+
9
+ if (!nodeStatus) return;
10
+ getKeys(status).forEach((key) => {
11
+ if (nodeStatus[key] !== undefined && status[key] !== undefined) {
12
+ nodeStatus[key] = Boolean(status[key]);
13
+ }
14
+ });
15
+ };
@@ -0,0 +1,76 @@
1
+ /*
2
+ * Tencent is pleased to support the open source community by making TMagicEditor available.
3
+ *
4
+ * Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+
19
+ import { cloneDeep } from 'lodash-es';
20
+
21
+ export class UndoRedo<T = any> {
22
+ private elementList: T[];
23
+ private listCursor: number;
24
+ private listMaxSize: number;
25
+
26
+ constructor(listMaxSize = 20) {
27
+ const minListMaxSize = 2;
28
+ this.elementList = [];
29
+ this.listCursor = 0;
30
+ this.listMaxSize = listMaxSize > minListMaxSize ? listMaxSize : minListMaxSize;
31
+ }
32
+
33
+ public pushElement(element: T): void {
34
+ // 新元素进来时,把游标之外的元素全部丢弃,并把新元素放进来
35
+ this.elementList.splice(this.listCursor, this.elementList.length - this.listCursor, cloneDeep(element));
36
+ this.listCursor += 1;
37
+ // 如果list中的元素超过maxSize,则移除第一个元素
38
+ if (this.elementList.length > this.listMaxSize) {
39
+ this.elementList.shift();
40
+ this.listCursor -= 1;
41
+ }
42
+ }
43
+
44
+ public canUndo(): boolean {
45
+ return this.listCursor > 1;
46
+ }
47
+
48
+ // 返回undo后的当前元素
49
+ public undo(): T | null {
50
+ if (!this.canUndo()) {
51
+ return null;
52
+ }
53
+ this.listCursor -= 1;
54
+ return this.getCurrentElement();
55
+ }
56
+
57
+ public canRedo() {
58
+ return this.elementList.length > this.listCursor;
59
+ }
60
+
61
+ // 返回redo后的当前元素
62
+ public redo(): T | null {
63
+ if (!this.canRedo()) {
64
+ return null;
65
+ }
66
+ this.listCursor += 1;
67
+ return this.getCurrentElement();
68
+ }
69
+
70
+ public getCurrentElement(): T | null {
71
+ if (this.listCursor < 1) {
72
+ return null;
73
+ }
74
+ return cloneDeep(this.elementList[this.listCursor - 1]);
75
+ }
76
+ }
@@ -2,7 +2,7 @@ import type { EventOption } from '@tmagic/core';
2
2
  import type { FormConfig, FormState } from '@tmagic/form';
3
3
  import type { DataSourceSchema, Id, MApp, MNode } from '@tmagic/schema';
4
4
  import StageCore, { ContainerHighlightType, type CustomizeMoveableOptionsCallbackConfig, type GuidesOptions, type MoveableOptions, RenderType, type UpdateDragEl } from '@tmagic/stage';
5
- import type { ComponentGroup, DatasourceTypeOption, MenuBarData, MenuButton, MenuComponent, SideBarData, StageRect } from './type';
5
+ import type { ComponentGroup, DatasourceTypeOption, MenuBarData, MenuButton, MenuComponent, PageBarSortOptions, SideBarData, StageRect } from './type';
6
6
  export interface EditorProps {
7
7
  /** 页面初始值 */
8
8
  modelValue?: MApp;
@@ -80,6 +80,8 @@ export interface EditorProps {
80
80
  /** 用于自定义组件树与画布的右键菜单 */
81
81
  customContentMenu?: (menus: (MenuButton | MenuComponent)[], type: string) => (MenuButton | MenuComponent)[];
82
82
  extendFormState?: (state: FormState) => Record<string, any> | Promise<Record<string, any>>;
83
+ /** 页面顺序拖拽配置参数 */
84
+ pageBarSortOptions?: PageBarSortOptions;
83
85
  }
84
86
  export declare const defaultEditorProps: {
85
87
  renderType: RenderType;
@@ -0,0 +1,17 @@
1
+ import type { FieldProps } from '@tmagic/form';
2
+ import type { CondOpSelectConfig } from '../type';
3
+ declare const _default: import("vue").DefineComponent<__VLS_TypePropsToOption<FieldProps<CondOpSelectConfig>>, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
4
+ change: (...args: any[]) => void;
5
+ }, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<__VLS_TypePropsToOption<FieldProps<CondOpSelectConfig>>>> & {
6
+ onChange?: ((...args: any[]) => any) | undefined;
7
+ }, {}, {}>;
8
+ export default _default;
9
+ type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
10
+ type __VLS_TypePropsToOption<T> = {
11
+ [K in keyof T]-?: {} extends Pick<T, K> ? {
12
+ type: import('vue').PropType<__VLS_NonUndefinedable<T[K]>>;
13
+ } : {
14
+ type: import('vue').PropType<T[K]>;
15
+ required: true;
16
+ };
17
+ };