@tmagic/editor 1.5.21 → 1.5.24

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.
@@ -201,7 +201,7 @@ const props = withDefaults(
201
201
  },
202
202
  );
203
203
 
204
- const { depService, uiService } = useServices();
204
+ const { depService, uiService, propsService } = useServices();
205
205
 
206
206
  const collecting = computed(() => depService.get('collecting'));
207
207
  const taskLength = computed(() => depService.get('taskLength'));
@@ -283,7 +283,19 @@ const getItemConfig = (data: SideItem): SideComponent => {
283
283
  return typeof data === 'string' ? map[data] : data;
284
284
  };
285
285
 
286
- const sideBarItems = computed(() => props.data.items.map((item) => getItemConfig(item)));
286
+ const sideBarItems = computed(() =>
287
+ props.data.items
288
+ .map((item) => getItemConfig(item))
289
+ .filter((item) => {
290
+ if (item.$key === SideItemKey.DATA_SOURCE) {
291
+ return !propsService.getDisabledDataSource();
292
+ }
293
+ if (item.$key === SideItemKey.CODE_BLOCK) {
294
+ return !propsService.getDisabledCodeBlock();
295
+ }
296
+ return true;
297
+ }),
298
+ );
287
299
 
288
300
  watch(
289
301
  sideBarItems,
@@ -43,20 +43,9 @@
43
43
  </template>
44
44
 
45
45
  <script lang="ts" setup>
46
- import {
47
- computed,
48
- markRaw,
49
- nextTick,
50
- onBeforeUnmount,
51
- onMounted,
52
- toRaw,
53
- useTemplateRef,
54
- watch,
55
- watchEffect,
56
- } from 'vue';
57
- import { cloneDeep } from 'lodash-es';
58
-
59
- import type { MApp, MContainer } from '@tmagic/core';
46
+ import { computed, markRaw, nextTick, onBeforeUnmount, onMounted, useTemplateRef, watch, watchEffect } from 'vue';
47
+
48
+ import type { MContainer } from '@tmagic/core';
60
49
  import StageCore, { getOffset, Runtime } from '@tmagic/stage';
61
50
  import { calcValueByFontsize, getIdFromEl } from '@tmagic/utils';
62
51
 
@@ -130,12 +119,6 @@ watchEffect(() => {
130
119
 
131
120
  stage.on('runtime-ready', (rt) => {
132
121
  runtime = rt;
133
- // toRaw返回的值是一个引用而非快照,需要cloneDeep
134
- root.value && runtime?.updateRootConfig?.(cloneDeep(toRaw(root.value)));
135
- page.value?.id && runtime?.updatePageId?.(page.value.id);
136
- setTimeout(() => {
137
- node.value && stage?.select(toRaw(node.value.id));
138
- });
139
122
  });
140
123
  });
141
124
 
@@ -164,19 +147,25 @@ watch(page, (page) => {
164
147
  }, 3000);
165
148
 
166
149
  runtime.updatePageId?.(page.id);
167
- nextTick(() => {
168
- stage?.select(page.id);
169
- });
170
- }
171
- });
172
150
 
173
- const rootChangeHandler = (root: MApp) => {
174
- if (runtime && root) {
175
- runtime.updateRootConfig?.(cloneDeep(toRaw(root)));
151
+ const unWatch = watch(
152
+ stageLoading,
153
+ () => {
154
+ if (stageLoading.value) {
155
+ return;
156
+ }
157
+
158
+ nextTick(() => {
159
+ stage?.select(page.id);
160
+ unWatch();
161
+ });
162
+ },
163
+ {
164
+ immediate: true,
165
+ },
166
+ );
176
167
  }
177
- };
178
-
179
- editorService.on('root-change', rootChangeHandler);
168
+ });
180
169
 
181
170
  const resizeObserver = new ResizeObserver((entries) => {
182
171
  for (const { contentRect } of entries) {
@@ -196,10 +185,10 @@ onMounted(() => {
196
185
 
197
186
  onBeforeUnmount(() => {
198
187
  stage?.destroy();
188
+ stage = null;
199
189
  resizeObserver.disconnect();
200
190
  editorService.set('stage', null);
201
191
  keybindingService.unregisterEl('stage');
202
- editorService.off('root-change', rootChangeHandler);
203
192
  });
204
193
 
205
194
  const parseDSL = getEditorConfig('parseDSL');
@@ -1,9 +1,19 @@
1
1
  <template>
2
- <div v-if="stageOverlayVisible" class="m-editor-stage-overlay" @click="closeOverlayHandler">
3
- <TMagicIcon class="m-editor-stage-overlay-close" :size="'20'" @click="closeOverlayHandler"
2
+ <div v-if="stageOverlayVisible" class="m-editor-stage-overlay">
3
+ <TMagicIcon class="m-editor-stage-overlay-close" :size="'30'" @click="closeOverlayHandler"
4
4
  ><CloseBold
5
5
  /></TMagicIcon>
6
- <div ref="stageOverlay" class="m-editor-stage-overlay-container" :style="style" @click.stop></div>
6
+
7
+ <ScrollViewer
8
+ class="m-editor-stage"
9
+ :width="wrapWidth"
10
+ :height="wrapHeight"
11
+ :wrap-width="columnWidth.center"
12
+ :wrap-height="frameworkRect.height"
13
+ :zoom="zoom"
14
+ >
15
+ <div ref="stageOverlay" class="m-editor-stage-container" :style="style"></div>
16
+ </ScrollViewer>
7
17
  </div>
8
18
  </template>
9
19
 
@@ -13,10 +23,11 @@ import { CloseBold } from '@element-plus/icons-vue';
13
23
 
14
24
  import { TMagicIcon } from '@tmagic/design';
15
25
 
26
+ import ScrollViewer from '@editor/components/ScrollViewer.vue';
16
27
  import { useServices } from '@editor/hooks/use-services';
17
28
  import type { StageOptions } from '@editor/type';
18
29
 
19
- const { stageOverlayService, editorService } = useServices();
30
+ const { stageOverlayService, editorService, uiService } = useServices();
20
31
 
21
32
  const stageOptions = inject<StageOptions>('stageOptions');
22
33
 
@@ -26,10 +37,12 @@ const stageOverlayVisible = computed(() => stageOverlayService.get('stageOverlay
26
37
  const wrapWidth = computed(() => stageOverlayService.get('wrapWidth'));
27
38
  const wrapHeight = computed(() => stageOverlayService.get('wrapHeight'));
28
39
  const stage = computed(() => editorService.get('stage'));
40
+ const zoom = computed(() => uiService.get('zoom'));
41
+ const columnWidth = computed(() => uiService.get('columnWidth'));
42
+ const frameworkRect = computed(() => uiService.get('frameworkRect'));
29
43
 
30
44
  const style = computed(() => ({
31
- width: `${wrapWidth.value}px`,
32
- height: `${wrapHeight.value}px`,
45
+ transform: `scale(${zoom.value})`,
33
46
  }));
34
47
 
35
48
  watch(stage, (stage) => {
@@ -43,6 +56,12 @@ watch(stage, (stage) => {
43
56
  }
44
57
  });
45
58
 
59
+ watch(zoom, (zoom) => {
60
+ const stage = stageOverlayService.get('stage');
61
+ if (!stage || !zoom) return;
62
+ stage.setZoom(zoom);
63
+ });
64
+
46
65
  watch(stageOverlayEl, (stageOverlay) => {
47
66
  const subStage = stageOverlayService.createStage(stageOptions);
48
67
  stageOverlayService.set('stage', subStage);
@@ -199,24 +199,33 @@ export default class extends EventEmitter {
199
199
  * @deprecated 请使用usePlugin代替
200
200
  */
201
201
  public use(options: Record<string, Function>) {
202
- Object.entries(options).forEach(([methodName, method]: [string, Function]) => {
202
+ for (const [methodName, method] of Object.entries(options)) {
203
203
  if (typeof method === 'function') this.middleware[methodName].push(method);
204
- });
204
+ }
205
205
  }
206
206
 
207
207
  public usePlugin(options: Record<string, Function>) {
208
- Object.entries(options).forEach(([methodName, method]: [string, Function]) => {
208
+ for (const [methodName, method] of Object.entries(options)) {
209
209
  if (typeof method === 'function') this.pluginOptionsList[methodName].push(method);
210
- });
210
+ }
211
+ }
212
+
213
+ public removePlugin(options: Record<string, Function>) {
214
+ for (const [methodName, method] of Object.entries(options)) {
215
+ if (Array.isArray(this.pluginOptionsList[methodName])) {
216
+ this.pluginOptionsList[methodName] = this.pluginOptionsList[methodName].filter((item) => item !== method);
217
+ }
218
+ }
211
219
  }
212
220
 
213
221
  public removeAllPlugins() {
214
- Object.keys(this.pluginOptionsList).forEach((key) => {
222
+ for (const key of Object.keys(this.pluginOptionsList)) {
215
223
  this.pluginOptionsList[key] = [];
216
- });
217
- Object.keys(this.middleware).forEach((key) => {
224
+ }
225
+
226
+ for (const key of Object.keys(this.middleware)) {
218
227
  this.middleware[key] = [];
219
- });
228
+ }
220
229
  }
221
230
 
222
231
  private async doTask() {
@@ -145,6 +145,18 @@ class Keybinding extends BaseService {
145
145
  for (const [type = '', eventType = 'keydown'] of when) {
146
146
  const cacheItem: KeyBindingCacheItem = { type, command, keybinding, eventType, bound: false };
147
147
 
148
+ if (
149
+ this.bindingList.find(
150
+ (item) =>
151
+ item.command === command &&
152
+ item.eventType === eventType &&
153
+ item.type === type &&
154
+ item.keybinding === keybinding,
155
+ )
156
+ ) {
157
+ continue;
158
+ }
159
+
148
160
  this.bindingList.push(cacheItem);
149
161
  }
150
162
  }
@@ -57,6 +57,10 @@ class Props extends BaseService {
57
57
  propsConfigMap: {},
58
58
  propsValueMap: {},
59
59
  relateIdMap: {},
60
+ /** 禁用数据源 */
61
+ disabledDataSource: false,
62
+ /** 禁用代码块 */
63
+ disabledCodeBlock: false,
60
64
  });
61
65
 
62
66
  constructor() {
@@ -66,6 +70,22 @@ class Props extends BaseService {
66
70
  ]);
67
71
  }
68
72
 
73
+ public setDisabledDataSource(disabled: boolean) {
74
+ this.state.disabledDataSource = disabled;
75
+ }
76
+
77
+ public setDisabledCodeBlock(disabled: boolean) {
78
+ this.state.disabledCodeBlock = disabled;
79
+ }
80
+
81
+ public getDisabledDataSource(): boolean {
82
+ return this.state.disabledDataSource;
83
+ }
84
+
85
+ public getDisabledCodeBlock(): boolean {
86
+ return this.state.disabledCodeBlock;
87
+ }
88
+
69
89
  public setPropsConfigs(configs: Record<string, FormConfig | PropsFormConfigFunction>) {
70
90
  Object.keys(configs).forEach((type: string) => {
71
91
  this.setPropsConfig(toLine(type), configs[type]);
@@ -74,7 +94,11 @@ class Props extends BaseService {
74
94
  }
75
95
 
76
96
  public async fillConfig(config: FormConfig, labelWidth?: string) {
77
- return fillConfig(config, typeof labelWidth !== 'function' ? labelWidth : '80px');
97
+ return fillConfig(config, {
98
+ labelWidth: typeof labelWidth !== 'function' ? labelWidth : '80px',
99
+ disabledDataSource: this.getDisabledDataSource(),
100
+ disabledCodeBlock: this.getDisabledCodeBlock(),
101
+ });
78
102
  }
79
103
 
80
104
  public async setPropsConfig(type: string, config: FormConfig | PropsFormConfigFunction) {
@@ -97,9 +97,9 @@ class StageOverlay extends BaseService {
97
97
  public createStage(stageOptions: StageOptions = {}) {
98
98
  return useStage({
99
99
  ...stageOptions,
100
- zoom: 1,
101
100
  runtimeUrl: '',
102
101
  autoScrollIntoView: false,
102
+ disabledRule: true,
103
103
  render: async (stage: StageCore) => {
104
104
  this.copyDocumentElement();
105
105
 
@@ -31,8 +31,13 @@
31
31
 
32
32
  .magic-code-editor-full-screen-icon {
33
33
  position: absolute;
34
- top: 5px;
35
- right: 0;
34
+ top: 20px;
35
+ right: 10px;
36
36
  z-index: 11;
37
+ opacity: 0.3;
38
+
39
+ &:hover {
40
+ opacity: 1;
41
+ }
37
42
  }
38
43
  }
@@ -84,6 +84,11 @@
84
84
  right: 15px;
85
85
  bottom: 15px;
86
86
  z-index: 30;
87
+ opacity: 0.5;
88
+
89
+ &:hover {
90
+ opacity: 1;
91
+ }
87
92
  }
88
93
 
89
94
  .m-editor-props-panel-style-icon {
@@ -91,6 +96,11 @@
91
96
  right: 15px;
92
97
  bottom: 60px;
93
98
  z-index: 30;
99
+ opacity: 0.5;
100
+
101
+ &:hover {
102
+ opacity: 1;
103
+ }
94
104
  }
95
105
 
96
106
  .m-editor-props-panel-src-code.magic-code-editor {
@@ -35,22 +35,15 @@
35
35
  width: 100%;
36
36
  height: 100%;
37
37
  background-color: #fff;
38
- display: flex;
39
38
  z-index: 20;
40
- overflow: auto;
41
- }
42
-
43
- .m-editor-stage-overlay-container {
44
- position: relative;
45
- flex-shrink: 0;
46
- margin: auto;
47
- box-shadow: rgba(0, 0, 0, 0.04) 0px 3px 5px;
48
39
  }
49
40
 
50
41
  .m-editor-stage-overlay-close.tmagic-design-icon {
51
42
  position: fixed;
52
43
  right: 20px;
53
44
  top: 10px;
45
+ cursor: pointer;
46
+ z-index: 1;
54
47
  }
55
48
 
56
49
  .m-editor-stage-float-button {
@@ -66,8 +59,10 @@
66
59
  background-color: #ffffff;
67
60
  transition: background-color 0.2s;
68
61
  color: rgba(0, 0, 0, 0.88);
69
- box-shadow: 0 6px 16px 0 rgba(0, 0, 0, 0.08),
70
- 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 9px 28px 8px rgba(0, 0, 0, 0.05);
62
+ box-shadow:
63
+ 0 6px 16px 0 rgba(0, 0, 0, 0.08),
64
+ 0 3px 6px -4px rgba(0, 0, 0, 0.12),
65
+ 0 9px 28px 8px rgba(0, 0, 0, 0.05);
71
66
  }
72
67
 
73
68
  .m-editor-node-list-menu {
package/src/type.ts CHANGED
@@ -33,6 +33,8 @@ import type {
33
33
  UpdateDragEl,
34
34
  } from '@tmagic/stage';
35
35
 
36
+ import Monaco from '@editor/utils/monaco-editor';
37
+
36
38
  import type { CodeBlockService } from './services/codeBlock';
37
39
  import type { ComponentListService } from './services/componentList';
38
40
  import type { DataSourceService } from './services/dataSource';
@@ -119,6 +121,16 @@ export type GetConfig = (config: FormConfig) => Promise<FormConfig> | FormConfig
119
121
 
120
122
  export interface EditorInstallOptions {
121
123
  parseDSL: <T = any>(dsl: string) => T;
124
+ customCreateMonacoEditor: (
125
+ monaco: typeof Monaco,
126
+ codeEditorEl: HTMLElement,
127
+ options: Monaco.editor.IStandaloneEditorConstructionOptions,
128
+ ) => Monaco.editor.IStandaloneCodeEditor;
129
+ customCreateMonacoDiffEditor: (
130
+ monaco: typeof Monaco,
131
+ codeEditorEl: HTMLElement,
132
+ options: Monaco.editor.IStandaloneEditorConstructionOptions,
133
+ ) => Monaco.editor.IStandaloneDiffEditor;
122
134
  [key: string]: any;
123
135
  }
124
136
 
@@ -152,6 +164,7 @@ export interface StageOptions {
152
164
  renderType?: RenderType;
153
165
  guidesOptions?: Partial<GuidesOptions>;
154
166
  disabledMultiSelect?: boolean;
167
+ disabledRule?: boolean;
155
168
  zoom?: number;
156
169
  }
157
170
 
@@ -176,6 +189,10 @@ export interface PropsState {
176
189
  propsConfigMap: Record<string, FormConfig>;
177
190
  propsValueMap: Record<string, Partial<MNode>>;
178
191
  relateIdMap: Record<Id, Id>;
192
+ /** 禁用数据源 */
193
+ disabledDataSource: boolean;
194
+ /** 禁用代码块 */
195
+ disabledCodeBlock: boolean;
179
196
  }
180
197
 
181
198
  export interface StageOverlayState {
@@ -17,9 +17,9 @@
17
17
  * limitations under the License.
18
18
  */
19
19
 
20
- import { NODE_CONDS_KEY } from '@tmagic/core';
20
+ import { NODE_CONDS_KEY, NODE_DISABLE_CODE_BLOCK_KEY, NODE_DISABLE_DATA_SOURCE_KEY } from '@tmagic/core';
21
21
  import { tMagicMessage } from '@tmagic/design';
22
- import type { FormConfig, FormState, TabPaneConfig } from '@tmagic/form';
22
+ import type { FormConfig, FormState, TabConfig, TabPaneConfig } from '@tmagic/form';
23
23
 
24
24
  export const arrayOptions = [
25
25
  { text: '包含', value: 'include' },
@@ -123,6 +123,20 @@ export const advancedTabConfig: TabPaneConfig = {
123
123
  title: '高级',
124
124
  lazy: true,
125
125
  items: [
126
+ {
127
+ name: NODE_DISABLE_CODE_BLOCK_KEY,
128
+ text: '禁用代码块',
129
+ type: 'switch',
130
+ defaultValue: false,
131
+ extra: '开启后,配置的代码块将不会被执行',
132
+ },
133
+ {
134
+ name: NODE_DISABLE_DATA_SOURCE_KEY,
135
+ text: '禁用数据源',
136
+ type: 'switch',
137
+ defaultValue: false,
138
+ extra: '开启后,组件内配置的数据源相关配置将不会被编译,显隐条件将失效',
139
+ },
126
140
  {
127
141
  name: 'created',
128
142
  text: 'created',
@@ -165,7 +179,14 @@ export const displayTabConfig: TabPaneConfig = {
165
179
  * @param config 组件属性配置
166
180
  * @returns Object
167
181
  */
168
- export const fillConfig = (config: FormConfig = [], labelWidth = '80px'): FormConfig => {
182
+ export const fillConfig = (
183
+ config: FormConfig = [],
184
+ {
185
+ labelWidth = '80px',
186
+ disabledDataSource = false,
187
+ disabledCodeBlock = false,
188
+ }: { labelWidth?: string; disabledDataSource?: boolean; disabledCodeBlock?: boolean } = {},
189
+ ): FormConfig => {
169
190
  const propsConfig: FormConfig = [];
170
191
 
171
192
  // 组件类型,必须要有
@@ -208,20 +229,34 @@ export const fillConfig = (config: FormConfig = [], labelWidth = '80px'): FormCo
208
229
  });
209
230
  }
210
231
 
211
- return [
212
- {
213
- type: 'tab',
214
- labelWidth,
215
- items: [
216
- {
217
- title: '属性',
218
- items: [...propsConfig, ...config],
219
- },
220
- { ...styleTabConfig },
221
- { ...eventTabConfig },
222
- { ...advancedTabConfig },
223
- { ...displayTabConfig },
224
- ],
225
- },
226
- ];
232
+ const noCodeAdvancedTabItems = advancedTabConfig.items.filter((item) => item.type !== 'code-select');
233
+
234
+ if (noCodeAdvancedTabItems.length > 0 && disabledCodeBlock) {
235
+ advancedTabConfig.items = noCodeAdvancedTabItems;
236
+ }
237
+
238
+ const tabConfig: TabConfig = {
239
+ type: 'tab',
240
+ labelWidth,
241
+ items: [
242
+ {
243
+ title: '属性',
244
+ items: [...propsConfig, ...config],
245
+ },
246
+ { ...styleTabConfig },
247
+ { ...eventTabConfig },
248
+ ],
249
+ };
250
+
251
+ if (!disabledCodeBlock) {
252
+ tabConfig.items.push({ ...advancedTabConfig });
253
+ } else if (noCodeAdvancedTabItems.length > 0) {
254
+ tabConfig.items.push({ ...advancedTabConfig });
255
+ }
256
+
257
+ if (!disabledDataSource) {
258
+ tabConfig.items.push({ ...displayTabConfig });
259
+ }
260
+
261
+ return [tabConfig];
227
262
  };