@tmagic/editor 1.1.4 → 1.1.6

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.1.4",
2
+ "version": "1.1.6",
3
3
  "name": "@tmagic/editor",
4
4
  "sideEffects": [
5
5
  "dist/*",
@@ -45,14 +45,14 @@
45
45
  "dependencies": {
46
46
  "@babel/core": "^7.18.0",
47
47
  "@element-plus/icons-vue": "^2.0.9",
48
- "@tmagic/core": "1.1.4",
49
- "@tmagic/form": "1.1.4",
50
- "@tmagic/schema": "1.1.4",
51
- "@tmagic/stage": "1.1.4",
52
- "@tmagic/utils": "1.1.4",
48
+ "@tmagic/core": "1.1.6",
49
+ "@tmagic/form": "1.1.6",
50
+ "@tmagic/schema": "1.1.6",
51
+ "@tmagic/stage": "1.1.6",
52
+ "@tmagic/utils": "1.1.6",
53
53
  "buffer": "^6.0.3",
54
54
  "color": "^3.1.3",
55
- "element-plus": "^2.2.6",
55
+ "element-plus": "^2.2.17",
56
56
  "events": "^3.3.0",
57
57
  "gesto": "^1.7.0",
58
58
  "keycon": "^1.1.2",
@@ -62,8 +62,8 @@
62
62
  "vue": "^3.2.37"
63
63
  },
64
64
  "peerDependencies": {
65
- "@tmagic/form": "1.1.4",
66
- "element-plus": "^2.2.6",
65
+ "@tmagic/form": "1.1.6",
66
+ "element-plus": "^2.2.17",
67
67
  "monaco-editor": "^0.34.0",
68
68
  "vue": "^3.2.37"
69
69
  },
@@ -72,13 +72,13 @@
72
72
  "@types/lodash-es": "^4.17.4",
73
73
  "@types/node": "^15.12.4",
74
74
  "@types/serialize-javascript": "^5.0.1",
75
- "@vitejs/plugin-vue": "^3.0.1",
75
+ "@vitejs/plugin-vue": "^3.1.0",
76
76
  "@vue/compiler-sfc": "^3.2.37",
77
77
  "@vue/test-utils": "^2.0.0",
78
78
  "rimraf": "^3.0.2",
79
79
  "sass": "^1.35.1",
80
80
  "typescript": "^4.7.4",
81
- "vite": "^3.0.4",
81
+ "vite": "^3.1.3",
82
82
  "vue-tsc": "^0.39.4"
83
83
  }
84
84
  }
package/src/Editor.vue CHANGED
@@ -11,6 +11,10 @@
11
11
  <slot name="layer-panel-header"></slot>
12
12
  </template>
13
13
 
14
+ <template #layer-node-content="{ node, data }">
15
+ <slot name="layer-node-content" :data="data" :node="node"></slot>
16
+ </template>
17
+
14
18
  <template #component-list-panel-header>
15
19
  <slot name="component-list-panel-header"></slot>
16
20
  </template>
@@ -277,8 +281,6 @@ export default defineComponent({
277
281
  },
278
282
  );
279
283
 
280
- uiService.initColumnWidth();
281
-
282
284
  onUnmounted(() => {
283
285
  editorService.destroy();
284
286
  historyService.destroy();
@@ -7,29 +7,25 @@
7
7
  ></magic-code-editor>
8
8
  </template>
9
9
 
10
- <script lang="ts">
11
- import { computed, defineComponent } from 'vue';
10
+ <script lang="ts" setup>
11
+ import { computed } from 'vue';
12
12
 
13
- export default defineComponent({
14
- name: 'm-fields-vs-code',
13
+ const emit = defineEmits(['change']);
15
14
 
16
- props: ['model', 'name', 'config', 'prop'],
15
+ const props = defineProps<{
16
+ model: any;
17
+ name: string;
18
+ config: {
19
+ language?: string;
20
+ };
21
+ prop: string;
22
+ }>();
17
23
 
18
- emits: ['change'],
24
+ const language = computed(() => props.config.language || 'javascript');
25
+ const height = computed(() => `${document.body.clientHeight - 168}px`);
19
26
 
20
- setup(props, { emit }) {
21
- const language = computed(() => props.config.language || 'javascript');
22
- const height = computed(() => `${document.body.clientHeight - 168}px`);
23
-
24
- return {
25
- height,
26
- language,
27
-
28
- save(v: string) {
29
- props.model[props.name] = v;
30
- emit('change', v);
31
- },
32
- };
33
- },
34
- });
27
+ const save = (v: string) => {
28
+ props.model[props.name] = v;
29
+ emit('change', v);
30
+ };
35
31
  </script>
@@ -2,80 +2,66 @@
2
2
  <m-fields-link :config="formConfig" :model="modelValue" name="form" @change="changeHandler"></m-fields-link>
3
3
  </template>
4
4
 
5
- <script lang="ts">
6
- import { computed, defineComponent, PropType, ref, watchEffect } from 'vue';
5
+ <script lang="ts" setup>
6
+ import { computed, reactive, watch } from 'vue';
7
7
  import serialize from 'serialize-javascript';
8
8
 
9
- interface CodeLinkConfig {
10
- type: 'code-link';
9
+ const props = defineProps<{
10
+ config: {
11
+ type: 'code-link';
12
+ name: string;
13
+ text?: string;
14
+ formTitle?: string;
15
+ };
16
+ model: any;
11
17
  name: string;
12
- text?: string;
13
- formTitle?: string;
14
- }
18
+ prop: string;
19
+ }>();
15
20
 
16
- export default defineComponent({
17
- name: 'm-fields-code-link',
21
+ const emit = defineEmits(['change']);
18
22
 
19
- props: {
20
- config: {
21
- type: Object as PropType<CodeLinkConfig>,
23
+ const formConfig = computed(() => ({
24
+ ...props.config,
25
+ text: '',
26
+ type: 'link',
27
+ form: [
28
+ {
29
+ name: props.name,
30
+ type: 'vs-code',
22
31
  },
32
+ ],
33
+ }));
23
34
 
24
- model: {
25
- type: Object,
26
- },
27
-
28
- name: {
29
- type: String,
30
- },
31
-
32
- prop: {
33
- type: String,
34
- },
35
+ const modelValue = reactive<{ form: Record<string, string> }>({
36
+ form: {
37
+ [props.name]: '',
35
38
  },
39
+ });
36
40
 
37
- emits: ['change'],
38
-
39
- setup(props, { emit }) {
40
- const modelValue = ref<{ form: Record<string, any> }>({
41
- form: {},
42
- });
43
-
44
- watchEffect(() => {
45
- if (!props.model || !props.name) return;
46
- modelValue.value.form[props.name] = serialize(props.model[props.name], {
41
+ watch(
42
+ () => props.model[props.name],
43
+ (value) => {
44
+ modelValue.form = {
45
+ [props.name]: serialize(value, {
47
46
  space: 2,
48
47
  unsafe: true,
49
- }).replace(/"(\w+)":\s/g, '$1: ');
50
- });
51
-
52
- return {
53
- modelValue,
54
-
55
- formConfig: computed(() => ({
56
- ...props.config,
57
- text: '',
58
- type: 'link',
59
- form: [
60
- {
61
- name: props.name,
62
- type: 'vs-code',
63
- },
64
- ],
65
- })),
66
-
67
- changeHandler(v: Record<string, any>) {
68
- if (!props.name || !props.model) return;
69
-
70
- try {
71
- // eslint-disable-next-line no-eval
72
- props.model[props.name] = eval(`${v[props.name]}`);
73
- emit('change', props.model[props.name]);
74
- } catch (e) {
75
- console.error(e);
76
- }
77
- },
48
+ }).replace(/"(\w+)":\s/g, '$1: '),
78
49
  };
79
50
  },
80
- });
51
+ {
52
+ immediate: true,
53
+ },
54
+ );
55
+
56
+ const changeHandler = (v: Record<string, any>) => {
57
+ if (!props.name || !props.model) return;
58
+
59
+ try {
60
+ // eslint-disable-next-line no-eval
61
+ props.model[props.name] = eval(`(${v[props.name]})`);
62
+ emit('change', props.model[props.name]);
63
+ } catch (e) {
64
+ console.error(e);
65
+ }
66
+ };
81
67
  </script>
package/src/index.ts CHANGED
@@ -59,8 +59,8 @@ export default {
59
59
 
60
60
  app.component(Editor.name, Editor);
61
61
  app.component('m-fields-ui-select', uiSelect);
62
- app.component(CodeLink.name, CodeLink);
63
- app.component(Code.name, Code);
62
+ app.component('m-fields-code-link', CodeLink);
63
+ app.component('m-fields-vs-code', Code);
64
64
  app.component(CodeEditor.name, CodeEditor);
65
65
  },
66
66
  };
@@ -10,77 +10,107 @@
10
10
  @save="saveCode"
11
11
  ></magic-code-editor>
12
12
 
13
- <div class="m-editor-content" v-else>
14
- <div class="m-editor-framework-left" :style="`width: ${columnWidth?.left}px`">
13
+ <layout
14
+ v-else
15
+ class="m-editor-content"
16
+ left-class="m-editor-framework-left"
17
+ center-class="m-editor-framework-center"
18
+ right-class="m-editor-framework-right"
19
+ v-model:left="columnWidth.left"
20
+ v-model:right="columnWidth.right"
21
+ :min-left="45"
22
+ :min-right="1"
23
+ @change="columnWidthChange"
24
+ >
25
+ <template #left>
15
26
  <slot name="sidebar"></slot>
16
- </div>
17
-
18
- <resizer type="left"></resizer>
19
-
20
- <template v-if="pageLength > 0">
21
- <div class="m-editor-framework-center" :style="`width: ${columnWidth?.center}px`">
22
- <slot name="workspace"></slot>
23
- </div>
24
-
25
- <resizer type="right"></resizer>
27
+ </template>
26
28
 
27
- <div class="m-editor-framework-right" :style="`width: ${columnWidth?.right}px`">
28
- <el-scrollbar>
29
- <slot name="props-panel"></slot>
30
- </el-scrollbar>
31
- </div>
29
+ <template #center>
30
+ <slot v-if="pageLength > 0" name="workspace"></slot>
31
+ <slot v-else name="empty">
32
+ <add-page-box></add-page-box>
33
+ </slot>
32
34
  </template>
33
35
 
34
- <slot v-else name="empty">
35
- <add-page-box></add-page-box>
36
- </slot>
37
- </div>
36
+ <template v-if="pageLength > 0" #right>
37
+ <el-scrollbar>
38
+ <slot name="props-panel"></slot>
39
+ </el-scrollbar>
40
+ </template>
41
+ </layout>
38
42
  </div>
39
43
  </template>
40
44
 
41
- <script lang="ts">
42
- import { computed, defineComponent, inject } from 'vue';
45
+ <script lang="ts" setup>
46
+ import { computed, inject, ref, watchEffect } from 'vue';
43
47
 
44
48
  import type { MApp } from '@tmagic/schema';
45
49
 
46
50
  import { GetColumnWidth, Services } from '../type';
47
51
 
48
52
  import AddPageBox from './AddPageBox.vue';
49
- import Resizer from './Resizer.vue';
53
+ import Layout from './Layout.vue';
50
54
 
51
- export default defineComponent({
52
- components: {
53
- AddPageBox,
54
- Resizer,
55
- },
55
+ const DEFAULT_LEFT_COLUMN_WIDTH = 310;
56
+ const DEFAULT_RIGHT_COLUMN_WIDTH = 480;
56
57
 
57
- props: {
58
- codeOptions: {
59
- type: Object,
60
- default: () => ({}),
61
- },
58
+ withDefaults(
59
+ defineProps<{
60
+ codeOptions?: Record<string, any>;
61
+ }>(),
62
+ {
63
+ codeOptions: () => ({}),
62
64
  },
65
+ );
63
66
 
64
- setup() {
65
- const { editorService, uiService } = inject<Services>('services') || {};
66
-
67
- const root = computed(() => editorService?.get<MApp>('root'));
68
-
69
- return {
70
- root,
71
- pageLength: computed(() => editorService?.get<number>('pageLength') || 0),
72
- showSrc: computed(() => uiService?.get<boolean>('showSrc')),
73
- columnWidth: computed(() => uiService?.get<GetColumnWidth>('columnWidth')),
74
-
75
- saveCode(value: string) {
76
- try {
77
- // eslint-disable-next-line no-eval
78
- editorService?.set('root', eval(value));
79
- } catch (e: any) {
80
- console.error(e);
81
- }
82
- },
83
- };
84
- },
67
+ const { editorService, uiService } = inject<Services>('services') || {};
68
+
69
+ const root = computed(() => editorService?.get<MApp>('root'));
70
+
71
+ const pageLength = computed(() => editorService?.get<number>('pageLength') || 0);
72
+ const showSrc = computed(() => uiService?.get<boolean>('showSrc'));
73
+ const columnWidth = ref<Partial<GetColumnWidth>>({
74
+ left: DEFAULT_LEFT_COLUMN_WIDTH,
75
+ center: 0,
76
+ right: 0,
77
+ });
78
+ uiService?.set('columnWidth', columnWidth.value);
79
+
80
+ watchEffect(() => {
81
+ if (pageLength.value <= 0) {
82
+ columnWidth.value.right = undefined;
83
+ columnWidth.value.center = globalThis.document.body.clientWidth - DEFAULT_LEFT_COLUMN_WIDTH;
84
+ } else {
85
+ columnWidth.value.right = columnWidth.value.right || DEFAULT_RIGHT_COLUMN_WIDTH;
86
+ columnWidth.value.center =
87
+ globalThis.document.body.clientWidth - DEFAULT_LEFT_COLUMN_WIDTH - DEFAULT_RIGHT_COLUMN_WIDTH;
88
+ }
85
89
  });
90
+
91
+ const saveCode = (value: string) => {
92
+ try {
93
+ // eslint-disable-next-line no-eval
94
+ editorService?.set('root', eval(value));
95
+ } catch (e: any) {
96
+ console.error(e);
97
+ }
98
+ };
99
+
100
+ const COLUMN_WIDTH_STORAGE_KEY = '$MagicEditorColumnWidthData';
101
+
102
+ const columnWidthCacheData = globalThis.localStorage.getItem(COLUMN_WIDTH_STORAGE_KEY);
103
+ if (columnWidthCacheData) {
104
+ try {
105
+ const columnWidthCache = JSON.parse(columnWidthCacheData);
106
+ columnWidth.value = columnWidthCache;
107
+ } catch (e) {
108
+ console.error(e);
109
+ }
110
+ }
111
+
112
+ const columnWidthChange = (columnWidth: GetColumnWidth) => {
113
+ uiService?.set('columnWidth', columnWidth);
114
+ globalThis.localStorage.setItem(COLUMN_WIDTH_STORAGE_KEY, JSON.stringify(columnWidth));
115
+ };
86
116
  </script>
@@ -0,0 +1,100 @@
1
+ <template>
2
+ <div ref="el">
3
+ <template v-if="typeof props.left !== 'undefined'">
4
+ <div class="m-editor-layout-left" :class="leftClass" :style="`width: ${left}px`">
5
+ <slot name="left"></slot>
6
+ </div>
7
+ <Resizer @change="changeLeft"></Resizer>
8
+ </template>
9
+
10
+ <div class="m-editor-layout-center" :class="centerClass" :style="`width: ${center}px`">
11
+ <slot name="center"></slot>
12
+ </div>
13
+
14
+ <template v-if="typeof props.right !== 'undefined'">
15
+ <Resizer @change="changeRight"></Resizer>
16
+ <div class="m-editor-layout-right" :class="rightClass" :style="`width: ${right}px`">
17
+ <slot name="right"></slot>
18
+ </div>
19
+ </template>
20
+ </div>
21
+ </template>
22
+
23
+ <script lang="ts" setup>
24
+ import { onMounted, onUnmounted, ref } from 'vue';
25
+
26
+ import Resizer from './Resizer.vue';
27
+
28
+ const emit = defineEmits(['update:left', 'change', 'update:right']);
29
+
30
+ const props = withDefaults(
31
+ defineProps<{
32
+ left?: number;
33
+ right?: number;
34
+ minLeft?: number;
35
+ minRight?: number;
36
+ leftClass?: string;
37
+ rightClass?: string;
38
+ centerClass?: string;
39
+ }>(),
40
+ {
41
+ minLeft: 1,
42
+ minRight: 1,
43
+ },
44
+ );
45
+
46
+ const el = ref<HTMLElement>();
47
+
48
+ let clientWidth = 0;
49
+ const resizerObserver = new ResizeObserver((entries) => {
50
+ for (const { contentRect } of entries) {
51
+ clientWidth = contentRect.width;
52
+
53
+ center.value = clientWidth - (props.left || 0) - (props.right || 0);
54
+
55
+ emit('change', {
56
+ left: props.left,
57
+ center: center.value,
58
+ right: props.right,
59
+ });
60
+ }
61
+ });
62
+
63
+ onMounted(() => {
64
+ if (el.value) {
65
+ resizerObserver.observe(el.value);
66
+ }
67
+ });
68
+
69
+ onUnmounted(() => {
70
+ resizerObserver.disconnect();
71
+ });
72
+
73
+ const center = ref(0);
74
+
75
+ const changeLeft = (deltaX: number) => {
76
+ if (typeof props.left === 'undefined') return;
77
+ const left = Math.max(props.left + deltaX, props.minLeft) || 0;
78
+ emit('update:left', left);
79
+ center.value = clientWidth - left - (props.right || 0);
80
+
81
+ emit('change', {
82
+ left,
83
+ center: center.value,
84
+ right: props.right,
85
+ });
86
+ };
87
+
88
+ const changeRight = (deltaX: number) => {
89
+ if (typeof props.right === 'undefined') return;
90
+ const right = Math.max(props.right - deltaX, props.minRight) || 0;
91
+ emit('update:right', right);
92
+ center.value = clientWidth - (props.left || 0) - right;
93
+
94
+ emit('change', {
95
+ left: props.left,
96
+ center: center.value,
97
+ right,
98
+ });
99
+ };
100
+ </script>
@@ -4,58 +4,29 @@
4
4
  </span>
5
5
  </template>
6
6
 
7
- <script lang="ts">
8
- import { defineComponent, inject, onMounted, onUnmounted, ref, toRaw } from 'vue';
7
+ <script lang="ts" setup>
8
+ import { onMounted, onUnmounted, ref } from 'vue';
9
9
  import Gesto from 'gesto';
10
10
 
11
- import { Services } from '../type';
11
+ const emit = defineEmits(['change']);
12
12
 
13
- export default defineComponent({
14
- name: 'm-editor-resize',
13
+ const target = ref<HTMLSpanElement>();
15
14
 
16
- props: {
17
- type: {
18
- type: String,
19
- },
20
- },
15
+ let getso: Gesto;
21
16
 
22
- setup(props) {
23
- const services = inject<Services>('services');
17
+ onMounted(() => {
18
+ if (!target.value) return;
19
+ getso = new Gesto(target.value, {
20
+ container: window,
21
+ pinchOutside: true,
22
+ }).on('drag', (e) => {
23
+ if (!target.value) return;
24
24
 
25
- const target = ref<HTMLSpanElement>();
26
-
27
- let getso: Gesto;
28
-
29
- onMounted(() => {
30
- if (!target.value) return;
31
- getso = new Gesto(target.value, {
32
- container: window,
33
- pinchOutside: true,
34
- }).on('drag', (e) => {
35
- if (!target.value || !services) return;
36
-
37
- let { left, right } = {
38
- ...toRaw(services.uiService.get('columnWidth')),
39
- };
40
- if (props.type === 'left') {
41
- left += e.deltaX;
42
- } else if (props.type === 'right') {
43
- right -= e.deltaX;
44
- }
45
- services.uiService.set('columnWidth', {
46
- left,
47
- right,
48
- });
49
- });
50
- });
51
-
52
- onUnmounted(() => {
53
- getso?.unset();
54
- });
25
+ emit('change', e.deltaX);
26
+ });
27
+ });
55
28
 
56
- return {
57
- target,
58
- };
59
- },
29
+ onUnmounted(() => {
30
+ getso?.unset();
60
31
  });
61
32
  </script>
@@ -11,6 +11,10 @@
11
11
  <slot name="layer-panel-header"></slot>
12
12
  </template>
13
13
 
14
+ <template #layer-node-content="{ node, data }" v-if="item === 'layer'">
15
+ <slot name="layer-node-content" :data="data" :node="node"></slot>
16
+ </template>
17
+
14
18
  <template #component-list-panel-header v-if="item === 'component-list'">
15
19
  <slot name="component-list-panel-header"></slot>
16
20
  </template>
@@ -30,8 +30,17 @@
30
30
  <component v-else-if="config.slots?.layerPanelHeader" :is="config.slots.layerPanelHeader" />
31
31
  </template>
32
32
 
33
- <template #layer-node-content="{ data, node }" v-if="config.slots?.layerNodeContent">
34
- <component :is="config.slots?.layerNodeContent" :data="data" :node="node" />
33
+ <template
34
+ #layer-node-content="{ data: nodeData, node }"
35
+ v-if="data === 'layer' || config.slots?.layerNodeContent"
36
+ >
37
+ <slot v-if="data === 'layer'" name="layer-node-content" :data="nodeData" :node="node"></slot>
38
+ <component
39
+ v-else-if="config.slots?.layerNodeContent"
40
+ :is="config.slots.layerNodeContent"
41
+ :data="nodeData"
42
+ :node="node"
43
+ />
35
44
  </template>
36
45
  </component>
37
46
  </el-tab-pane>
@@ -315,9 +315,12 @@ class Editor extends BaseService {
315
315
  root: cloneDeep(root),
316
316
  });
317
317
 
318
- node.style = fixNodePosition(node, parent, stage);
318
+ const newStyle = fixNodePosition(node, parent, stage);
319
319
 
320
- await stage?.update({ config: cloneDeep(node), parentId: parent.id, root: cloneDeep(root) });
320
+ if (newStyle && (newStyle.top !== node.style.top || newStyle.left !== node.style.left)) {
321
+ node.style = newStyle;
322
+ await stage?.update({ config: cloneDeep(node), parentId: parent.id, root: cloneDeep(root) });
323
+ }
321
324
 
322
325
  this.addModifiedNodeId(node.id);
323
326