@tmagic/form 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 (77) hide show
  1. package/dist/es/Form.vue_vue_type_script_setup_true_lang.js +51 -16
  2. package/dist/es/FormDialog.vue_vue_type_script_setup_true_lang.js +12 -5
  3. package/dist/es/FormDrawer.vue_vue_type_script_setup_true_lang.js +38 -12
  4. package/dist/es/containers/Col.vue_vue_type_script_setup_true_lang.js +2 -1
  5. package/dist/es/containers/Container.vue_vue_type_script_setup_true_lang.js +27 -19
  6. package/dist/es/containers/GroupList.vue_vue_type_script_setup_true_lang.js +6 -5
  7. package/dist/es/containers/GroupListItem.vue_vue_type_script_setup_true_lang.js +41 -31
  8. package/dist/es/containers/Panel.vue_vue_type_script_setup_true_lang.js +16 -10
  9. package/dist/es/containers/table/ActionsColumn.vue_vue_type_script_setup_true_lang.js +13 -6
  10. package/dist/es/containers/table/Table.vue_vue_type_script_setup_true_lang.js +4 -2
  11. package/dist/es/containers/table/useTableColumns.js +5 -1
  12. package/dist/es/containers/table-group-list/TableGroupList.vue_vue_type_script_setup_true_lang.js +2 -1
  13. package/dist/es/fields/Cascader.vue_vue_type_script_setup_true_lang.js +5 -2
  14. package/dist/es/fields/Checkbox.vue_vue_type_script_setup_true_lang.js +4 -1
  15. package/dist/es/fields/CheckboxGroup.vue_vue_type_script_setup_true_lang.js +5 -2
  16. package/dist/es/fields/ColorPicker.vue_vue_type_script_setup_true_lang.js +4 -1
  17. package/dist/es/fields/Date.vue_vue_type_script_setup_true_lang.js +5 -2
  18. package/dist/es/fields/DateTime.vue_vue_type_script_setup_true_lang.js +5 -2
  19. package/dist/es/fields/Daterange.vue_vue_type_script_setup_true_lang.js +5 -2
  20. package/dist/es/fields/Display.vue_vue_type_script_setup_true_lang.js +5 -2
  21. package/dist/es/fields/DynamicField.vue_vue_type_script_setup_true_lang.js +4 -1
  22. package/dist/es/fields/Link.vue_vue_type_script_setup_true_lang.js +29 -7
  23. package/dist/es/fields/Number.vue_vue_type_script_setup_true_lang.js +7 -2
  24. package/dist/es/fields/NumberRange.vue_vue_type_script_setup_true_lang.js +4 -1
  25. package/dist/es/fields/RadioGroup.vue_vue_type_script_setup_true_lang.js +19 -9
  26. package/dist/es/fields/Select.vue_vue_type_script_setup_true_lang.js +4 -1
  27. package/dist/es/fields/Switch.vue_vue_type_script_setup_true_lang.js +4 -1
  28. package/dist/es/fields/Text.vue_vue_type_script_setup_true_lang.js +112 -77
  29. package/dist/es/fields/Textarea.vue_vue_type_script_setup_true_lang.js +4 -1
  30. package/dist/es/fields/Time.vue_vue_type_script_setup_true_lang.js +4 -1
  31. package/dist/es/fields/Timerange.vue_vue_type_script_setup_true_lang.js +6 -3
  32. package/dist/es/index.js +4 -4
  33. package/dist/es/plugin.js +3 -1
  34. package/dist/es/schema.js +11 -1
  35. package/dist/es/style.css +122 -8
  36. package/dist/es/submitForm.js +13 -11
  37. package/dist/es/utils/config.js +4 -1
  38. package/dist/es/utils/form.js +33 -3
  39. package/dist/es/utils/typeMatch.js +3 -1
  40. package/dist/style.css +122 -8
  41. package/dist/themes/magic-admin.css +499 -0
  42. package/dist/tmagic-form.umd.cjs +568 -300
  43. package/package.json +4 -4
  44. package/src/Form.vue +71 -18
  45. package/src/FormDialog.vue +14 -3
  46. package/src/FormDrawer.vue +40 -12
  47. package/src/containers/Col.vue +1 -0
  48. package/src/containers/Container.vue +21 -6
  49. package/src/containers/GroupList.vue +1 -1
  50. package/src/containers/GroupListItem.vue +28 -22
  51. package/src/containers/Panel.vue +10 -3
  52. package/src/containers/table/ActionsColumn.vue +10 -4
  53. package/src/containers/table/Table.vue +1 -0
  54. package/src/containers/table/useTableColumns.ts +7 -3
  55. package/src/containers/table-group-list/TableGroupList.vue +7 -1
  56. package/src/fields/Link.vue +16 -3
  57. package/src/fields/Number.vue +2 -1
  58. package/src/fields/RadioGroup.vue +21 -6
  59. package/src/fields/Text.vue +43 -19
  60. package/src/plugin.ts +3 -0
  61. package/src/schema.ts +11 -0
  62. package/src/submitForm.ts +34 -15
  63. package/src/theme/container.scss +3 -0
  64. package/src/theme/fieldset.scss +51 -0
  65. package/src/theme/form.scss +6 -0
  66. package/src/theme/group-list.scss +9 -7
  67. package/src/theme/index.scss +1 -0
  68. package/src/theme/link.scss +17 -0
  69. package/src/theme/panel.scss +1 -1
  70. package/src/theme/radio-group.scss +23 -0
  71. package/src/theme/tabs.scss +2 -2
  72. package/src/theme/text.scss +38 -0
  73. package/src/theme/themes/magic-admin/index.scss +95 -0
  74. package/src/utils/config.ts +7 -1
  75. package/src/utils/form.ts +37 -0
  76. package/src/utils/typeMatch.ts +10 -1
  77. package/types/index.d.ts +77 -5
@@ -37,11 +37,17 @@
37
37
  :size="addButtonSize"
38
38
  :plain="displayMode === 'table'"
39
39
  :icon="Plus"
40
+ text
40
41
  :disabled="disabled"
41
42
  v-bind="currentConfig.addButtonConfig?.props || { type: 'primary' }"
42
43
  @click="newHandler"
43
44
  >
44
- {{ currentConfig.addButtonConfig?.text || (displayMode === 'table' ? '新增一行' : '新增') }}
45
+ {{
46
+ currentConfig.addButtonConfig?.text ||
47
+ (displayMode === 'table'
48
+ ? `新增一行${groupListConfig.titlePrefix || ''}`
49
+ : `新增${groupListConfig.titlePrefix || ''}`)
50
+ }}
45
51
  </TMagicButton>
46
52
  </template>
47
53
  </component>
@@ -1,5 +1,16 @@
1
1
  <template>
2
- <a v-if="config.href && !disabled" target="_blank" :href="href" :style="config.css || {}">{{ displayText }}</a>
2
+ <a
3
+ target="_blank"
4
+ :href="href"
5
+ v-if="isGlobalFlat && config.href && !disabled"
6
+ class="magic-admin-link"
7
+ :style="config.css || {}"
8
+ >
9
+ <TMagicButton link type="primary">
10
+ <TMagicIcon><Notebook /></TMagicIcon>{{ displayText }}
11
+ </TMagicButton>
12
+ </a>
13
+ <a v-else-if="config.href && !disabled" target="_blank" :href="href" :style="config.css || {}">{{ displayText }}</a>
3
14
  <span v-else-if="config.href && disabled" :style="config.disabledCss || {}">{{ displayText }}</span>
4
15
  <div v-else class="m-fields-link">
5
16
  <TMagicButton link type="primary" @click="editHandler">点击编辑</TMagicButton>
@@ -18,18 +29,20 @@
18
29
 
19
30
  <script lang="ts" setup>
20
31
  import { computed, inject, readonly, ref } from 'vue';
32
+ import { Notebook } from '@element-plus/icons-vue';
21
33
 
22
- import { TMagicButton } from '@tmagic/design';
34
+ import { TMagicButton, TMagicIcon } from '@tmagic/design';
23
35
 
24
36
  import FormDialog from '../FormDialog.vue';
25
37
  import type { FieldProps, FormState, LinkConfig } from '../schema';
38
+ import { isGlobalFlat } from '../utils/config';
26
39
  import { useAddField } from '../utils/useAddField';
27
40
 
28
41
  defineOptions({
29
42
  name: 'MFormLink',
30
43
  });
31
44
 
32
- const props = defineProps<FieldProps<LinkConfig>>();
45
+ const props = defineProps<FieldProps<LinkConfig> & { theme?: string }>();
33
46
 
34
47
  const emit = defineEmits(['change']);
35
48
 
@@ -3,7 +3,7 @@
3
3
  v-if="model"
4
4
  v-model="value"
5
5
  clearable
6
- controls-position="right"
6
+ :controls-position="isGlobalFlat ? '' : 'right'"
7
7
  :size="size"
8
8
  :max="config.max"
9
9
  :min="config.min"
@@ -21,6 +21,7 @@ import { inject, ref, watch } from 'vue';
21
21
  import { TMagicInputNumber } from '@tmagic/design';
22
22
 
23
23
  import type { FieldProps, FormState, NumberConfig } from '../schema';
24
+ import { isGlobalFlat } from '../utils/config';
24
25
  import { useAddField } from '../utils/useAddField';
25
26
 
26
27
  defineOptions({
@@ -1,5 +1,11 @@
1
1
  <template>
2
- <TMagicRadioGroup v-if="model" :model-value="model[name]" :size="size" :disabled="disabled">
2
+ <TMagicRadioGroup
3
+ v-if="model"
4
+ :model-value="model[name]"
5
+ :size="size"
6
+ :disabled="disabled"
7
+ class="icon-{{ iconSize }}"
8
+ >
3
9
  <component
4
10
  v-for="option in config.options"
5
11
  :is="itemComponent"
@@ -8,9 +14,14 @@
8
14
  @click="clickHandler(option.value)"
9
15
  >
10
16
  <TMagicTooltip :disabled="!Boolean(option.tooltip)" placement="top-start" :content="option.tooltip">
11
- <div>
12
- <TMagicIcon v-if="option.icon" :size="iconSize"><component :is="option.icon"></component></TMagicIcon>
13
- <span v-if="option.text">{{ option.text }}</span>
17
+ <div class="m-fields-radio-group__option">
18
+ <TMagicIcon
19
+ v-if="option.icon"
20
+ :size="iconSize"
21
+ :class="{ 'm-fields-radio-group__icon_with_text': !!option.text }"
22
+ ><component :is="option.icon"></component
23
+ ></TMagicIcon>
24
+ <span v-if="option.text" class="m-fields-radio-group__text">{{ option.text }}</span>
14
25
  </div>
15
26
  </TMagicTooltip>
16
27
  </component>
@@ -45,13 +56,17 @@ const clickHandler = (item: string | number | boolean) => {
45
56
 
46
57
  useAddField(props.prop);
47
58
 
59
+ // 这里换了设计稿里的图标,所以需要调整一下图标大小
48
60
  const iconSize = computed(() => {
61
+ if (props.config.iconSize) {
62
+ return props.config.iconSize;
63
+ }
49
64
  if (props.size === 'small') {
50
- return '12';
65
+ return '14';
51
66
  }
52
67
  if (props.size === 'large') {
53
68
  return '16';
54
69
  }
55
- return '14';
70
+ return '16';
56
71
  });
57
72
  </script>
@@ -1,6 +1,31 @@
1
1
  <template>
2
- <div class="m-fields-text">
2
+ <div :class="['m-fields-text', { 'm-fields-text--static': config.static }]">
3
+ <div v-if="config.disabled"></div>
4
+ <!-- 新增静态展示文本样式 -->
5
+ <template v-if="config.static">
6
+ <span v-if="config.prepend" class="m-fields-text__prepend">{{ config.prepend }}</span>
7
+ <span class="m-fields-text__value">{{ value }}</span>
8
+ <template v-if="appendConfig">
9
+ <TMagicButton
10
+ v-if="appendConfig.type === 'button'"
11
+ style="color: #0056ea"
12
+ :size="size"
13
+ @click.prevent="buttonClickHandler"
14
+ >
15
+ {{ appendConfig.text }}
16
+ </TMagicButton>
17
+ <img
18
+ v-else-if="appendConfig.type === 'icon'"
19
+ class="m-fields-text__icon"
20
+ :src="appendConfig.text"
21
+ @click="buttonClickHandler"
22
+ />
23
+ <span v-else>{{ appendConfig.text }}</span>
24
+ </template>
25
+ </template>
26
+
3
27
  <TMagicInput
28
+ v-else
4
29
  v-model="value"
5
30
  ref="input"
6
31
  :clearable="config.clearable ?? true"
@@ -17,17 +42,18 @@
17
42
  <template #append v-if="appendConfig">
18
43
  <TMagicButton
19
44
  v-if="appendConfig.type === 'button'"
20
- style="color: #409eff"
45
+ style="color: #0056ea"
21
46
  :size="size"
22
47
  @click.prevent="buttonClickHandler"
23
48
  >
24
49
  {{ appendConfig.text }}
25
50
  </TMagicButton>
51
+ <img v-else-if="appendConfig.type === 'icon'" :src="appendConfig.text" @click="buttonClickHandler" />
26
52
  <span v-else>{{ appendConfig.text }}</span>
27
53
  </template>
28
54
  </TMagicInput>
29
55
 
30
- <Teleport to="body">
56
+ <Teleport to="body" v-if="!config.static">
31
57
  <div v-if="popoverVisible" class="tmagic-form-text-popper m-form-item__content" ref="popoverEl">
32
58
  <div class="m-form-validate__warning">输入内容前后有空格,是否移除空格?</div>
33
59
  <div style="display: flex; justify-content: flex-end">
@@ -80,28 +106,26 @@ watch(
80
106
  );
81
107
 
82
108
  const appendConfig = computed(() => {
83
- if (typeof props.config.append === 'string') {
109
+ const { append } = props.config;
110
+
111
+ // 字符串形态:纯文本 append。
112
+ if (typeof append === 'string') {
84
113
  return {
85
114
  type: 'text',
86
- text: props.config.append,
115
+ text: append,
87
116
  handler: undefined,
88
117
  };
89
118
  }
90
- if (typeof props.config.append === 'object') {
91
- if (typeof props.config.append?.handler === 'function') {
92
- return {
93
- type: 'button',
94
- text: props.config.append.text,
95
- handler: props.config.append.handler,
96
- };
97
- }
98
- if (props.config.append) {
99
- if (props.config.append.value === 0) {
100
- return false;
101
- }
102
119
 
103
- return props.config.append;
104
- }
120
+ // 对象形态:按 schema 定义,`type` 可为 `'button' | 'icon'`,`handler` 可选。
121
+ //
122
+ // 旧逻辑里只要带 handler 就强制覆盖为 `type: 'button'`,导致 schema 中显式传入的
123
+ // `type: 'icon'` 在到达模板前被抹掉(参见 `@editor/utils/props.ts` 中 ID 字段
124
+ // 的复制按钮配置)。这里直接返回原对象,模板按 `type` 分支渲染 button / icon / text。
125
+ if (typeof append === 'object' && append) {
126
+ // `value === 0` 沿用旧约定:作为「隐藏 append」的开关。
127
+ if (append.value === 0) return false;
128
+ return append;
105
129
  }
106
130
 
107
131
  return false;
package/src/plugin.ts CHANGED
@@ -50,11 +50,13 @@ import { setConfig } from './utils/config';
50
50
  import { registerTypeMatchRules, type TypeMatchValidator } from './utils/typeMatch';
51
51
  import Form from './Form.vue';
52
52
  import FormDialog from './FormDialog.vue';
53
+ import FormDrawer from './FormDrawer.vue';
53
54
 
54
55
  import './theme/index.scss';
55
56
 
56
57
  // #region FormInstallOptions
57
58
  export interface FormInstallOptions {
59
+ flat?: boolean;
58
60
  /** 自定义字段 type 的 typeMatch 校验规则,可覆盖内置规则或扩展业务字段 */
59
61
  typeMatchRules?: Record<string, TypeMatchValidator>;
60
62
  [key: string]: any;
@@ -76,6 +78,7 @@ export default {
76
78
 
77
79
  app.component('m-form', Form);
78
80
  app.component('m-form-dialog', FormDialog);
81
+ app.component('m-form-drawer', FormDrawer);
79
82
  app.component('m-form-container', Container);
80
83
  app.component('m-form-fieldset', Fieldset);
81
84
  app.component('m-form-group-list', TableGroupList);
package/src/schema.ts CHANGED
@@ -29,6 +29,17 @@ export interface FormDiffConfig {
29
29
  export const FORM_DIFF_CONFIG_KEY: InjectionKey<FormDiffConfig> = Symbol('mFormDiffConfig');
30
30
  export const FORM_TYPE_MATCH_VALID_KEY: InjectionKey<ComputedRef<boolean>> = Symbol('mFormTypeMatchValid');
31
31
 
32
+ /**
33
+ * 静默模式标记,由 `submitForm` / `validateForm` 以隐藏方式挂载临时表单时 provide(debug 弹层模式不提供)。
34
+ *
35
+ * 重型字段组件(如 vs-code)可 inject 该标记并跳过自身渲染:字段校验由 FormItem 基于 model 值完成,
36
+ * 与叶子 UI 组件实例无关,跳过可省去无谓的实例化开销(如 monaco worker / model 的创建)。
37
+ *
38
+ * 注意:仅「挂载无值副作用」(不在 onMounted/watch immediate 中 emit change、不依赖 DOM 计算值)的
39
+ * 字段组件可以安全跳过,接入前需逐一审计。
40
+ */
41
+ export const FORM_SILENT_MODE_KEY: InjectionKey<boolean> = Symbol('mFormSilentMode');
42
+
32
43
  export interface ValidateError {
33
44
  message: string;
34
45
  field: string;
package/src/submitForm.ts CHANGED
@@ -16,10 +16,22 @@
16
16
  * limitations under the License.
17
17
  */
18
18
 
19
- import { type AppContext, type Component, createApp, defineComponent, h, nextTick, type Ref, ref, watch } from 'vue';
20
-
19
+ import {
20
+ type AppContext,
21
+ type Component,
22
+ createApp,
23
+ defineComponent,
24
+ h,
25
+ nextTick,
26
+ provide,
27
+ type Ref,
28
+ ref,
29
+ watch,
30
+ } from 'vue';
31
+
32
+ import { applyExtendState } from './utils/form';
21
33
  import Form from './Form.vue';
22
- import type { ChangeRecord, FormConfig, FormState } from './schema';
34
+ import { type ChangeRecord, FORM_SILENT_MODE_KEY, type FormConfig, type FormState } from './schema';
23
35
 
24
36
  // #region SubmitFormOptions
25
37
  /**
@@ -192,17 +204,10 @@ const mountFormInstance = <T>(options: MountFormInstanceOptions<T>): Promise<T>
192
204
  console.error('[MForm] extendState failed:', e);
193
205
  return;
194
206
  }
195
- const apply = (state: Record<string, any> | null | undefined) => {
196
- if (!state) return;
197
- for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(state))) {
198
- if ('value' in descriptor) {
199
- (form.formState as any)[key] = (state as any)[key];
200
- } else {
201
- descriptor.configurable = true;
202
- Object.defineProperty(form.formState, key, descriptor);
203
- }
204
- }
205
- };
207
+ // 合并逻辑收口在 applyExtendState:props 派生的只读 getter 字段
208
+ // (keyProp 等)以普通字段形式返回时会被跳过并告警,避免 proxy set 抛错
209
+ const apply = (state: Record<string, any> | null | undefined) =>
210
+ applyExtendState(form.formState, state);
206
211
  if (result && typeof result.then === 'function') {
207
212
  result.then(apply, (e: any) => console.error('[MForm] extendState failed:', e));
208
213
  } else {
@@ -216,7 +221,21 @@ const mountFormInstance = <T>(options: MountFormInstanceOptions<T>): Promise<T>
216
221
  })
217
222
  : userWrapper;
218
223
 
219
- const app = createApp(wrapperComponent);
224
+ // 静默(隐藏挂载)模式下注入静默标记:vs-code 等重型字段组件可据此跳过自身渲染,
225
+ // 校验/取值依赖 FormItem 与 model 值,与叶子 UI 组件无关(见 FORM_SILENT_MODE_KEY 注释)。
226
+ // 用组件级 provide 而非 app.provide:appContext 合并后 app._context.provides 与父级应用
227
+ // 共享引用,app.provide 会把标记泄漏到父级应用。
228
+ const rootComponent = hidden
229
+ ? defineComponent({
230
+ name: 'MFormSilentProvider',
231
+ setup() {
232
+ provide(FORM_SILENT_MODE_KEY, true);
233
+ return () => h(wrapperComponent);
234
+ },
235
+ })
236
+ : wrapperComponent;
237
+
238
+ const app = createApp(rootComponent);
220
239
  instance.app = app;
221
240
 
222
241
  // 继承父级应用上下文(components / directives / provides / config 等)
@@ -22,4 +22,7 @@
22
22
  background: #f7dadd;
23
23
  }
24
24
  }
25
+ .m-form-title-extra {
26
+ margin-left: 8px;
27
+ }
25
28
  }
@@ -1,3 +1,54 @@
1
+ .m-container-fieldset {
2
+ &.no-border-fieldset {
3
+ &.fieldset-in-row {
4
+ > fieldset.m-fieldset {
5
+ legend {
6
+ left: 0;
7
+ }
8
+ }
9
+ }
10
+ > fieldset.m-fieldset {
11
+ border: 0;
12
+ legend {
13
+ position: relative;
14
+ left: -5px;
15
+ font-size: 16px;
16
+ font-weight: 500;
17
+ line-height: 24px;
18
+ padding: 0;
19
+ }
20
+ }
21
+ }
22
+ &.fieldset-in-card-fit {
23
+ border-bottom: 1px solid #e6e6e6;
24
+ > fieldset.m-fieldset {
25
+ padding: 16px 0 16px 0 !important;
26
+ border: 0;
27
+ margin-top: 0;
28
+ margin-bottom: 0;
29
+ legend {
30
+ position: relative;
31
+ top: 10px;
32
+ background-color: transparent;
33
+ }
34
+ }
35
+ &.fieldset-in-card-fit-last {
36
+ padding-bottom: 0 !important;
37
+ border-bottom: 0;
38
+ }
39
+ &.fieldset-in-card-fit-first {
40
+ padding-top: 0 !important;
41
+ }
42
+ &:last-child {
43
+ padding-bottom: 0 !important;
44
+ border-bottom: 0;
45
+ }
46
+ &:first {
47
+ padding-top: 0 !important;
48
+ }
49
+ }
50
+ }
51
+
1
52
  fieldset.m-fieldset {
2
53
  position: relative;
3
54
  border: 1px solid rgb(229, 229, 229);
@@ -53,3 +53,9 @@
53
53
  margin-bottom: var(--td-comp-margin-xxl);
54
54
  }
55
55
  }
56
+
57
+ .m-form-container {
58
+ .m-form-container-expand {
59
+ text-align: center;
60
+ }
61
+ }
@@ -1,4 +1,8 @@
1
1
  .m-fields-group-list {
2
+ .m-fields-group-list-item.tmagic-design-card--flat:last-child {
3
+ border: 0;
4
+ }
5
+
2
6
  .el-button--text {
3
7
  padding: 0;
4
8
  margin-bottom: 7px;
@@ -19,14 +23,11 @@
19
23
  &:last-of-type {
20
24
  border-bottom: 0;
21
25
  }
22
- }
23
26
 
24
- .tmagic-design-card {
25
- .el-card__header {
26
- padding: 5px 20px;
27
- }
28
- .t-card__header {
29
- padding: 5px 0;
27
+ .m-fields-group-list-item-header {
28
+ display: flex;
29
+ align-items: center;
30
+ gap: 8px;
30
31
  }
31
32
  }
32
33
 
@@ -34,5 +35,6 @@
34
35
  display: flex;
35
36
  justify-content: space-between;
36
37
  margin-top: 10px;
38
+ margin-bottom: 16px;
37
39
  }
38
40
  }
@@ -13,3 +13,4 @@
13
13
  @use "./tabs.scss";
14
14
  @use "./number-range.scss";
15
15
  @use "./form-box.scss";
16
+ @use "./radio-group.scss";
@@ -1,3 +1,20 @@
1
1
  div.m-fields-link {
2
2
  width: fit-content;
3
3
  }
4
+ a.magic-admin-link {
5
+ width: calc(100%);
6
+ box-sizing: border-box;
7
+ border-radius: 4px;
8
+ border: 1px solid #e6e6e6;
9
+ background-color: #fafafa;
10
+ padding: 0 8px;
11
+ height: 28px;
12
+ display: inline-flex;
13
+ gap: 4px;
14
+ align-items: center;
15
+ text-decoration: none;
16
+
17
+ i {
18
+ margin-right: 4px;
19
+ }
20
+ }
@@ -4,7 +4,7 @@
4
4
  background: #f2f6fc;
5
5
  }
6
6
  a {
7
- color: #409eff;
7
+ color: var(--el-color-primary, #409eff);
8
8
  }
9
9
  }
10
10
 
@@ -0,0 +1,23 @@
1
+ // 单个 radio option 的内容容器:横向排列 icon + 文本,垂直居中对齐。
2
+ // 这样多行文本(`text: '内联布局\n inline'`)能跟左侧 icon 在视觉中线对齐,
3
+ // 不会出现 icon 顶到第一行的错位。
4
+ .m-fields-radio-group__option {
5
+ display: flex;
6
+ align-items: center;
7
+ }
8
+
9
+ .m-fields-radio-group__text {
10
+ // `inline-block` 关键:inline span 的 line-height 会被父级 inline formatting
11
+ // context(如 `.el-radio-button__inner` 的 strut)覆盖,外观高度量出来会比
12
+ // `line-height` 大;显式声明 `inline-block` 让 span 有独立的格式化上下文,
13
+ // 自身 line-height 才真正生效。
14
+ display: inline-block;
15
+ vertical-align: middle;
16
+ // `pre-line` 让 `\n` 渲染为换行,同时保留自动折行。
17
+ white-space: pre-line;
18
+ line-height: 20px;
19
+ }
20
+
21
+ .m-fields-radio-group__icon_with_text {
22
+ margin-right: 8px;
23
+ }
@@ -5,8 +5,8 @@
5
5
  margin-right: auto;
6
6
  min-width: 50px;
7
7
  outline: none;
8
- border-color: #409eff;
9
- color: #409eff;
8
+ border-color: var(--el-color-primary, #409eff);
9
+ color: var(--el-color-primary, #409eff);
10
10
  width: 10px;
11
11
  &::before {
12
12
  content: "添加";
@@ -2,6 +2,30 @@
2
2
  display: flex;
3
3
  align-items: center;
4
4
  width: 100%;
5
+
6
+ // 纯文本(非输入框)形态:保留 prepend / append 槽位的横向布局。
7
+ // 配合 `TextConfig.static = true` 使用,常见于 ID 之类「只读 + 操作 icon」场景。
8
+ &--static {
9
+ gap: 6px;
10
+ min-height: 32px;
11
+
12
+ .m-fields-text__prepend {
13
+ color: var(--el-text-color-secondary, #909399);
14
+ }
15
+
16
+ .m-fields-text__value {
17
+ color: var(--el-text-color-regular, #606266);
18
+ overflow: hidden;
19
+ text-overflow: ellipsis;
20
+ white-space: nowrap;
21
+ }
22
+
23
+ .m-fields-text__icon {
24
+ width: 16px;
25
+ height: 16px;
26
+ cursor: pointer;
27
+ }
28
+ }
5
29
  }
6
30
 
7
31
  .m-form-validate__warning {
@@ -29,6 +53,20 @@
29
53
  }
30
54
  }
31
55
 
56
+ .m-container-text {
57
+ &.m-fields-title-container {
58
+ .tmagic-design-form-item {
59
+ .el-form-item__label {
60
+ color: #0f1113;
61
+ font-weight: 500;
62
+ font-size: 16px;
63
+ }
64
+ line-height: 24px;
65
+ margin-bottom: 16px;
66
+ }
67
+ }
68
+ }
69
+
32
70
  .tmagic-form-text-popper[data-popper-placement^="top"]
33
71
  > .tmagic-form-text-popper-arrow {
34
72
  bottom: -4px;
@@ -0,0 +1,95 @@
1
+ // magic-admin 主题:所有规则均以 `.m-form.m-form--magic-admin` 为前缀,
2
+ // 仅在 `<MForm theme="magic-admin" />` 时生效,避免污染默认样式。
3
+ @use "../../index.scss";
4
+
5
+ .m-form.m-form--magic-admin {
6
+ // 精确匹配"只挂 `m-form-container` + `m-container-fieldset` 这两个 class"的元素:
7
+ // `.a.b` 只能保证"包含"这两个 class,多余的 class 也会命中;
8
+ // 用 `[class="..."]` 做全量字符串等值匹配即可排除第三个 class 的情况。
9
+ // 由于 Vue/框架不保证 class 拼接顺序,两种顺序都列出以覆盖到位。
10
+ [class="m-form-container m-container-fieldset"],
11
+ [class="m-container-fieldset m-form-container"] {
12
+ margin-top: 15px;
13
+ }
14
+
15
+ .m-container-tab:not(.magic-right-panel-tabs-top):not(
16
+ .magic-form-dynamic-tab
17
+ ) {
18
+ > .tmagic-design-tabs:not(.el-tabs--border-card) {
19
+ > .el-tabs__content {
20
+ background-color: #fff;
21
+ padding: 16px 16px 0 16px;
22
+ border-radius: 4px;
23
+ }
24
+ }
25
+ }
26
+
27
+ .m-container-tab.magic-form-dynamic-tab {
28
+ }
29
+
30
+ .m-form-tip {
31
+ color: rgba(0, 0, 0, 0.55);
32
+ }
33
+
34
+ .tmagic-design-form-item {
35
+ &.show-after-diff {
36
+ background: #d4edbc;
37
+ }
38
+
39
+ &.show-before-diff {
40
+ background: #fad2cf;
41
+ }
42
+ }
43
+ .m-fields-radio-group__text {
44
+ // `pre-line` 让 `\n` 渲染为换行,同时保留自动折行;线高与默认按钮组高度对齐。
45
+ white-space: pre-line;
46
+ line-height: 20px;
47
+ }
48
+ .el-form-item__content {
49
+ .tmagic-design-radio-group {
50
+ .tmagic-design-radio-button {
51
+ height: 32px;
52
+ .el-radio-button__inner {
53
+ height: 32px;
54
+ display: flex;
55
+ padding-top: 0;
56
+ padding-bottom: 0;
57
+ align-items: center;
58
+ }
59
+ }
60
+ }
61
+ }
62
+ .m-fields-data-source-field-select .tmagic-design-button {
63
+ margin-left: 8px;
64
+ span {
65
+ font-size: 16px;
66
+ }
67
+ }
68
+
69
+ .m-fields-group-list-item.tmagic-design-card--flat {
70
+ .el-card__body {
71
+ .m-fields-table-wrap {
72
+ .m-fields-table {
73
+ .el-table__header-wrapper {
74
+ thead {
75
+ height: 48px;
76
+ }
77
+ }
78
+ }
79
+ }
80
+ }
81
+ .m-fields-group-list-item-header {
82
+ position: relative;
83
+ .delete-button {
84
+ position: absolute;
85
+ right: 0;
86
+ color: #0f1113;
87
+ }
88
+ }
89
+ }
90
+ .m-form-container {
91
+ .m-form-container-expand {
92
+ text-align: left;
93
+ }
94
+ }
95
+ }