@tmagic/editor 1.3.0-alpha.6 → 1.3.0-alpha.7

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.
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.3.0-alpha.6",
2
+ "version": "1.3.0-alpha.7",
3
3
  "name": "@tmagic/editor",
4
4
  "type": "module",
5
5
  "sideEffects": [
@@ -46,13 +46,13 @@
46
46
  "dependencies": {
47
47
  "@babel/core": "^7.18.0",
48
48
  "@element-plus/icons-vue": "^2.0.9",
49
- "@tmagic/core": "1.3.0-alpha.6",
50
- "@tmagic/design": "1.3.0-alpha.6",
51
- "@tmagic/form": "1.3.0-alpha.6",
52
- "@tmagic/schema": "1.3.0-alpha.6",
53
- "@tmagic/stage": "1.3.0-alpha.6",
54
- "@tmagic/table": "1.3.0-alpha.6",
55
- "@tmagic/utils": "1.3.0-alpha.6",
49
+ "@tmagic/core": "1.3.0-alpha.7",
50
+ "@tmagic/design": "1.3.0-alpha.7",
51
+ "@tmagic/form": "1.3.0-alpha.7",
52
+ "@tmagic/schema": "1.3.0-alpha.7",
53
+ "@tmagic/stage": "1.3.0-alpha.7",
54
+ "@tmagic/table": "1.3.0-alpha.7",
55
+ "@tmagic/utils": "1.3.0-alpha.7",
56
56
  "buffer": "^6.0.3",
57
57
  "color": "^3.1.3",
58
58
  "events": "^3.3.0",
@@ -64,8 +64,8 @@
64
64
  "vue": "^3.3.4"
65
65
  },
66
66
  "peerDependencies": {
67
- "@tmagic/design": "1.3.0-alpha.6",
68
- "@tmagic/form": "1.3.0-alpha.6",
67
+ "@tmagic/design": "1.3.0-alpha.7",
68
+ "@tmagic/form": "1.3.0-alpha.7",
69
69
  "monaco-editor": "^0.34.0",
70
70
  "vue": "^3.3.4"
71
71
  },
package/src/Editor.vue CHANGED
@@ -100,6 +100,7 @@ import keybindingService from './services/keybinding';
100
100
  import propsService from './services/props';
101
101
  import storageService from './services/storage';
102
102
  import uiService from './services/ui';
103
+ import keybindingConfig from './utils/keybinding-config';
103
104
  import editorProps from './editorProps';
104
105
  import { initServiceEvents, initServiceState } from './initService';
105
106
  import type { Services } from './type';
@@ -136,6 +137,8 @@ export default defineComponent({
136
137
 
137
138
  initServiceEvents(props, emit, services);
138
139
  initServiceState(props, services);
140
+ keybindingService.registe(keybindingConfig);
141
+ keybindingService.registeEl('global');
139
142
 
140
143
  provide('services', services);
141
144
 
@@ -12,6 +12,7 @@
12
12
  </div>
13
13
  <teleport to="body">
14
14
  <content-menu
15
+ v-if="subMenuData.length"
15
16
  class="sub-menu"
16
17
  ref="subMenu"
17
18
  :menu-data="subMenuData"
@@ -55,6 +56,8 @@ const menuStyle = ref({
55
56
  top: '0',
56
57
  });
57
58
 
59
+ const contains = (el: HTMLElement) => menu.value?.contains(el) || subMenu.value?.contains(el);
60
+
58
61
  const hide = () => {
59
62
  if (!visible.value) return;
60
63
 
@@ -69,7 +72,7 @@ const hideHandler = (e: MouseEvent) => {
69
72
  if (!visible.value || !target) {
70
73
  return;
71
74
  }
72
- if (menu.value?.contains(target) || subMenu.value?.$el?.contains(target)) {
75
+ if (contains(target)) {
73
76
  return;
74
77
  }
75
78
  hide();
@@ -104,13 +107,15 @@ const showSubMenu = (item: MenuButton | MenuComponent) => {
104
107
  return;
105
108
  }
106
109
 
107
- subMenuData.value = menuItem.items;
108
- if (menu.value) {
109
- subMenu.value.show({
110
- clientX: menu.value.offsetLeft + menu.value.clientWidth,
111
- clientY: menu.value.offsetTop,
112
- });
113
- }
110
+ subMenuData.value = menuItem.items || [];
111
+ setTimeout(() => {
112
+ if (menu.value) {
113
+ subMenu.value?.show({
114
+ clientX: menu.value.offsetLeft + menu.value.clientWidth,
115
+ clientY: menu.value.offsetTop,
116
+ });
117
+ }
118
+ }, 0);
114
119
  };
115
120
 
116
121
  onMounted(() => {
@@ -126,7 +131,9 @@ onUnmounted(() => {
126
131
  });
127
132
 
128
133
  defineExpose({
134
+ menu,
129
135
  hide,
130
136
  show,
137
+ contains,
131
138
  });
132
139
  </script>
@@ -33,7 +33,7 @@
33
33
  </TMagicCard>
34
34
  </template>
35
35
  <script lang="ts" setup>
36
- import { inject, ref, watchEffect } from 'vue';
36
+ import { inject, provide, ref, watchEffect } from 'vue';
37
37
  import { cloneDeep } from 'lodash-es';
38
38
 
39
39
  import { TMagicCard, TMagicInput, tMagicMessage } from '@tmagic/design';
@@ -41,6 +41,7 @@ import { ColumnConfig, TableConfig } from '@tmagic/form';
41
41
  import { CodeParam, Id } from '@tmagic/schema';
42
42
 
43
43
  import type { Services } from '@editor/type';
44
+ import { getConfig } from '@editor/utils/config';
44
45
 
45
46
  import CodeDraftEditor from './CodeDraftEditor.vue';
46
47
 
@@ -48,6 +49,8 @@ defineOptions({
48
49
  name: 'MEditorFunctionEditor',
49
50
  });
50
51
 
52
+ provide('mForm', {});
53
+
51
54
  const defaultParamColConfig: ColumnConfig = {
52
55
  type: 'row',
53
56
  label: '参数类型',
@@ -147,9 +150,8 @@ initTableModel();
147
150
  // 保存前钩子
148
151
  const beforeSave = (codeValue: string): boolean => {
149
152
  try {
150
- // eval检测js代码是否存在语法错误
151
- // eslint-disable-next-line no-eval
152
- eval(codeValue);
153
+ // 检测js代码是否存在语法错误
154
+ getConfig('parseDSL')(codeValue);
153
155
  return true;
154
156
  } catch (e: any) {
155
157
  tMagicMessage.error(e.stack);
@@ -6,6 +6,8 @@
6
6
  import { computed, reactive, watch } from 'vue';
7
7
  import serialize from 'serialize-javascript';
8
8
 
9
+ import { getConfig } from '@editor/utils/config';
10
+
9
11
  defineOptions({
10
12
  name: 'MEditorCodeLink',
11
13
  });
@@ -69,8 +71,8 @@ const changeHandler = (v: Record<string, any>) => {
69
71
  if (!props.name || !props.model) return;
70
72
 
71
73
  try {
72
- // eslint-disable-next-line no-eval
73
- props.model[props.name] = eval(`(${v[props.name]})`);
74
+ const parseDSL = getConfig('parseDSL');
75
+ props.model[props.name] = parseDSL(`(${v[props.name]})`);
74
76
  emit('change', props.model[props.name]);
75
77
  } catch (e) {
76
78
  console.error(e);
package/src/index.ts CHANGED
@@ -64,11 +64,12 @@ export { default as LayoutContainer } from './components/SplitView.vue';
64
64
  export { default as SplitView } from './components/SplitView.vue';
65
65
 
66
66
  const defaultInstallOpt: InstallOptions = {
67
- // @todo, 自定义图片上传方法等编辑器依赖的外部选项
67
+ // eslint-disable-next-line no-eval
68
+ parseDSL: (dsl: string) => eval(dsl),
68
69
  };
69
70
 
70
71
  export default {
71
- install: (app: App, opt?: InstallOptions): void => {
72
+ install: (app: App, opt?: Partial<InstallOptions>): void => {
72
73
  const option = Object.assign(defaultInstallOpt, opt || {});
73
74
 
74
75
  // eslint-disable-next-line no-param-reassign
@@ -25,6 +25,7 @@ export const initServiceState = (
25
25
  eventsService,
26
26
  uiService,
27
27
  codeBlockService,
28
+ keybindingService,
28
29
  }: Services,
29
30
  ) => {
30
31
  // 初始值变化,重新设置节点信息
@@ -104,6 +105,7 @@ export const initServiceState = (
104
105
  uiService.resetState();
105
106
  componentListService.resetState();
106
107
  codeBlockService.resetState();
108
+ keybindingService.reset();
107
109
  });
108
110
  };
109
111
 
@@ -52,6 +52,7 @@ import { TMagicScrollbar } from '@tmagic/design';
52
52
 
53
53
  import SplitView from '@editor/components/SplitView.vue';
54
54
  import type { GetColumnWidth, Services } from '@editor/type';
55
+ import { getConfig } from '@editor/utils/config';
55
56
 
56
57
  import AddPageBox from './AddPageBox.vue';
57
58
  import CodeEditor from './CodeEditor.vue';
@@ -131,8 +132,8 @@ const columnWidthChange = (columnW: GetColumnWidth) => {
131
132
 
132
133
  const saveCode = (value: string) => {
133
134
  try {
134
- // eslint-disable-next-line no-eval
135
- editorService?.set('root', eval(value));
135
+ const parseDSL = getConfig('parseDSL');
136
+ editorService?.set('root', parseDSL(value));
136
137
  } catch (e: any) {
137
138
  console.error(e);
138
139
  }
@@ -50,8 +50,7 @@
50
50
  </template>
51
51
 
52
52
  <script lang="ts" setup>
53
- import { computed, inject, onMounted, onUnmounted, ref, watch } from 'vue';
54
- import KeyController from 'keycon';
53
+ import { computed, inject, onBeforeUnmount, onMounted, onUnmounted, ref, watch } from 'vue';
55
54
  import { difference, throttle, union } from 'lodash-es';
56
55
 
57
56
  import { TMagicScrollbar, TMagicTree } from '@tmagic/design';
@@ -248,51 +247,71 @@ const windowBlurHandler = () => {
248
247
  isCtrlKeyDown.value = false;
249
248
  };
250
249
 
251
- const globalKeyupHandler = () => {
252
- if (document.activeElement !== tree.value?.$el) {
250
+ keybindingService?.registeCommand('layer-panel-not-ctrl-keydown', (e) => {
251
+ if (e.key !== keybindingService.ctrlKey) {
253
252
  isCtrlKeyDown.value = false;
254
253
  }
255
- };
254
+ });
256
255
 
257
- let keycon: KeyController;
256
+ keybindingService?.registeCommand('layer-panel-ctrl-keydown', () => {
257
+ isCtrlKeyDown.value = true;
258
+ });
258
259
 
259
- onMounted(() => {
260
- editorService?.on('remove', editorServiceRemoveHandler);
260
+ keybindingService?.registeCommand('layer-panel-ctrl-keyup', () => {
261
+ isCtrlKeyDown.value = false;
262
+ });
263
+
264
+ keybindingService?.registeCommand('layer-panel-global-keydwon', () => {
265
+ if (!tree.value?.$el.contains(document.activeElement)) {
266
+ isCtrlKeyDown.value = false;
267
+ }
268
+ });
269
+
270
+ keybindingService?.registe([
271
+ {
272
+ command: 'layer-panel-not-ctrl-keydown',
273
+ when: [['layer-panel', 'keydown']],
274
+ },
275
+ {
276
+ command: 'layer-panel-ctrl-keydown',
277
+ keybinding: 'ctrl',
278
+ when: [['layer-panel', 'keydown']],
279
+ },
280
+ {
281
+ command: 'layer-panel-ctrl-keyup',
282
+ keybinding: 'ctrl',
283
+ when: [['layer-panel', 'keyup']],
284
+ },
285
+ {
286
+ command: 'layer-panel-global-keydwon',
287
+ keybinding: 'ctrl',
288
+ when: [['global', 'keydown']],
289
+ },
290
+ ]);
261
291
 
292
+ watch(tree, () => {
262
293
  if (tree.value?.$el) {
263
- // 如果是在树上按下ctrl,那么在树外松开ctrl时,也要触发松开事件
264
- keybindingService?.on('keyup', globalKeyupHandler);
265
-
266
- keycon = new KeyController(tree.value.$el);
267
- const isMac = /mac os x/.test(navigator.userAgent.toLowerCase());
268
- const ctrl = isMac ? 'meta' : 'ctrl';
269
-
270
- keycon
271
- .keydown((e) => {
272
- if (e.key !== ctrl) {
273
- isCtrlKeyDown.value = false;
274
- }
275
- })
276
- .keydown(ctrl, () => {
277
- isCtrlKeyDown.value = true;
278
- })
279
- .keyup(ctrl, () => {
280
- isCtrlKeyDown.value = false;
281
- });
294
+ keybindingService?.registeEl('layer-panel', tree.value.$el);
282
295
 
283
296
  tree.value.$el.addEventListener('blur', windowBlurHandler);
297
+ } else {
298
+ keybindingService?.unregisteEl('layer-panel');
284
299
  }
300
+ });
301
+
302
+ onMounted(() => {
303
+ editorService?.on('remove', editorServiceRemoveHandler);
285
304
 
286
305
  globalThis.addEventListener('blur', windowBlurHandler);
287
306
  });
288
307
 
289
- onUnmounted(() => {
290
- keycon.destroy();
308
+ onBeforeUnmount(() => {
309
+ tree.value?.$el.removeEventListener('blur', windowBlurHandler);
310
+ });
291
311
 
312
+ onUnmounted(() => {
292
313
  editorService?.off('remove', editorServiceRemoveHandler);
293
- keybindingService?.off('keyup', globalKeyupHandler);
294
314
  globalThis.removeEventListener('blur', windowBlurHandler);
295
- tree.value?.$el.removeEventListener('blur', windowBlurHandler);
296
315
  });
297
316
 
298
317
  // 鼠标在组件树移动触发高亮
@@ -2,6 +2,7 @@
2
2
  <ScrollViewer
3
3
  class="m-editor-stage"
4
4
  ref="stageWrap"
5
+ tabindex="-1"
5
6
  :width="stageRect?.width"
6
7
  :height="stageRect?.height"
7
8
  :wrap-width="stageContainerRect?.width"
@@ -35,6 +36,7 @@ import StageCore, { calcValueByFontsize, getOffset, Runtime } from '@tmagic/stag
35
36
 
36
37
  import ScrollViewer from '@editor/components/ScrollViewer.vue';
37
38
  import { Layout, MenuButton, MenuComponent, Services, StageOptions } from '@editor/type';
39
+ import { getConfig } from '@editor/utils/config';
38
40
  import { useStage } from '@editor/utils/stage';
39
41
 
40
42
  import ViewerMenu from './ViewerMenu.vue';
@@ -74,6 +76,10 @@ watchEffect(() => {
74
76
 
75
77
  stage = useStage(stageOptions);
76
78
 
79
+ stage.on('select', () => {
80
+ stageWrap.value?.container?.focus();
81
+ });
82
+
77
83
  services?.editorService.set('stage', markRaw(stage));
78
84
 
79
85
  stage?.mount(stageContainer.value);
@@ -120,13 +126,17 @@ const resizeObserver = new ResizeObserver((entries) => {
120
126
  });
121
127
 
122
128
  onMounted(() => {
123
- stageWrap.value?.container && resizeObserver.observe(stageWrap.value.container);
129
+ if (stageWrap.value?.container) {
130
+ resizeObserver.observe(stageWrap.value.container);
131
+ services?.keybindingService.registeEl('stage', stageWrap.value.container);
132
+ }
124
133
  });
125
134
 
126
135
  onUnmounted(() => {
127
136
  stage?.destroy();
128
137
  resizeObserver.disconnect();
129
138
  services?.editorService.set('stage', null);
139
+ services?.keybindingService.unregisteEl('stage');
130
140
  });
131
141
 
132
142
  const contextmenuHandler = (e: MouseEvent) => {
@@ -153,8 +163,8 @@ const dropHandler = async (e: DragEvent) => {
153
163
  }
154
164
 
155
165
  if (e.dataTransfer && parent && stageContainer.value && stage) {
156
- // eslint-disable-next-line no-eval
157
- const config = eval(`(${e.dataTransfer.getData('data')})`);
166
+ const parseDSL = getConfig('parseDSL');
167
+ const config = parseDSL(`(${e.dataTransfer.getData('data')})`);
158
168
  const layout = await services?.editorService.getLayout(parent);
159
169
 
160
170
  const containerRect = stageContainer.value.getBoundingClientRect();
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="m-editor-workspace" tabindex="-1">
2
+ <div class="m-editor-workspace">
3
3
  <Breadcrumb></Breadcrumb>
4
4
 
5
5
  <slot name="stage">
@@ -18,7 +18,7 @@
18
18
  <script lang="ts" setup>
19
19
  import { computed, inject } from 'vue';
20
20
 
21
- import type { MenuButton, MenuComponent, Services } from '@editor/type';
21
+ import { MenuButton, MenuComponent, Services } from '@editor/type';
22
22
 
23
23
  import Breadcrumb from './Breadcrumb.vue';
24
24
  import PageBar from './PageBar.vue';
@@ -23,6 +23,7 @@ import { CodeBlockContent, CodeBlockDSL, Id } from '@tmagic/schema';
23
23
 
24
24
  import type { CodeState } from '@editor/type';
25
25
  import { CODE_DRAFT_STORAGE_KEY } from '@editor/type';
26
+ import { getConfig } from '@editor/utils/config';
26
27
 
27
28
  import BaseService from './BaseService';
28
29
 
@@ -95,8 +96,8 @@ class CodeBlock extends BaseService {
95
96
  const codeConfigProcessed = codeConfig;
96
97
  if (codeConfig.content) {
97
98
  // 在保存的时候转换代码内容
98
- // eslint-disable-next-line no-eval
99
- codeConfigProcessed.content = eval(codeConfig.content);
99
+ const parseDSL = getConfig('parseDSL');
100
+ codeConfigProcessed.content = parseDSL(codeConfig.content);
100
101
  }
101
102
 
102
103
  const existContent = codeDsl[id] || {};