@tmagic/editor 1.8.0-beta.13 → 1.8.0-beta.15

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 (127) hide show
  1. package/dist/es/Editor.vue_vue_type_script_setup_true_lang.js +15 -3
  2. package/dist/es/components/ContentMenu.vue_vue_type_script_setup_true_lang.js +31 -8
  3. package/dist/es/components/FloatingBox.vue_vue_type_script_setup_true_lang.js +7 -2
  4. package/dist/es/fields/Code.vue_vue_type_script_setup_true_lang.js +15 -4
  5. package/dist/es/fields/CodeLink.vue_vue_type_script_setup_true_lang.js +4 -1
  6. package/dist/es/fields/CodeSelect.vue_vue_type_script_setup_true_lang.js +80 -55
  7. package/dist/es/fields/CodeSelectCol.vue_vue_type_script_setup_true_lang.js +5 -1
  8. package/dist/es/fields/CondOpSelect.vue_vue_type_script_setup_true_lang.js +4 -1
  9. package/dist/es/fields/DataSourceFieldSelect/Index.vue_vue_type_script_setup_true_lang.js +10 -7
  10. package/dist/es/fields/DataSourceFields.vue_vue_type_script_setup_true_lang.js +4 -1
  11. package/dist/es/fields/DataSourceInput.vue_vue_type_script_setup_true_lang.js +4 -1
  12. package/dist/es/fields/DataSourceMethodSelect.vue_vue_type_script_setup_true_name_true_lang.js +4 -1
  13. package/dist/es/fields/DataSourceMethods.vue_vue_type_script_setup_true_lang.js +4 -1
  14. package/dist/es/fields/DataSourceMocks.vue_vue_type_script_setup_true_lang.js +4 -1
  15. package/dist/es/fields/DataSourceSelect.vue_vue_type_script_setup_true_lang.js +4 -1
  16. package/dist/es/fields/DisplayConds.vue_vue_type_script_setup_true_lang.js +8 -2
  17. package/dist/es/fields/EventSelect.vue_vue_type_script_setup_true_lang.js +99 -64
  18. package/dist/es/fields/KeyValue.vue_vue_type_script_setup_true_lang.js +4 -1
  19. package/dist/es/fields/PageFragmentSelect.vue_vue_type_script_setup_true_lang.js +4 -1
  20. package/dist/es/fields/StyleSetter/Index.vue_vue_type_script_setup_true_lang.js +5 -4
  21. package/dist/es/fields/StyleSetter/components/BackgroundPosition.vue_vue_type_script_setup_true_lang.js +4 -1
  22. package/dist/es/fields/StyleSetter/components/Border.vue_vue_type_script_setup_true_lang.js +1 -1
  23. package/dist/es/fields/StyleSetter/icons/align-items/Center.js +31 -0
  24. package/dist/es/fields/StyleSetter/icons/align-items/FlexEnd.js +31 -0
  25. package/dist/es/fields/StyleSetter/icons/align-items/FlexStart.js +31 -0
  26. package/dist/es/fields/StyleSetter/icons/align-items/SpaceAround.js +50 -0
  27. package/dist/es/fields/StyleSetter/icons/align-items/SpaceBetween.js +50 -0
  28. package/dist/es/fields/StyleSetter/icons/background-repeat/NoRepeat.js +6 -6
  29. package/dist/es/fields/StyleSetter/icons/background-repeat/Repeat.js +5 -2
  30. package/dist/es/fields/StyleSetter/icons/background-repeat/RepeatX.js +28 -5
  31. package/dist/es/fields/StyleSetter/icons/background-repeat/RepeatY.js +31 -5
  32. package/dist/es/fields/StyleSetter/icons/flex-direction/Column.js +10 -2
  33. package/dist/es/fields/StyleSetter/icons/flex-direction/ColumnReverse.js +10 -2
  34. package/dist/es/fields/StyleSetter/icons/flex-direction/Row.js +10 -2
  35. package/dist/es/fields/StyleSetter/icons/flex-direction/RowReverse.js +10 -2
  36. package/dist/es/fields/StyleSetter/icons/justify-content/Center.js +16 -2
  37. package/dist/es/fields/StyleSetter/icons/justify-content/FlexEnd.js +18 -2
  38. package/dist/es/fields/StyleSetter/icons/justify-content/FlexStart.js +18 -2
  39. package/dist/es/fields/StyleSetter/icons/justify-content/SpaceAround.js +36 -2
  40. package/dist/es/fields/StyleSetter/icons/justify-content/SpaceBetween.js +32 -2
  41. package/dist/es/fields/StyleSetter/pro/Background.vue_vue_type_script_setup_true_lang.js +7 -6
  42. package/dist/es/fields/StyleSetter/pro/Font.vue_vue_type_script_setup_true_lang.js +6 -3
  43. package/dist/es/fields/StyleSetter/pro/Layout.vue_vue_type_script_setup_true_lang.js +47 -25
  44. package/dist/es/fields/UISelect.vue_vue_type_script_setup_true_lang.js +4 -1
  45. package/dist/es/icons/DatasourceIcon.js +17 -0
  46. package/dist/es/index.js +2 -2
  47. package/dist/es/layouts/Framework.vue_vue_type_script_setup_true_lang.js +14 -10
  48. package/dist/es/layouts/props-panel/PropsPanel.vue_vue_type_script_setup_true_lang.js +13 -4
  49. package/dist/es/layouts/sidebar/Sidebar.vue_vue_type_script_setup_true_lang.js +3 -3
  50. package/dist/es/plugin.js +2 -1
  51. package/dist/es/services/editor.js +86 -24
  52. package/dist/es/services/history.js +16 -0
  53. package/dist/es/services/ui.js +5 -3
  54. package/dist/es/style.css +307 -40
  55. package/dist/es/utils/config.js +4 -1
  56. package/dist/es/utils/const.js +2 -2
  57. package/dist/es/utils/data-source/index.js +4 -2
  58. package/dist/es/utils/props.js +43 -29
  59. package/dist/es/utils/type-match-rules.js +12 -5
  60. package/dist/style.css +307 -40
  61. package/dist/themes/magic-admin.css +3004 -0
  62. package/dist/tmagic-editor.umd.cjs +1161 -476
  63. package/package.json +7 -7
  64. package/src/Editor.vue +22 -1
  65. package/src/components/ContentMenu.vue +44 -8
  66. package/src/components/FloatingBox.vue +8 -2
  67. package/src/editorProps.ts +4 -0
  68. package/src/fields/Code.vue +10 -2
  69. package/src/fields/CodeSelect.vue +54 -43
  70. package/src/fields/CodeSelectCol.vue +1 -0
  71. package/src/fields/DataSourceFieldSelect/Index.vue +14 -5
  72. package/src/fields/DisplayConds.vue +4 -1
  73. package/src/fields/EventSelect.vue +56 -32
  74. package/src/fields/StyleSetter/Index.vue +1 -4
  75. package/src/fields/StyleSetter/components/Border.vue +1 -1
  76. package/src/fields/StyleSetter/icons/align-items/Center.vue +19 -0
  77. package/src/fields/StyleSetter/icons/align-items/FlexEnd.vue +19 -0
  78. package/src/fields/StyleSetter/icons/align-items/FlexStart.vue +19 -0
  79. package/src/fields/StyleSetter/icons/align-items/SpaceAround.vue +34 -0
  80. package/src/fields/StyleSetter/icons/align-items/SpaceBetween.vue +34 -0
  81. package/src/fields/StyleSetter/icons/align-items/index.ts +5 -0
  82. package/src/fields/StyleSetter/icons/background-repeat/NoRepeat.vue +20 -4
  83. package/src/fields/StyleSetter/icons/background-repeat/Repeat.vue +10 -28
  84. package/src/fields/StyleSetter/icons/background-repeat/RepeatX.vue +4 -5
  85. package/src/fields/StyleSetter/icons/background-repeat/RepeatY.vue +4 -5
  86. package/src/fields/StyleSetter/icons/flex-direction/Column.vue +4 -3
  87. package/src/fields/StyleSetter/icons/flex-direction/ColumnReverse.vue +4 -3
  88. package/src/fields/StyleSetter/icons/flex-direction/Row.vue +4 -3
  89. package/src/fields/StyleSetter/icons/flex-direction/RowReverse.vue +4 -3
  90. package/src/fields/StyleSetter/icons/justify-content/Center.vue +5 -2
  91. package/src/fields/StyleSetter/icons/justify-content/FlexEnd.vue +15 -2
  92. package/src/fields/StyleSetter/icons/justify-content/FlexStart.vue +15 -2
  93. package/src/fields/StyleSetter/icons/justify-content/SpaceAround.vue +28 -3
  94. package/src/fields/StyleSetter/icons/justify-content/SpaceBetween.vue +28 -2
  95. package/src/fields/StyleSetter/pro/Background.vue +7 -2
  96. package/src/fields/StyleSetter/pro/Font.vue +3 -3
  97. package/src/fields/StyleSetter/pro/Layout.vue +98 -28
  98. package/src/icons/DatasourceIcon.vue +7 -0
  99. package/src/index.ts +3 -0
  100. package/src/layouts/Framework.vue +7 -1
  101. package/src/layouts/props-panel/PropsPanel.vue +38 -12
  102. package/src/layouts/sidebar/Sidebar.vue +3 -3
  103. package/src/plugin.ts +3 -2
  104. package/src/services/editor.ts +76 -11
  105. package/src/services/history.ts +22 -1
  106. package/src/services/ui.ts +20 -5
  107. package/src/theme/code-block.scss +37 -0
  108. package/src/theme/common/var.scss +1 -1
  109. package/src/theme/component-list-panel.scss +2 -2
  110. package/src/theme/data-source-field.scss +4 -0
  111. package/src/theme/display-conds.scss +11 -0
  112. package/src/theme/event.scss +58 -4
  113. package/src/theme/framework.scss +4 -1
  114. package/src/theme/history-list-panel.scss +9 -9
  115. package/src/theme/nav-menu.scss +5 -1
  116. package/src/theme/props-panel.scss +2 -1
  117. package/src/theme/style-setter/border.scss +14 -5
  118. package/src/theme/theme.scss +1 -0
  119. package/src/theme/themes/magic-admin/index.scss +214 -0
  120. package/src/theme/ui-select.scss +1 -1
  121. package/src/type.ts +33 -6
  122. package/src/utils/config.ts +9 -1
  123. package/src/utils/const.ts +3 -2
  124. package/src/utils/data-source/index.ts +3 -3
  125. package/src/utils/props.ts +22 -9
  126. package/src/utils/type-match-rules.ts +11 -5
  127. package/types/index.d.ts +114 -35
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.8.0-beta.13",
2
+ "version": "1.8.0-beta.15",
3
3
  "name": "@tmagic/editor",
4
4
  "type": "module",
5
5
  "sideEffects": [
@@ -58,11 +58,11 @@
58
58
  "moveable": "^0.53.0",
59
59
  "serialize-javascript": "^7.0.0",
60
60
  "sortablejs": "^1.15.6",
61
- "@tmagic/form": "1.8.0-beta.13",
62
- "@tmagic/design": "1.8.0-beta.13",
63
- "@tmagic/stage": "1.8.0-beta.13",
64
- "@tmagic/utils": "1.8.0-beta.13",
65
- "@tmagic/table": "1.8.0-beta.13"
61
+ "@tmagic/design": "1.8.0-beta.15",
62
+ "@tmagic/form": "1.8.0-beta.15",
63
+ "@tmagic/table": "1.8.0-beta.15",
64
+ "@tmagic/utils": "1.8.0-beta.15",
65
+ "@tmagic/stage": "1.8.0-beta.15"
66
66
  },
67
67
  "devDependencies": {
68
68
  "@types/events": "^3.0.3",
@@ -76,7 +76,7 @@
76
76
  "type-fest": "^5.2.0",
77
77
  "typescript": "^6.0.3",
78
78
  "vue": "^3.5.40",
79
- "@tmagic/core": "1.8.0-beta.13"
79
+ "@tmagic/core": "1.8.0-beta.15"
80
80
  },
81
81
  "peerDependenciesMeta": {
82
82
  "typescript": {
package/src/Editor.vue CHANGED
@@ -4,6 +4,7 @@
4
4
  :page-bar-sort-options="pageBarSortOptions"
5
5
  :page-filter-function="pageFilterFunction"
6
6
  :hide-sidebar="hideSidebar"
7
+ :theme="theme"
7
8
  >
8
9
  <template #header>
9
10
  <slot name="header"></slot>
@@ -135,9 +136,10 @@
135
136
  <script lang="ts" setup>
136
137
  import { EventEmitter } from 'events';
137
138
 
138
- import { provide, ref } from 'vue';
139
+ import { computed, provide, ref } from 'vue';
139
140
 
140
141
  import type { MApp } from '@tmagic/core';
142
+ import { M_THEME_KEY } from '@tmagic/design';
141
143
 
142
144
  import Framework from './layouts/Framework.vue';
143
145
  import TMagicNavMenu from './layouts/NavMenu.vue';
@@ -241,6 +243,15 @@ provide(ENABLE_PROPS_FORM_VALIDATE, props.enablePropsFormValidate ?? false);
241
243
  * 与 PropsPanel 通过 `:extend-state` 显式传入的方式保持等价。
242
244
  */
243
245
  provide('extendFormState', props.extendFormState);
246
+
247
+ // 用 computed 包一层再 provide,否则传下去的是 provide 那一刻的值快照,
248
+ // props.isLargeStageContainer 后续变化不会同步到子孙(如 @tmagic/design/ColorPicker)。
249
+ // 子孙侧 `inject<ComputedRef<boolean>>('isLargeStageContainer', computed(() => false))`
250
+ // 用 `.value` 或模板自动解包读取即可拿到最新值。
251
+ provide(
252
+ 'isLargeStageContainer',
253
+ computed(() => props.isLargeStageContainer),
254
+ );
244
255
  /**
245
256
  * 提供 PropsPanel 主属性表单的 formState getter,供历史差异弹窗复用,
246
257
  * 让 CompareForm 与 PropsPanel 的 filterFunction 上下文保持一致。
@@ -256,6 +267,16 @@ provide('historyListExtraTabs', props.historyListExtraTabs);
256
267
 
257
268
  provide<EventBus>('eventBus', new EventEmitter());
258
269
 
270
+ /**
271
+ * 把当前主题以响应式 ref 形式 provide 给后代,供包含 `Teleport` 的组件
272
+ * (如 `TMagicPopover` / `FloatingBox` / `ContentMenu`)在传送目标上挂 `m-theme--<theme>`
273
+ * 类,让主题级 CSS 变量在 portal 节点上也能命中。详见 `@tmagic/design/theme.ts`。
274
+ */
275
+ provide(
276
+ M_THEME_KEY,
277
+ computed(() => props.theme ?? ''),
278
+ );
279
+
259
280
  const propsPanelMountedHandler = (e: InstanceType<typeof FormPanel>) => {
260
281
  propsPanelRef.value = e;
261
282
  emit('props-panel-mounted', e);
@@ -2,8 +2,8 @@
2
2
  <transition name="fade">
3
3
  <div
4
4
  v-show="visible"
5
- class="magic-editor-content-menu"
6
5
  ref="menu"
6
+ :class="['magic-editor-content-menu', themeClass]"
7
7
  :style="menuStyle"
8
8
  @mouseenter="mouseenterHandler()"
9
9
  @contextmenu.prevent
@@ -39,7 +39,7 @@
39
39
  <script lang="ts" setup>
40
40
  import { computed, nextTick, onBeforeUnmount, onMounted, type Ref, ref, useTemplateRef } from 'vue';
41
41
 
42
- import { useZIndex } from '@tmagic/design';
42
+ import { useThemeClass, useZIndex } from '@tmagic/design';
43
43
 
44
44
  import { MenuButton, MenuComponent } from '@editor/type';
45
45
 
@@ -73,6 +73,14 @@ const menuEl = useTemplateRef<HTMLDivElement>('menu');
73
73
  const buttonRefs = useTemplateRef<InstanceType<typeof ToolButton>[]>('buttons');
74
74
  const subMenuRef = useTemplateRef<any>('subMenu');
75
75
  const visible = ref(false);
76
+
77
+ /**
78
+ * 主题修饰类(来自最近的 `<MEditor>` / `<MForm>` 祖先 provide)。
79
+ * - 顶层 `ContentMenu` 渲染在编辑器子树中,加上去是冗余但无害;
80
+ * - 子菜单(递归 `<content-menu :is-sub-menu="true">` 被 `<teleport to="body">` 送到 body)
81
+ * 不在编辑器子树中,必须显式挂上主题类,主题级 CSS 变量才能命中。
82
+ */
83
+ const themeClass = useThemeClass();
76
84
  const subMenuData: Ref<(MenuButton | MenuComponent)[]> = ref<(MenuButton | MenuComponent)[]>([]);
77
85
  const zIndex = useZIndex();
78
86
  const curZIndex = ref<number>(0);
@@ -120,20 +128,42 @@ const outsideClickHideHandler = (e: MouseEvent) => {
120
128
  hide();
121
129
  };
122
130
 
123
- const setPosition = (e: { clientY: number; clientX: number }) => {
124
- const menuHeight = menuEl.value?.clientHeight || 0;
131
+ // 根据菜单实际尺寸修正位置,避免超出可视范围
132
+ const fixPosition = () => {
133
+ const menu = menuEl.value;
134
+ if (!menu || !visible.value) return;
135
+
136
+ const menuHeight = menu.clientHeight;
137
+ const menuWidth = menu.clientWidth;
138
+
139
+ let { top, left } = menuPosition.value;
125
140
 
126
- let top = e.clientY;
127
- if (menuHeight + e.clientY > document.body.clientHeight) {
128
- top = document.body.clientHeight - menuHeight;
141
+ if (top + menuHeight > document.body.clientHeight) {
142
+ top = Math.max(0, document.body.clientHeight - menuHeight);
129
143
  }
130
144
 
145
+ if (left + menuWidth > document.body.clientWidth) {
146
+ left = Math.max(0, document.body.clientWidth - menuWidth);
147
+ }
148
+
149
+ if (top !== menuPosition.value.top || left !== menuPosition.value.left) {
150
+ menuPosition.value = { top, left };
151
+ }
152
+ };
153
+
154
+ const setPosition = (e: { clientY: number; clientX: number }) => {
131
155
  menuPosition.value = {
132
- top,
156
+ top: e.clientY,
133
157
  left: e.clientX,
134
158
  };
159
+ fixPosition();
135
160
  };
136
161
 
162
+ // 菜单大小动态变化(如菜单项更新)后重新修正位置
163
+ const resizeObserver = new ResizeObserver(() => {
164
+ fixPosition();
165
+ });
166
+
137
167
  const show = (e?: { clientY: number; clientX: number }) => {
138
168
  visible.value = true;
139
169
 
@@ -178,12 +208,18 @@ const mouseenterHandler = () => {
178
208
  };
179
209
 
180
210
  onMounted(() => {
211
+ if (menuEl.value) {
212
+ resizeObserver.observe(menuEl.value);
213
+ }
214
+
181
215
  if (props.isSubMenu) return;
182
216
 
183
217
  globalThis.addEventListener('mousedown', outsideClickHideHandler, true);
184
218
  });
185
219
 
186
220
  onBeforeUnmount(() => {
221
+ resizeObserver.disconnect();
222
+
187
223
  if (props.isSubMenu) return;
188
224
 
189
225
  globalThis.removeEventListener('mousedown', outsideClickHideHandler, true);
@@ -2,7 +2,7 @@
2
2
  <Teleport to="body" v-if="visible">
3
3
  <div
4
4
  ref="target"
5
- class="m-editor-float-box"
5
+ :class="['m-editor-float-box', themeClass]"
6
6
  v-bind="$attrs"
7
7
  :style="{ ...style, zIndex: curZIndex }"
8
8
  @mousedown="nextZIndex"
@@ -27,7 +27,7 @@ import { computed, type CSSProperties, nextTick, onBeforeUnmount, provide, ref,
27
27
  import { Close } from '@element-plus/icons-vue';
28
28
  import VanillaMoveable from 'moveable';
29
29
 
30
- import { TMagicButton, useZIndex } from '@tmagic/design';
30
+ import { TMagicButton, useThemeClass, useZIndex } from '@tmagic/design';
31
31
 
32
32
  import MIcon from '@editor/components/Icon.vue';
33
33
 
@@ -62,6 +62,12 @@ const props = withDefaults(
62
62
  const targetEl = useTemplateRef<HTMLDivElement>('target');
63
63
  const titleEl = useTemplateRef<HTMLDivElement>('title');
64
64
 
65
+ /**
66
+ * 主题修饰类(来自最近的 `<MEditor>` / `<MForm>` 祖先 provide)。
67
+ * 挂在 `Teleport` 出去的浮动面板根节点上,让主题级 CSS 变量在 portal 节点上也能命中。
68
+ */
69
+ const themeClass = useThemeClass();
70
+
65
71
  const zIndex = useZIndex();
66
72
  const curZIndex = ref<number>(0);
67
73
 
@@ -35,6 +35,10 @@ import type {
35
35
  export const ENABLE_PROPS_FORM_VALIDATE: InjectionKey<boolean> = Symbol('enablePropsFormValidate');
36
36
 
37
37
  export interface EditorProps {
38
+ /** 是否是大屏模拟器容器,大屏容器时,左侧属性面板会扩展为两列(正常3列),颜色表单不扩展两列等 */
39
+ isLargeStageContainer?: boolean;
40
+
41
+ theme?: string;
38
42
  /** 页面初始值 */
39
43
  modelValue?: MApp;
40
44
  /** 左侧面板中的组件类型列表 */
@@ -1,5 +1,6 @@
1
1
  <template>
2
2
  <MagicCodeEditor
3
+ v-if="!silentMode"
3
4
  :height="config.height"
4
5
  :type="diffMode ? 'diff' : undefined"
5
6
  :init-values="diffMode ? (lastValues || {})[name] : model[name]"
@@ -17,9 +18,9 @@
17
18
  </template>
18
19
 
19
20
  <script lang="ts" setup>
20
- import { computed } from 'vue';
21
+ import { computed, inject } from 'vue';
21
22
 
22
- import type { CodeConfig, FieldProps } from '@tmagic/form';
23
+ import { type CodeConfig, type FieldProps, FORM_SILENT_MODE_KEY } from '@tmagic/form';
23
24
 
24
25
  import MagicCodeEditor from '@editor/layouts/CodeEditor.vue';
25
26
 
@@ -27,6 +28,13 @@ defineOptions({
27
28
  name: 'MFieldsVsCode',
28
29
  });
29
30
 
31
+ /**
32
+ * 静默模式(submitForm/validateForm 隐藏挂载)下跳过 monaco 渲染:
33
+ * 校验由 FormItem 针对 model 中的值完成,与编辑器实例无关;本组件挂载无值副作用
34
+ * (save 仅由用户操作/编辑器内容变更触发),跳过可省去 monaco worker/model 的无谓实例化。
35
+ */
36
+ const silentMode = inject(FORM_SILENT_MODE_KEY, false);
37
+
30
38
  const emit = defineEmits<{
31
39
  change: [value: string | any];
32
40
  }>();
@@ -1,9 +1,10 @@
1
1
  <template>
2
2
  <div class="m-fields-code-select" :class="config.className">
3
- <TMagicCard>
3
+ <TMagicCard :flat="config.flat">
4
4
  <MContainer
5
5
  :config="codeConfig"
6
6
  :size="size"
7
+ class="code-select-content"
7
8
  :prop="prop"
8
9
  :disabled="disabled"
9
10
  :is-compare="isCompareMode"
@@ -12,16 +13,20 @@
12
13
  @change="changeHandler"
13
14
  >
14
15
  </MContainer>
16
+ <TMagicButton class="create-button fullWidth" :icon="Plus" :size="size" :disabled="disabled" @click="newHandler()"
17
+ >添加{{ config.text }}</TMagicButton
18
+ >
15
19
  </TMagicCard>
16
20
  </div>
17
21
  </template>
18
22
 
19
23
  <script lang="ts" setup>
20
24
  import { computed, watch } from 'vue';
25
+ import { Plus } from '@element-plus/icons-vue';
21
26
  import { isEmpty } from 'lodash-es';
22
27
 
23
28
  import { HookCodeType, HookType } from '@tmagic/core';
24
- import { TMagicCard } from '@tmagic/design';
29
+ import { TMagicButton, TMagicCard } from '@tmagic/design';
25
30
  import type { CodeSelectConfig, ContainerChangeEventData, FieldProps, GroupListConfig } from '@tmagic/form';
26
31
  import { MContainer } from '@tmagic/form';
27
32
 
@@ -53,12 +58,23 @@ const props = withDefaults(defineProps<FieldProps<CodeSelectConfig>>(), {});
53
58
  * 仅当存在历史值时才启用对比,避免 lastValues 缺失时退化为「全部新增」的空对比。
54
59
  */
55
60
  const isCompareMode = computed(() => Boolean(props.isCompare && props.lastValues));
56
-
61
+ const newHandler = () => {
62
+ const defaultCode = {
63
+ codeType: HookCodeType.CODE,
64
+ codeId: '',
65
+ };
66
+ const name = props.config.name || '';
67
+ const hookData = props.model[name]?.hookData || [];
68
+ emit('change', defaultCode, {
69
+ modifyKey: `hookData.${hookData.length}`,
70
+ });
71
+ };
57
72
  const codeConfig = computed<GroupListConfig>(() => ({
58
73
  type: 'group-list',
59
74
  name: 'hookData',
60
75
  enableToggleMode: false,
61
76
  expandAll: true,
77
+ addable: () => false,
62
78
  title: (mForm, { model, index }: any) => {
63
79
  if (model.codeType === HookCodeType.DATA_SOURCE_METHOD) {
64
80
  if (Array.isArray(model.codeId)) {
@@ -81,49 +97,44 @@ const codeConfig = computed<GroupListConfig>(() => ({
81
97
 
82
98
  return model.codeId || index;
83
99
  },
100
+ titlePrefix: props.config.name === undefined ? undefined : String(props.config.name),
84
101
  items: [
85
102
  {
86
- type: 'row',
87
- items: [
88
- {
89
- type: 'select',
90
- name: 'codeType',
91
- span: 6,
92
- options: [
93
- { value: HookCodeType.CODE, text: '代码块' },
94
- { value: HookCodeType.DATA_SOURCE_METHOD, text: '数据源方法' },
95
- ],
96
- rules: [{ typeMatch: true, trigger: 'change' }],
97
- defaultValue: HookCodeType.CODE,
98
- onChange: (_mForm, v: HookCodeType, { setModel }) => {
99
- if (v === HookCodeType.DATA_SOURCE_METHOD) {
100
- setModel('codeId', []);
101
- } else {
102
- setModel('codeId', '');
103
- }
104
-
105
- return v;
106
- },
107
- },
108
- {
109
- type: 'code-select-col',
110
- name: 'codeId',
111
- span: 18,
112
- labelWidth: 0,
113
- display: (_mForm, { model }) => model.codeType !== HookCodeType.DATA_SOURCE_METHOD,
114
- notEditable: () => !codeBlockService.getEditStatus(),
115
- rules: [{ typeMatch: true, trigger: 'change' }],
116
- },
117
- {
118
- type: 'data-source-method-select',
119
- name: 'codeId',
120
- span: 18,
121
- labelWidth: 0,
122
- display: (_mForm, { model }) => model.codeType === HookCodeType.DATA_SOURCE_METHOD,
123
- notEditable: () => !dataSourceService.get('editable'),
124
- rules: [{ typeMatch: true, trigger: 'change' }],
125
- },
103
+ text: '代码类型',
104
+ type: 'select',
105
+ name: 'codeType',
106
+ labelPosition: 'right',
107
+ rules: [{ typeMatch: true, trigger: 'change' }],
108
+ options: [
109
+ { value: HookCodeType.CODE, text: '代码块' },
110
+ { value: HookCodeType.DATA_SOURCE_METHOD, text: '数据源方法' },
126
111
  ],
112
+ defaultValue: HookCodeType.CODE,
113
+ onChange: (_mForm, v: HookCodeType, { setModel }) => {
114
+ if (v === HookCodeType.DATA_SOURCE_METHOD) {
115
+ setModel('codeId', []);
116
+ } else {
117
+ setModel('codeId', '');
118
+ }
119
+ return v;
120
+ },
121
+ },
122
+ {
123
+ type: 'code-select-col',
124
+ name: 'codeId',
125
+ text: '代码块',
126
+ rules: [{ typeMatch: true, trigger: 'change' }],
127
+
128
+ display: (_mForm, { model }) => model.codeType !== HookCodeType.DATA_SOURCE_METHOD,
129
+ notEditable: () => !codeBlockService.getEditStatus(),
130
+ },
131
+ {
132
+ type: 'data-source-method-select',
133
+ name: 'codeId',
134
+ text: '数据源字段',
135
+ rules: [{ typeMatch: true, trigger: 'change' }],
136
+ display: (_mForm, { model }) => model.codeType === HookCodeType.DATA_SOURCE_METHOD,
137
+ notEditable: () => !dataSourceService.get('editable'),
127
138
  },
128
139
  ],
129
140
  }));
@@ -147,6 +147,7 @@ const selectConfig: SelectConfig = {
147
147
  type: 'select',
148
148
  name: props.name,
149
149
  disabled: props.disabled,
150
+ text: props.config.text,
150
151
  options: () => {
151
152
  if (codeDsl.value) {
152
153
  return map(codeDsl.value, (value, key) => ({
@@ -1,7 +1,12 @@
1
1
  <template>
2
- <div class="m-fields-data-source-field-select">
2
+ <div
3
+ class="m-fields-data-source-field-select"
4
+ :class="{
5
+ [`data-source-field-${type}`]: !isSelectValid,
6
+ }"
7
+ >
3
8
  <FieldSelect
4
- v-if="!disabledDataSource && (showDataSourceFieldSelect || !config.fieldConfig)"
9
+ v-if="isSelectValid"
5
10
  :model-value="model[name]"
6
11
  :disabled="disabled"
7
12
  :size="size"
@@ -37,15 +42,14 @@
37
42
  :size="size"
38
43
  :disabled="disabled"
39
44
  @click="onToggleDataSourceFieldSelectHandler"
40
- ><MIcon :icon="Coin"></MIcon
41
- ></TMagicButton>
45
+ ><MIcon :icon="dataSourceIcon"></MIcon>
46
+ </TMagicButton>
42
47
  </TMagicTooltip>
43
48
  </div>
44
49
  </template>
45
50
 
46
51
  <script setup lang="ts">
47
52
  import { computed, inject, ref, resolveComponent, watch } from 'vue';
48
- import { Coin } from '@element-plus/icons-vue';
49
53
 
50
54
  import { DataSchema } from '@tmagic/core';
51
55
  import { TMagicButton, tMagicMessage, TMagicTooltip } from '@tmagic/design';
@@ -61,6 +65,8 @@ import { DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX, removeDataSourceFieldPrefix } f
61
65
  import MIcon from '@editor/components/Icon.vue';
62
66
  import { useServices } from '@editor/hooks/use-services';
63
67
 
68
+ import dataSourceIcon from '../../icons/DatasourceIcon.vue';
69
+
64
70
  import FieldSelect from './FieldSelect.vue';
65
71
 
66
72
  defineOptions({
@@ -75,6 +81,9 @@ const props = withDefaults(defineProps<FieldProps<DataSourceFieldSelectConfig>>(
75
81
 
76
82
  const showDataSourceFieldSelect = ref(false);
77
83
 
84
+ const isSelectValid = computed(
85
+ () => !disabledDataSource.value && (showDataSourceFieldSelect.value || !props.config.fieldConfig),
86
+ );
78
87
  watch(
79
88
  () => props.model[props.name],
80
89
  (value) => {
@@ -68,12 +68,15 @@ const config = computed<GroupListConfig>(() => ({
68
68
  titlePrefix: props.config.titlePrefix,
69
69
  expandAll: true,
70
70
  enableToggleMode: false,
71
+ flat: props.config.flat,
71
72
  items: [
72
73
  {
73
74
  type: 'table',
74
75
  name: 'cond',
75
- operateColWidth: 80,
76
+ operateColWidth: props.config.operateColWidth,
76
77
  enableToggleMode: false,
78
+ fixed: props.config.fixed,
79
+ flat: props.config.flat,
77
80
  items: [
78
81
  parentFields.value.length
79
82
  ? {
@@ -12,16 +12,21 @@
12
12
  @change="onChangeHandler"
13
13
  ></MTable>
14
14
 
15
- <div v-else class="fullWidth">
16
- <TMagicButton
17
- v-if="!isCompareMode"
18
- class="create-button"
19
- type="primary"
20
- :size="size"
21
- :disabled="disabled"
22
- @click="addEvent()"
23
- >添加事件</TMagicButton
24
- >
15
+ <div v-else class="fullWidth event-select-container">
16
+ <div class="event-select-header">
17
+ <div class="event-select-title">事件配置</div>
18
+ <TMagicButton
19
+ v-if="!isCompareMode && displayList.length > 0"
20
+ class="create-button"
21
+ text
22
+ type="primary"
23
+ :icon="Plus"
24
+ :size="size"
25
+ :disabled="disabled"
26
+ @click="addEvent()"
27
+ >添加事件</TMagicButton
28
+ >
29
+ </div>
25
30
  <MPanel
26
31
  v-for="entry in displayList"
27
32
  :key="entry.index"
@@ -32,32 +37,45 @@
32
37
  :model="entry.cardItem"
33
38
  :last-values="entry.lastCardItem"
34
39
  :is-compare="isCompareMode"
40
+ :hide-expand="true"
35
41
  :label-width="config.labelWidth || '100px'"
36
42
  @change="onChangeHandler"
37
43
  >
38
44
  <template #header>
39
- <MFormContainer
40
- class="fullWidth"
41
- :config="eventNameConfig"
42
- :model="entry.cardItem"
43
- :last-values="entry.lastCardItem"
44
- :is-compare="isCompareMode"
45
- :disabled="disabled"
46
- :size="size"
47
- :prop="`${prop}.${entry.index}`"
48
- @change="eventNameChangeHandler"
49
- ></MFormContainer>
50
- <TMagicButton
51
- v-if="!isCompareMode"
52
- style="color: #f56c6c"
53
- link
54
- :icon="Delete"
55
- :disabled="disabled"
56
- :size="size"
57
- @click="removeEvent(Number(entry.index))"
58
- ></TMagicButton>
45
+ <div class="event-item-header">
46
+ <div class="event-item-title">事件{{ Number(entry.index) + 1 }}</div>
47
+ <MFormContainer
48
+ class="fullWidth"
49
+ :config="eventNameConfig"
50
+ :model="entry.cardItem"
51
+ :last-values="entry.lastCardItem"
52
+ :is-compare="isCompareMode"
53
+ :disabled="disabled"
54
+ :size="size"
55
+ :prop="`${prop}.${entry.index}`"
56
+ @change="eventNameChangeHandler"
57
+ ></MFormContainer>
58
+ <TMagicButton
59
+ class="event-item-delete-button"
60
+ v-if="!isCompareMode"
61
+ link
62
+ :icon="Delete"
63
+ :disabled="disabled"
64
+ :size="size"
65
+ @click="removeEvent(Number(entry.index))"
66
+ ></TMagicButton>
67
+ </div>
59
68
  </template>
60
69
  </MPanel>
70
+
71
+ <TMagicButton
72
+ v-if="!isCompareMode"
73
+ class="create-button fullWidth"
74
+ :icon="Plus"
75
+ :disabled="disabled"
76
+ @click="addEvent()"
77
+ >添加事件</TMagicButton
78
+ >
61
79
  </div>
62
80
  </div>
63
81
  </template>
@@ -65,6 +83,7 @@
65
83
  <script lang="ts" setup>
66
84
  import { computed } from 'vue';
67
85
  import { Delete } from '@element-plus/icons-vue';
86
+ import { Plus } from '@element-plus/icons-vue';
68
87
  import { has } from 'lodash-es';
69
88
 
70
89
  import { ActionType } from '@tmagic/core';
@@ -108,7 +127,7 @@ const { editorService, dataSourceService, eventsService, codeBlockService, props
108
127
  const eventNameConfig = computed(() => {
109
128
  const defaultEventNameConfig = {
110
129
  name: 'name',
111
- text: '事件',
130
+ text: '事件类型',
112
131
  type: (mForm: FormState | undefined, { formValue }: any) => {
113
132
  if (
114
133
  props.config.src !== 'component' ||
@@ -118,7 +137,7 @@ const eventNameConfig = computed(() => {
118
137
  }
119
138
  return 'select';
120
139
  },
121
- labelWidth: '40px',
140
+ labelWidth: '70px',
122
141
  checkStrictly: () => props.config.src !== 'component',
123
142
  valueSeparator: '.',
124
143
  options: (_mForm: FormState, { formValue }: any) => getEventNameOptions(props.config.src, formValue),
@@ -178,6 +197,7 @@ const actionTypeConfig = computed(() => {
178
197
  name: 'actionType',
179
198
  text: '联动类型',
180
199
  type: 'select',
200
+ labelPosition: 'left',
181
201
  defaultValue: ActionType.COMP,
182
202
  options: actionTypeOptions.value,
183
203
  rules: [
@@ -200,6 +220,7 @@ const targetCompConfig = computed(() => {
200
220
  name: 'to',
201
221
  text: '联动组件',
202
222
  type: 'ui-select',
223
+ labelPosition: 'left',
203
224
  display: (_mForm, { model }) => model.actionType === ActionType.COMP,
204
225
  onChange: (_MForm, _v, { setModel }) => {
205
226
  setModel('method', '');
@@ -219,6 +240,7 @@ const compActionConfig = computed(() => {
219
240
  const defaultCompActionConfig: DynamicTypeConfig = {
220
241
  name: 'method',
221
242
  text: '动作',
243
+ labelPosition: 'left',
222
244
  type: (mForm: FormState | undefined, { model }: any) => {
223
245
  const to = editorService.getNodeById(model.to);
224
246
 
@@ -317,6 +339,7 @@ const actionsConfig = computed(
317
339
  () =>
318
340
  defineFormItem({
319
341
  type: 'panel',
342
+ labelPosition: 'left',
320
343
  items: [
321
344
  {
322
345
  type: 'group-list',
@@ -324,6 +347,7 @@ const actionsConfig = computed(
324
347
  expandAll: true,
325
348
  enableToggleMode: false,
326
349
  titlePrefix: '动作',
350
+ labelPosition: 'left',
327
351
  items: [
328
352
  actionTypeConfig.value,
329
353
  targetCompConfig.value,
@@ -2,7 +2,7 @@
2
2
  <TMagicCollapse class="m-fields-style-setter" v-model="collapseValue">
3
3
  <template v-for="(item, index) in list" :key="index">
4
4
  <TMagicCollapseItem :name="`${index}`">
5
- <template #title><MIcon :icon="Grid"></MIcon>{{ item.title }}</template>
5
+ <template #title>{{ item.title }}</template>
6
6
  <component
7
7
  v-if="item.component"
8
8
  :is="item.component"
@@ -22,14 +22,11 @@
22
22
 
23
23
  <script setup lang="ts">
24
24
  import { shallowRef } from 'vue';
25
- import { Grid } from '@element-plus/icons-vue';
26
25
 
27
26
  import { TMagicCollapse, TMagicCollapseItem } from '@tmagic/design';
28
27
  import type { ContainerChangeEventData, FieldProps } from '@tmagic/form';
29
28
  import type { StyleSchema } from '@tmagic/schema';
30
29
 
31
- import MIcon from '@editor/components/Icon.vue';
32
-
33
30
  import { Background, Border, Font, Layout, Position, Transform } from './pro/';
34
31
 
35
32
  defineOptions({