@tmagic/editor 1.8.0-beta.11 → 1.8.0-beta.12

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 (111) hide show
  1. package/dist/es/Editor.vue_vue_type_script_setup_true_lang.js +7 -4
  2. package/dist/es/components/CodeBlockEditor.vue_vue_type_script_setup_true_lang.js +4 -0
  3. package/dist/es/components/CodeParams.vue_vue_type_script_setup_true_lang.js +2 -1
  4. package/dist/es/components/CompareForm.vue_vue_type_script_setup_true_lang.js +5 -2
  5. package/dist/es/components/FloatingBox.vue_vue_type_script_setup_true_lang.js +60 -14
  6. package/dist/es/components/ScrollBar.js +0 -1
  7. package/dist/es/editorProps.js +6 -1
  8. package/dist/es/fields/CodeSelect.vue_vue_type_script_setup_true_lang.js +15 -3
  9. package/dist/es/fields/CondOpSelect.vue_vue_type_script_setup_true_lang.js +2 -17
  10. package/dist/es/fields/DataSourceFieldSelect/FieldSelect.vue_vue_type_script_setup_true_lang.js +2 -1
  11. package/dist/es/fields/DataSourceFields.vue_vue_type_script_setup_true_lang.js +7 -0
  12. package/dist/es/fields/DataSourceInput.vue_vue_type_script_setup_true_lang.js +5 -17
  13. package/dist/es/fields/DataSourceMocks.vue_vue_type_script_setup_true_lang.js +4 -0
  14. package/dist/es/fields/DisplayConds.vue_vue_type_script_setup_true_lang.js +29 -3
  15. package/dist/es/fields/EventSelect.vue_vue_type_script_setup_true_lang.js +50 -88
  16. package/dist/es/fields/StyleSetter/Index.vue_vue_type_script_setup_true_lang.js +2 -5
  17. package/dist/es/fields/StyleSetter/pro/Background.vue_vue_type_script_setup_true_lang.js +48 -23
  18. package/dist/es/fields/StyleSetter/pro/Border.vue_vue_type_script_setup_true_lang.js +6 -3
  19. package/dist/es/fields/StyleSetter/pro/Font.vue_vue_type_script_setup_true_lang.js +28 -22
  20. package/dist/es/fields/StyleSetter/pro/Layout.vue_vue_type_script_setup_true_lang.js +28 -22
  21. package/dist/es/fields/StyleSetter/pro/Position.vue_vue_type_script_setup_true_lang.js +28 -22
  22. package/dist/es/fields/StyleSetter/pro/Transform.vue_vue_type_script_setup_true_lang.js +6 -3
  23. package/dist/es/fields/UISelect.js +0 -1
  24. package/dist/es/index.js +9 -6
  25. package/dist/es/layouts/CodeEditor.vue_vue_type_script_setup_true_lang.js +21 -6
  26. package/dist/es/layouts/Framework.vue_vue_type_script_setup_true_lang.js +9 -6
  27. package/dist/es/layouts/history-list/HistoryDiffDialog.vue_vue_type_script_setup_true_lang.js +4 -1
  28. package/dist/es/layouts/history-list/composables.js +1 -1
  29. package/dist/es/layouts/history-list/useHistoryRevert.js +7 -3
  30. package/dist/es/layouts/props-panel/FormPanel.vue_vue_type_script_setup_true_lang.js +44 -5
  31. package/dist/es/layouts/props-panel/PropsPanel.vue_vue_type_script_setup_true_lang.js +15 -8
  32. package/dist/es/layouts/props-panel/use-style-panel.js +3 -2
  33. package/dist/es/layouts/sidebar/Sidebar.vue_vue_type_script_setup_true_lang.js +15 -31
  34. package/dist/es/layouts/sidebar/code-block/CodeBlockListPanel.vue_vue_type_script_setup_true_lang.js +2 -2
  35. package/dist/es/layouts/sidebar/code-block/useContentMenu.js +18 -3
  36. package/dist/es/layouts/sidebar/data-source/DataSourceConfigPanel.vue_vue_type_script_setup_true_lang.js +4 -0
  37. package/dist/es/layouts/sidebar/data-source/DataSourceListPanel.vue_vue_type_script_setup_true_lang.js +2 -2
  38. package/dist/es/layouts/sidebar/data-source/useContentMenu.js +18 -3
  39. package/dist/es/layouts/sidebar/layer/LayerNodeContent.js +5 -0
  40. package/dist/es/layouts/sidebar/layer/LayerNodeContent.vue_vue_type_script_setup_true_lang.js +46 -0
  41. package/dist/es/layouts/sidebar/layer/LayerPanel.vue_vue_type_script_setup_true_lang.js +2 -1
  42. package/dist/es/layouts/workspace/viewer/NodeListMenu.vue_vue_type_script_setup_true_lang.js +8 -2
  43. package/dist/es/plugin.js +3 -1
  44. package/dist/es/services/editor.js +104 -5
  45. package/dist/es/services/props.js +2 -1
  46. package/dist/es/services/storage.js +1 -1
  47. package/dist/es/services/ui.js +3 -0
  48. package/dist/es/style.css +104 -55
  49. package/dist/es/utils/data-source/index.js +30 -11
  50. package/dist/es/utils/event.js +123 -0
  51. package/dist/es/utils/monaco-editor.js +22 -6
  52. package/dist/es/utils/props.js +94 -8
  53. package/dist/es/utils/type-match-rules.js +360 -0
  54. package/dist/style.css +104 -55
  55. package/dist/tmagic-editor.umd.cjs +16895 -15757
  56. package/package.json +8 -8
  57. package/src/Editor.vue +3 -1
  58. package/src/components/CodeBlockEditor.vue +3 -0
  59. package/src/components/CompareForm.vue +7 -0
  60. package/src/components/FloatingBox.vue +77 -8
  61. package/src/components/ScrollBar.vue +0 -67
  62. package/src/editorProps.ts +13 -0
  63. package/src/fields/CodeSelect.vue +4 -1
  64. package/src/fields/CondOpSelect.vue +2 -24
  65. package/src/fields/DataSourceFields.vue +5 -0
  66. package/src/fields/DataSourceInput.vue +7 -25
  67. package/src/fields/DataSourceMocks.vue +3 -0
  68. package/src/fields/DisplayConds.vue +14 -0
  69. package/src/fields/EventSelect.vue +84 -129
  70. package/src/fields/StyleSetter/Index.vue +2 -8
  71. package/src/fields/StyleSetter/pro/Background.vue +94 -55
  72. package/src/fields/StyleSetter/pro/Border.vue +9 -11
  73. package/src/fields/StyleSetter/pro/Font.vue +66 -64
  74. package/src/fields/StyleSetter/pro/Layout.vue +140 -138
  75. package/src/fields/StyleSetter/pro/Position.vue +69 -67
  76. package/src/fields/StyleSetter/pro/Transform.vue +23 -25
  77. package/src/fields/UISelect.vue +0 -12
  78. package/src/index.ts +1 -0
  79. package/src/layouts/CodeEditor.vue +32 -6
  80. package/src/layouts/Framework.vue +7 -6
  81. package/src/layouts/history-list/HistoryDiffDialog.vue +11 -1
  82. package/src/layouts/history-list/useHistoryRevert.ts +4 -0
  83. package/src/layouts/props-panel/FormPanel.vue +66 -5
  84. package/src/layouts/props-panel/PropsPanel.vue +20 -6
  85. package/src/layouts/props-panel/use-style-panel.ts +4 -3
  86. package/src/layouts/sidebar/Sidebar.vue +2 -0
  87. package/src/layouts/sidebar/code-block/CodeBlockListPanel.vue +4 -1
  88. package/src/layouts/sidebar/code-block/useContentMenu.ts +13 -1
  89. package/src/layouts/sidebar/data-source/DataSourceConfigPanel.vue +3 -0
  90. package/src/layouts/sidebar/data-source/DataSourceListPanel.vue +2 -2
  91. package/src/layouts/sidebar/data-source/useContentMenu.ts +13 -1
  92. package/src/layouts/sidebar/layer/LayerNodeContent.vue +57 -0
  93. package/src/layouts/sidebar/layer/LayerPanel.vue +4 -1
  94. package/src/layouts/workspace/viewer/NodeListMenu.vue +4 -1
  95. package/src/plugin.ts +3 -1
  96. package/src/services/editor.ts +168 -3
  97. package/src/services/ui.ts +6 -0
  98. package/src/theme/event.scss +8 -0
  99. package/src/theme/floating-box.scss +9 -1
  100. package/src/theme/layer-node-content.scss +14 -0
  101. package/src/theme/scroll-bar.scss +64 -0
  102. package/src/theme/theme.scss +3 -0
  103. package/src/theme/ui-select.scss +9 -0
  104. package/src/type.ts +53 -2
  105. package/src/utils/data-source/index.ts +30 -12
  106. package/src/utils/event.ts +224 -0
  107. package/src/utils/index.ts +2 -0
  108. package/src/utils/monaco-editor.ts +27 -0
  109. package/src/utils/props.ts +160 -2
  110. package/src/utils/type-match-rules.ts +678 -0
  111. package/types/index.d.ts +372 -85
@@ -1,6 +1,9 @@
1
1
  <template>
2
2
  <MContainer
3
- :config="config"
3
+ v-for="item in formConfig"
4
+ :prop="prop"
5
+ :key="item.name"
6
+ :config="item"
4
7
  :model="values"
5
8
  :last-values="lastValues"
6
9
  :is-compare="isCompare"
@@ -23,8 +26,8 @@
23
26
  <script lang="ts" setup>
24
27
  import { markRaw } from 'vue';
25
28
 
26
- import type { ChildConfig, ContainerChangeEventData } from '@tmagic/form';
27
- import { defineFormItem, MContainer } from '@tmagic/form';
29
+ import type { ContainerChangeEventData } from '@tmagic/form';
30
+ import { defineFormConfig, MContainer } from '@tmagic/form';
28
31
  import type { StyleSchema } from '@tmagic/schema';
29
32
 
30
33
  import Box from '../components/Box.vue';
@@ -49,6 +52,7 @@ defineProps<{
49
52
  isCompare?: boolean;
50
53
  disabled?: boolean;
51
54
  size?: 'large' | 'default' | 'small';
55
+ prop?: string;
52
56
  }>();
53
57
 
54
58
  const emit = defineEmits<{
@@ -56,145 +60,143 @@ const emit = defineEmits<{
56
60
  addDiffCount: [];
57
61
  }>();
58
62
 
59
- const config = defineFormItem({
60
- items: [
61
- {
62
- name: 'display',
63
- text: '模式',
64
- type: 'radioGroup',
65
- childType: 'button',
66
- labelWidth: '68px',
67
- options: [
68
- { value: 'inline', icon: markRaw(DisplayInline), tooltip: '内联布局 inline' },
69
- { value: 'flex', icon: markRaw(DisplayFlex), tooltip: '弹性布局 flex' },
70
- { value: 'block', icon: markRaw(DisplayBlock), tooltip: '块级布局 block' },
71
- { value: 'inline-block', icon: markRaw(DisplayInlineBlock), tooltip: '内联块布局 inline-block' },
72
- { value: 'none', icon: markRaw(DisplayNone), tooltip: '隐藏 none' },
73
- ],
74
- },
75
- {
76
- name: 'flexDirection',
77
- text: '主轴方向',
78
- type: 'radioGroup',
79
- childType: 'button',
80
- labelWidth: '68px',
81
- options: [
82
- { value: 'row', icon: markRaw(FlexDirectionRow), tooltip: '水平方向 起点在左侧 row' },
83
- { value: 'row-reverse', icon: markRaw(FlexDirectionRowReverse), tooltip: '水平方向 起点在右侧 row-reverse' },
84
- { value: 'column', icon: markRaw(FlexDirectionColumn), tooltip: '垂直方向 起点在上沿 column' },
85
- {
86
- value: 'column-reverse',
87
- icon: markRaw(FlexDirectionColumnReverse),
88
- tooltip: '垂直方向 起点在下沿 column-reverse',
63
+ const formConfig = defineFormConfig([
64
+ {
65
+ name: 'display',
66
+ text: '模式',
67
+ type: 'radioGroup',
68
+ childType: 'button',
69
+ labelWidth: '68px',
70
+ options: [
71
+ { value: 'inline', icon: markRaw(DisplayInline), tooltip: '内联布局 inline' },
72
+ { value: 'flex', icon: markRaw(DisplayFlex), tooltip: '弹性布局 flex' },
73
+ { value: 'block', icon: markRaw(DisplayBlock), tooltip: '块级布局 block' },
74
+ { value: 'inline-block', icon: markRaw(DisplayInlineBlock), tooltip: '内联块布局 inline-block' },
75
+ { value: 'none', icon: markRaw(DisplayNone), tooltip: '隐藏 none' },
76
+ ],
77
+ },
78
+ {
79
+ name: 'flexDirection',
80
+ text: '主轴方向',
81
+ type: 'radioGroup',
82
+ childType: 'button',
83
+ labelWidth: '68px',
84
+ options: [
85
+ { value: 'row', icon: markRaw(FlexDirectionRow), tooltip: '水平方向 起点在左侧 row' },
86
+ { value: 'row-reverse', icon: markRaw(FlexDirectionRowReverse), tooltip: '水平方向 起点在右侧 row-reverse' },
87
+ { value: 'column', icon: markRaw(FlexDirectionColumn), tooltip: '垂直方向 起点在上沿 column' },
88
+ {
89
+ value: 'column-reverse',
90
+ icon: markRaw(FlexDirectionColumnReverse),
91
+ tooltip: '垂直方向 起点在下沿 column-reverse',
92
+ },
93
+ ],
94
+ display: (_mForm, { model }: { model: Record<any, any> }) => model.display === 'flex',
95
+ },
96
+ {
97
+ name: 'justifyContent',
98
+ text: '主轴对齐',
99
+ type: 'radioGroup',
100
+ childType: 'button',
101
+ labelWidth: '68px',
102
+ options: [
103
+ { value: 'flex-start', icon: markRaw(JustifyContentFlexStart), tooltip: '左对齐 flex-start' },
104
+ { value: 'flex-end', icon: markRaw(JustifyContentFlexEnd), tooltip: '右对齐 flex-end' },
105
+ { value: 'center', icon: markRaw(JustifyContentCenter), tooltip: '居中 center' },
106
+ { value: 'space-between', icon: markRaw(JustifyContentSpaceBetween), tooltip: '两端对齐 space-between' },
107
+ { value: 'space-around', icon: markRaw(JustifyContentSpaceAround), tooltip: '横向平分 space-around' },
108
+ ],
109
+ display: (_mForm, { model }: { model: Record<any, any> }) => model.display === 'flex',
110
+ },
111
+ {
112
+ name: 'alignItems',
113
+ text: '辅轴对齐',
114
+ type: 'radioGroup',
115
+ childType: 'button',
116
+ labelWidth: '68px',
117
+ options: [
118
+ { value: 'flex-start', icon: markRaw(JustifyContentFlexStart), tooltip: '左对齐 flex-start' },
119
+ { value: 'flex-end', icon: markRaw(JustifyContentFlexEnd), tooltip: '右对齐 flex-end' },
120
+ { value: 'center', icon: markRaw(JustifyContentCenter), tooltip: '居中 center' },
121
+ { value: 'space-between', icon: markRaw(JustifyContentSpaceBetween), tooltip: '两端对齐 space-between' },
122
+ { value: 'space-around', icon: markRaw(JustifyContentSpaceAround), tooltip: '横向平分 space-around' },
123
+ ],
124
+ display: (_mForm, { model }: { model: Record<any, any> }) => model.display === 'flex',
125
+ },
126
+ {
127
+ name: 'flexWrap',
128
+ text: '换行',
129
+ type: 'radioGroup',
130
+ childType: 'button',
131
+ labelWidth: '68px',
132
+ options: [
133
+ { value: 'nowrap', text: '不换行', tooltip: '不换行 nowrap' },
134
+ { value: 'wrap', text: '正换行', tooltip: '第一行在上方 wrap' },
135
+ { value: 'wrap-reverse', text: '逆换行', tooltip: '第一行在下方 wrap-reverse' },
136
+ ],
137
+ display: (_mForm, { model }: { model: Record<any, any> }) => model.display === 'flex',
138
+ },
139
+ {
140
+ type: 'row',
141
+ items: [
142
+ {
143
+ name: 'width',
144
+ text: '宽度',
145
+ labelWidth: '68px',
146
+ type: 'data-source-field-select',
147
+ fieldConfig: {
148
+ type: 'text',
89
149
  },
90
- ],
91
- display: (_mForm, { model }: { model: Record<any, any> }) => model.display === 'flex',
92
- },
93
- {
94
- name: 'justifyContent',
95
- text: '主轴对齐',
96
- type: 'radioGroup',
97
- childType: 'button',
98
- labelWidth: '68px',
99
- options: [
100
- { value: 'flex-start', icon: markRaw(JustifyContentFlexStart), tooltip: '左对齐 flex-start' },
101
- { value: 'flex-end', icon: markRaw(JustifyContentFlexEnd), tooltip: '右对齐 flex-end' },
102
- { value: 'center', icon: markRaw(JustifyContentCenter), tooltip: '居中 center' },
103
- { value: 'space-between', icon: markRaw(JustifyContentSpaceBetween), tooltip: '两端对齐 space-between' },
104
- { value: 'space-around', icon: markRaw(JustifyContentSpaceAround), tooltip: '横向平分 space-around' },
105
- ],
106
- display: (_mForm, { model }: { model: Record<any, any> }) => model.display === 'flex',
107
- },
108
- {
109
- name: 'alignItems',
110
- text: '辅轴对齐',
111
- type: 'radioGroup',
112
- childType: 'button',
113
- labelWidth: '68px',
114
- options: [
115
- { value: 'flex-start', icon: markRaw(JustifyContentFlexStart), tooltip: '左对齐 flex-start' },
116
- { value: 'flex-end', icon: markRaw(JustifyContentFlexEnd), tooltip: '右对齐 flex-end' },
117
- { value: 'center', icon: markRaw(JustifyContentCenter), tooltip: '居中 center' },
118
- { value: 'space-between', icon: markRaw(JustifyContentSpaceBetween), tooltip: '两端对齐 space-between' },
119
- { value: 'space-around', icon: markRaw(JustifyContentSpaceAround), tooltip: '横向平分 space-around' },
120
- ],
121
- display: (_mForm, { model }: { model: Record<any, any> }) => model.display === 'flex',
122
- },
123
- {
124
- name: 'flexWrap',
125
- text: '换行',
126
- type: 'radioGroup',
127
- childType: 'button',
128
- labelWidth: '68px',
129
- options: [
130
- { value: 'nowrap', text: '不换行', tooltip: '不换行 nowrap' },
131
- { value: 'wrap', text: '正换行', tooltip: '第一行在上方 wrap' },
132
- { value: 'wrap-reverse', text: '逆换行', tooltip: '第一行在下方 wrap-reverse' },
133
- ],
134
- display: (_mForm, { model }: { model: Record<any, any> }) => model.display === 'flex',
135
- },
136
- {
137
- type: 'row',
138
- items: [
139
- {
140
- name: 'width',
141
- text: '宽度',
142
- labelWidth: '68px',
143
- type: 'data-source-field-select',
144
- fieldConfig: {
145
- type: 'text',
146
- },
150
+ },
151
+ {
152
+ name: 'height',
153
+ text: '高度',
154
+ labelWidth: '68px',
155
+ type: 'data-source-field-select',
156
+ fieldConfig: {
157
+ type: 'text',
147
158
  },
148
- {
149
- name: 'height',
150
- text: '高度',
151
- labelWidth: '68px',
152
- type: 'data-source-field-select',
153
- fieldConfig: {
154
- type: 'text',
155
- },
159
+ },
160
+ ],
161
+ },
162
+ {
163
+ type: 'row',
164
+ items: [
165
+ {
166
+ type: 'data-source-field-select',
167
+ text: 'overflow',
168
+ name: 'overflow',
169
+ labelWidth: '68px',
170
+ checkStrictly: false,
171
+ dataSourceFieldType: ['string'],
172
+ fieldConfig: {
173
+ type: 'select',
174
+ clearable: true,
175
+ allowCreate: true,
176
+ options: [
177
+ { text: 'visible', value: 'visible' },
178
+ { text: 'hidden', value: 'hidden' },
179
+ { text: 'clip', value: 'clip' },
180
+ { text: 'scroll', value: 'scroll' },
181
+ { text: 'auto', value: 'auto' },
182
+ { text: 'overlay', value: 'overlay' },
183
+ { text: 'initial', value: 'initial' },
184
+ ],
156
185
  },
157
- ],
158
- },
159
- {
160
- type: 'row',
161
- items: [
162
- {
163
- type: 'data-source-field-select',
164
- text: 'overflow',
165
- name: 'overflow',
166
- labelWidth: '68px',
167
- checkStrictly: false,
168
- dataSourceFieldType: ['string'],
169
- fieldConfig: {
170
- type: 'select',
171
- clearable: true,
172
- allowCreate: true,
173
- options: [
174
- { text: 'visible', value: 'visible' },
175
- { text: 'hidden', value: 'hidden' },
176
- { text: 'clip', value: 'clip' },
177
- { text: 'scroll', value: 'scroll' },
178
- { text: 'auto', value: 'auto' },
179
- { text: 'overlay', value: 'overlay' },
180
- { text: 'initial', value: 'initial' },
181
- ],
182
- },
186
+ },
187
+ {
188
+ type: 'data-source-field-select',
189
+ text: '透明度',
190
+ name: 'opacity',
191
+ labelWidth: '68px',
192
+ dataSourceFieldType: ['string', 'number'],
193
+ fieldConfig: {
194
+ type: 'text',
183
195
  },
184
- {
185
- type: 'data-source-field-select',
186
- text: '透明度',
187
- name: 'opacity',
188
- labelWidth: '68px',
189
- dataSourceFieldType: ['string', 'number'],
190
- fieldConfig: {
191
- type: 'text',
192
- },
193
- },
194
- ],
195
- },
196
- ],
197
- }) as ChildConfig;
196
+ },
197
+ ],
198
+ },
199
+ ]);
198
200
 
199
201
  const change = (value: string | StyleSchema, eventData: ContainerChangeEventData) => {
200
202
  emit('change', value, eventData);
@@ -1,6 +1,9 @@
1
1
  <template>
2
2
  <MContainer
3
- :config="config"
3
+ v-for="(item, index) in formConfig"
4
+ :prop="prop"
5
+ :key="index"
6
+ :config="item"
4
7
  :model="values"
5
8
  :last-values="lastValues"
6
9
  :is-compare="isCompare"
@@ -12,7 +15,7 @@
12
15
  </template>
13
16
 
14
17
  <script lang="ts" setup>
15
- import { type ContainerChangeEventData, defineFormItem, MContainer } from '@tmagic/form';
18
+ import { type ContainerChangeEventData, defineFormConfig, MContainer } from '@tmagic/form';
16
19
  import type { StyleSchema } from '@tmagic/schema';
17
20
 
18
21
  const props = defineProps<{
@@ -21,6 +24,7 @@ const props = defineProps<{
21
24
  isCompare?: boolean;
22
25
  disabled?: boolean;
23
26
  size?: 'large' | 'default' | 'small';
27
+ prop?: string;
24
28
  }>();
25
29
 
26
30
  const emit = defineEmits<{
@@ -36,78 +40,76 @@ const positionText: Record<string, string> = {
36
40
  sticky: '粘性定位',
37
41
  };
38
42
 
39
- const config = defineFormItem({
40
- items: [
41
- {
42
- name: 'position',
43
- text: '定位',
44
- labelWidth: '68px',
45
- type: 'data-source-field-select',
46
- fieldConfig: {
47
- type: 'select',
48
- options: Object.keys(positionText).map((item) => ({
49
- value: item,
50
- text: `${item}(${positionText[item]})`,
51
- })),
52
- },
43
+ const formConfig = defineFormConfig([
44
+ {
45
+ name: 'position',
46
+ text: '定位',
47
+ labelWidth: '68px',
48
+ type: 'data-source-field-select',
49
+ fieldConfig: {
50
+ type: 'select',
51
+ options: Object.keys(positionText).map((item) => ({
52
+ value: item,
53
+ text: `${item}(${positionText[item]})`,
54
+ })),
53
55
  },
54
- {
55
- type: 'row',
56
- labelWidth: '68px',
57
- display: () => props.values.position !== 'static',
58
- items: [
59
- {
60
- name: 'left',
61
- type: 'data-source-field-select',
62
- text: 'left',
63
- fieldConfig: {
64
- type: 'text',
65
- },
56
+ },
57
+ {
58
+ type: 'row',
59
+ labelWidth: '68px',
60
+ display: () => props.values.position !== 'static',
61
+ items: [
62
+ {
63
+ name: 'left',
64
+ type: 'data-source-field-select',
65
+ text: 'left',
66
+ fieldConfig: {
67
+ type: 'text',
66
68
  },
67
- {
68
- name: 'top',
69
- type: 'data-source-field-select',
70
- text: 'top',
71
- fieldConfig: {
72
- type: 'text',
73
- },
69
+ },
70
+ {
71
+ name: 'top',
72
+ type: 'data-source-field-select',
73
+ text: 'top',
74
+ fieldConfig: {
75
+ type: 'text',
74
76
  },
75
- ],
76
- },
77
- {
78
- type: 'row',
79
- labelWidth: '68px',
80
- display: () => props.values.position !== 'static',
81
- items: [
82
- {
83
- name: 'right',
84
- type: 'data-source-field-select',
85
- text: 'right',
86
- fieldConfig: {
87
- type: 'text',
88
- },
77
+ },
78
+ ],
79
+ },
80
+ {
81
+ type: 'row',
82
+ labelWidth: '68px',
83
+ display: () => props.values.position !== 'static',
84
+ items: [
85
+ {
86
+ name: 'right',
87
+ type: 'data-source-field-select',
88
+ text: 'right',
89
+ fieldConfig: {
90
+ type: 'text',
89
91
  },
90
- {
91
- name: 'bottom',
92
- type: 'data-source-field-select',
93
- text: 'bottom',
94
- fieldConfig: {
95
- type: 'text',
96
- },
92
+ },
93
+ {
94
+ name: 'bottom',
95
+ type: 'data-source-field-select',
96
+ text: 'bottom',
97
+ fieldConfig: {
98
+ type: 'text',
97
99
  },
98
- ],
99
- },
100
- {
101
- labelWidth: '68px',
102
- name: 'zIndex',
103
- text: 'zIndex',
104
- type: 'data-source-field-select',
105
- fieldConfig: {
106
- type: 'text',
107
100
  },
101
+ ],
102
+ },
103
+ {
104
+ labelWidth: '68px',
105
+ name: 'zIndex',
106
+ text: 'zIndex',
107
+ type: 'data-source-field-select',
108
+ fieldConfig: {
109
+ type: 'text',
108
110
  },
109
- ],
110
- });
111
+ },
112
+ ]);
111
113
 
112
114
  const change = (value: string | StyleSchema, eventData: ContainerChangeEventData) => {
113
115
  emit('change', value, eventData);
@@ -1,5 +1,6 @@
1
1
  <template>
2
2
  <MContainer
3
+ :prop="prop"
3
4
  :config="config"
4
5
  :model="values"
5
6
  :last-values="lastValues"
@@ -21,6 +22,7 @@ defineProps<{
21
22
  isCompare?: boolean;
22
23
  disabled?: boolean;
23
24
  size?: 'large' | 'default' | 'small';
25
+ prop?: string;
24
26
  }>();
25
27
 
26
28
  const emit = defineEmits<{
@@ -29,33 +31,29 @@ const emit = defineEmits<{
29
31
  }>();
30
32
 
31
33
  const config = defineFormItem({
34
+ name: 'transform',
32
35
  items: [
33
36
  {
34
- name: 'transform',
35
- items: [
36
- {
37
- name: 'rotate',
38
- text: '旋转角度',
39
- labelWidth: '68px',
40
- type: 'data-source-field-select',
41
- checkStrictly: false,
42
- dataSourceFieldType: ['string', 'number'],
43
- fieldConfig: {
44
- type: 'text',
45
- },
46
- },
47
- {
48
- name: 'scale',
49
- text: '缩放',
50
- labelWidth: '68px',
51
- type: 'data-source-field-select',
52
- checkStrictly: false,
53
- dataSourceFieldType: ['string', 'number'],
54
- fieldConfig: {
55
- type: 'text',
56
- },
57
- },
58
- ],
37
+ name: 'rotate',
38
+ text: '旋转角度',
39
+ labelWidth: '68px',
40
+ type: 'data-source-field-select',
41
+ checkStrictly: false,
42
+ dataSourceFieldType: ['string', 'number'],
43
+ fieldConfig: {
44
+ type: 'text',
45
+ },
46
+ },
47
+ {
48
+ name: 'scale',
49
+ text: '缩放',
50
+ labelWidth: '68px',
51
+ type: 'data-source-field-select',
52
+ checkStrictly: false,
53
+ dataSourceFieldType: ['string', 'number'],
54
+ fieldConfig: {
55
+ type: 'text',
56
+ },
59
57
  },
60
58
  ],
61
59
  });
@@ -127,15 +127,3 @@ const unhighlight = () => {
127
127
  stageOverlayService.get('stage')?.clearHighlight();
128
128
  };
129
129
  </script>
130
-
131
- <style lang="scss">
132
- .m-fields-ui-select {
133
- cursor: pointer;
134
- i {
135
- margin-right: 3px;
136
- }
137
- span {
138
- color: #2882e0;
139
- }
140
- }
141
- </style>
package/src/index.ts CHANGED
@@ -48,6 +48,7 @@ export { default as componentListService } from './services/componentList';
48
48
  export { default as keybindingService } from './services/keybinding';
49
49
  export { default as ComponentListPanel } from './layouts/sidebar/ComponentListPanel.vue';
50
50
  export { default as LayerPanel } from './layouts/sidebar/layer/LayerPanel.vue';
51
+ export { default as LayerNodeContent } from './layouts/sidebar/layer/LayerNodeContent.vue';
51
52
  export { default as CodeSelect } from './fields/CodeSelect.vue';
52
53
  export { default as CodeSelectCol } from './fields/CodeSelectCol.vue';
53
54
  export { default as DataSourceFields } from './fields/DataSourceFields.vue';
@@ -194,6 +194,9 @@ const values = ref('');
194
194
  const loading = ref(false);
195
195
  const codeEditorEl = useTemplateRef<HTMLDivElement>('codeEditor');
196
196
 
197
+ // 组件是否已卸载,避免异步初始化过程中组件被销毁后继续创建编辑器
198
+ let destroyed = false;
199
+
197
200
  const resizeObserver = new globalThis.ResizeObserver(
198
201
  throttle((): void => {
199
202
  vsEditor?.layout();
@@ -254,11 +257,18 @@ const handleKeyDown = (e: KeyboardEvent) => {
254
257
  }
255
258
  };
256
259
 
260
+ // 判断容器是否仍然有效:组件未卸载、ref 存在且已挂载到文档树中
261
+ // Monaco 在创建编辑器时会向上遍历 parentNode 判断是否处于 shadow DOM,
262
+ // 若容器为 null 或已从文档树脱离,将抛出 "Cannot read properties of null (reading 'parentNode')"
263
+ const isEditorElValid = () => !destroyed && !!codeEditorEl.value && codeEditorEl.value.isConnected;
264
+
257
265
  const init = async () => {
258
- if (!codeEditorEl.value) return;
266
+ if (!isEditorElValid()) return;
259
267
 
260
- if (codeEditorEl.value.clientHeight === 0) {
268
+ if (codeEditorEl.value!.clientHeight === 0) {
261
269
  await nextTick();
270
+ // await 期间组件可能已被卸载或容器被移除
271
+ if (!isEditorElValid()) return;
262
272
  }
263
273
 
264
274
  // 重置缓存的额外高度,因为编辑器重新初始化
@@ -266,6 +276,11 @@ const init = async () => {
266
276
 
267
277
  monaco = await loadMonaco();
268
278
 
279
+ // 加载 monaco 是异步过程,期间组件可能已被卸载或容器被移除
280
+ if (!isEditorElValid()) return;
281
+
282
+ const editorEl = codeEditorEl.value!;
283
+
269
284
  const options = {
270
285
  value: values.value,
271
286
  language: props.language,
@@ -275,7 +290,7 @@ const init = async () => {
275
290
  };
276
291
 
277
292
  if (props.type === 'diff') {
278
- vsDiffEditor = await getEditorConfig('customCreateMonacoDiffEditor')(monaco!, codeEditorEl.value, options);
293
+ vsDiffEditor = await getEditorConfig('customCreateMonacoDiffEditor')(monaco!, editorEl, options);
279
294
 
280
295
  // 监听diff编辑器内容变化
281
296
  vsDiffEditor.getModifiedEditor().onDidChangeModelContent(() => {
@@ -285,7 +300,7 @@ const init = async () => {
285
300
  }
286
301
  });
287
302
  } else {
288
- vsEditor = await getEditorConfig('customCreateMonacoEditor')(monaco!, codeEditorEl.value, options);
303
+ vsEditor = await getEditorConfig('customCreateMonacoEditor')(monaco!, editorEl, options);
289
304
 
290
305
  // 监听编辑器内容变化
291
306
  vsEditor.onDidChangeModelContent(() => {
@@ -296,10 +311,19 @@ const init = async () => {
296
311
  });
297
312
  }
298
313
 
314
+ // 编辑器创建可能是异步的,创建完成后若组件已卸载则立即销毁,避免内存泄漏
315
+ if (destroyed) {
316
+ vsEditor?.dispose();
317
+ vsDiffEditor?.dispose();
318
+ vsEditor = null;
319
+ vsDiffEditor = null;
320
+ return;
321
+ }
322
+
299
323
  setEditorValue(props.initValues, props.modifiedValues);
300
324
 
301
325
  emit('initd', vsEditor);
302
- codeEditorEl.value.addEventListener('keydown', handleKeyDown);
326
+ editorEl.addEventListener('keydown', handleKeyDown);
303
327
 
304
328
  if (props.type !== 'diff' && props.autoSave) {
305
329
  vsEditor?.onDidBlurEditorWidget(() => {
@@ -311,7 +335,7 @@ const init = async () => {
311
335
  });
312
336
  }
313
337
 
314
- resizeObserver.observe(codeEditorEl.value);
338
+ resizeObserver.observe(editorEl);
315
339
  };
316
340
 
317
341
  watch(
@@ -362,6 +386,8 @@ onMounted(async () => {
362
386
  });
363
387
 
364
388
  onBeforeUnmount(() => {
389
+ destroyed = true;
390
+
365
391
  resizeObserver.disconnect();
366
392
 
367
393
  vsEditor?.dispose();