@tmagic/editor 1.7.5-beta.1 → 1.7.5

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.
@@ -8,7 +8,7 @@ import editorService from '@editor/services/editor';
8
8
  import uiService from '@editor/services/ui';
9
9
  import type { StageOptions } from '@editor/type';
10
10
  import { H_GUIDE_LINE_STORAGE_KEY, UI_SELECT_MODE_EVENT_NAME, V_GUIDE_LINE_STORAGE_KEY } from '@editor/utils/const';
11
- import { getGuideLineFromCache } from '@editor/utils/editor';
11
+ import { buildChangeRecords, getGuideLineFromCache } from '@editor/utils/editor';
12
12
 
13
13
  const root = computed(() => editorService.get('root'));
14
14
  const page = computed(() => editorService.get('page'));
@@ -94,7 +94,15 @@ export const useStage = (stageOptions: StageOptions) => {
94
94
  return;
95
95
  }
96
96
 
97
- editorService.update(ev.data.map((data) => ({ id: getIdFromEl()(data.el) || '', style: data.style })));
97
+ // 为每个元素单独更新,确保 changeRecords 与对应的元素关联
98
+ ev.data.forEach((data) => {
99
+ const id = getIdFromEl()(data.el);
100
+ if (!id) return;
101
+
102
+ const { style = {} } = data;
103
+
104
+ editorService.update({ id, style }, { changeRecords: buildChangeRecords(style, 'style') });
105
+ });
98
106
  });
99
107
 
100
108
  stage.on('sort', (ev: SortEventData) => {
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div :class="`magic-code-editor`">
2
+ <div class="magic-code-editor">
3
3
  <Teleport to="body" :disabled="!fullScreen">
4
4
  <div :class="{ 'magic-code-editor-wrapper': true, 'full-screen': fullScreen }" :style="{ height: computeHeight }">
5
5
  <TMagicButton
@@ -47,6 +47,7 @@ const props = withDefaults(
47
47
  minRows?: number;
48
48
  maxRows?: number;
49
49
  };
50
+ editorCustomType?: string;
50
51
  }>(),
51
52
  {
52
53
  initValues: '',
@@ -63,6 +64,7 @@ const props = withDefaults(
63
64
  const emit = defineEmits(['initd', 'save']);
64
65
 
65
66
  const autoHeight = ref<string>('');
67
+ let cachedExtraHeight: number | null = null;
66
68
 
67
69
  const computeHeight = computed(() => {
68
70
  if (fullScreen.value) {
@@ -80,6 +82,41 @@ const computeHeight = computed(() => {
80
82
  return '100%';
81
83
  });
82
84
 
85
+ const calculateExtraHeight = (): number => {
86
+ let extraHeight = 10; // 默认值
87
+
88
+ if (vsEditor && codeEditorEl.value) {
89
+ try {
90
+ // 获取编辑器容器的总高度和内容区域高度
91
+ const editorElement = codeEditorEl.value.querySelector('.monaco-editor');
92
+ const scrollableElement = codeEditorEl.value.querySelector('.monaco-scrollable-element');
93
+
94
+ if (editorElement && scrollableElement) {
95
+ const editorRect = editorElement.getBoundingClientRect();
96
+ const scrollableRect = scrollableElement.getBoundingClientRect();
97
+
98
+ // 计算编辑器的边框、内边距等额外高度
99
+ extraHeight = Math.max(editorRect.height - scrollableRect.height, 0);
100
+
101
+ // 如果无法获取到有效的差值,使用编辑器配置中的相关选项
102
+ if (extraHeight === 0) {
103
+ const editorOptions = vsEditor.getOptions();
104
+ const scrollBeyondLastLine = editorOptions.get(monaco.editor.EditorOption.scrollBeyondLastLine);
105
+ const padding = editorOptions.get(monaco.editor.EditorOption.padding);
106
+ const lineHeight = editorOptions.get(monaco.editor.EditorOption.lineHeight) || 20;
107
+
108
+ extraHeight = (scrollBeyondLastLine ? lineHeight : 0) + (padding?.top || 0) + (padding?.bottom || 0) + 10; // 基础边距
109
+ }
110
+ }
111
+ } catch (error) {
112
+ // 如果获取失败,保持默认值
113
+ console.warn('Failed to calculate editor extra height:', error);
114
+ }
115
+ }
116
+
117
+ return extraHeight;
118
+ };
119
+
83
120
  const setAutoHeight = (v = '') => {
84
121
  let lines = Math.max(v.split('\n').length, props.autosize?.minRows || 1);
85
122
  if (v) {
@@ -95,7 +132,12 @@ const setAutoHeight = (v = '') => {
95
132
  lineHeight = editorOptions.get(monaco.editor.EditorOption.lineHeight) || 20;
96
133
  }
97
134
 
98
- const newHeight = `${lines * lineHeight + 10}px`;
135
+ // 获取缓存的额外高度,如果没有缓存则计算并缓存
136
+ if (cachedExtraHeight === null) {
137
+ cachedExtraHeight = calculateExtraHeight();
138
+ }
139
+
140
+ const newHeight = `${lines * lineHeight + cachedExtraHeight}px`;
99
141
 
100
142
  // 只有当高度真正改变时才更新
101
143
  if (autoHeight.value !== newHeight) {
@@ -210,10 +252,14 @@ const init = async () => {
210
252
  await nextTick();
211
253
  }
212
254
 
255
+ // 重置缓存的额外高度,因为编辑器重新初始化
256
+ cachedExtraHeight = null;
257
+
213
258
  const options = {
214
259
  value: values.value,
215
260
  language: props.language,
216
261
  theme: 'vs-dark',
262
+ editorCustomType: props.editorCustomType,
217
263
  ...props.options,
218
264
  };
219
265
 
@@ -297,6 +343,9 @@ onBeforeUnmount(() => {
297
343
 
298
344
  vsEditor = null;
299
345
  vsDiffEditor = null;
346
+
347
+ // 重置缓存
348
+ cachedExtraHeight = null;
300
349
  });
301
350
  onUnmounted(() => {
302
351
  codeEditorEl.value?.removeEventListener('keydown', handleKeyDown);
@@ -7,7 +7,13 @@
7
7
  <slot name="content-before"></slot>
8
8
 
9
9
  <slot name="src-code" v-if="showSrc">
10
- <CodeEditor class="m-editor-content" :init-values="root" :options="codeOptions" @save="saveCode"></CodeEditor>
10
+ <CodeEditor
11
+ class="m-editor-content"
12
+ editor-custom-type="m-editor-content"
13
+ :init-values="root"
14
+ :options="codeOptions"
15
+ @save="saveCode"
16
+ ></CodeEditor>
11
17
  </slot>
12
18
 
13
19
  <SplitView
@@ -32,6 +32,7 @@
32
32
  <CodeEditor
33
33
  v-if="showSrc"
34
34
  class="m-editor-props-panel-src-code"
35
+ editor-custom-type="m-editor-props-panel-src-code"
35
36
  :height="`${editorContentHeight}px`"
36
37
  :init-values="codeValueKey ? values[codeValueKey] : values"
37
38
  :options="codeOptions"
package/src/type.ts CHANGED
@@ -123,12 +123,12 @@ export interface EditorInstallOptions {
123
123
  customCreateMonacoEditor: (
124
124
  monaco: typeof Monaco,
125
125
  codeEditorEl: HTMLElement,
126
- options: Monaco.editor.IStandaloneEditorConstructionOptions,
126
+ options: Monaco.editor.IStandaloneEditorConstructionOptions & { editorCustomType?: string },
127
127
  ) => Monaco.editor.IStandaloneCodeEditor;
128
128
  customCreateMonacoDiffEditor: (
129
129
  monaco: typeof Monaco,
130
130
  codeEditorEl: HTMLElement,
131
- options: Monaco.editor.IStandaloneEditorConstructionOptions,
131
+ options: Monaco.editor.IStandaloneEditorConstructionOptions & { editorCustomType?: string },
132
132
  ) => Monaco.editor.IStandaloneDiffEditor;
133
133
  [key: string]: any;
134
134
  }
@@ -1,11 +1,6 @@
1
1
  import { DataSchema, DataSourceFieldType, DataSourceSchema } from '@tmagic/core';
2
2
  import { CascaderOption, FormConfig, FormState } from '@tmagic/form';
3
- import {
4
- DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX,
5
- dataSourceTemplateRegExp,
6
- getKeysArray,
7
- isNumber,
8
- } from '@tmagic/utils';
3
+ import { dataSourceTemplateRegExp, getKeysArray, isNumber } from '@tmagic/utils';
9
4
 
10
5
  import BaseFormConfig from './formConfigs/base';
11
6
  import HttpFormConfig from './formConfigs/http';
@@ -211,41 +206,44 @@ export const getCascaderOptionsFromFields = (
211
206
  fields: DataSchema[] = [],
212
207
  dataSourceFieldType: DataSourceFieldType[] = ['any'],
213
208
  ): CascaderOption[] => {
214
- const child: CascaderOption[] = [];
215
- fields.forEach((field) => {
216
- if (!dataSourceFieldType.length) {
217
- dataSourceFieldType.push('any');
218
- }
219
-
220
- let children: CascaderOption[] = [];
221
- if (field.type && ['any', 'array', 'object'].includes(field.type)) {
222
- children = getCascaderOptionsFromFields(field.fields, dataSourceFieldType);
223
- }
209
+ const typeSet = new Set(dataSourceFieldType.length ? dataSourceFieldType : ['any']);
210
+ const includesAny = typeSet.has('any');
224
211
 
225
- const item = {
226
- label: `${field.title || field.name}(${field.type})`,
227
- value: field.name,
228
- children,
229
- };
212
+ const result: CascaderOption[] = [];
230
213
 
214
+ for (const field of fields) {
231
215
  const fieldType = field.type || 'any';
232
- if (dataSourceFieldType.includes('any') || dataSourceFieldType.includes(fieldType)) {
233
- child.push(item);
234
- return;
235
- }
216
+ const isContainerType = fieldType === 'any' || fieldType === 'array' || fieldType === 'object';
236
217
 
237
- if (!dataSourceFieldType.includes(fieldType) && !['array', 'object', 'any'].includes(fieldType)) {
238
- return;
239
- }
218
+ const children = isContainerType ? getCascaderOptionsFromFields(field.fields, dataSourceFieldType) : [];
219
+
220
+ const matchesType = includesAny || typeSet.has(fieldType);
240
221
 
241
- if (!children.length && ['object', 'array', 'any'].includes(field.type || '')) {
242
- return;
222
+ if (matchesType || (isContainerType && children.length)) {
223
+ result.push({
224
+ label: `${field.title || field.name}(${field.type})`,
225
+ value: field.name,
226
+ children,
227
+ });
243
228
  }
229
+ }
244
230
 
245
- child.push(item);
246
- });
247
- return child;
231
+ return result;
248
232
  };
249
233
 
250
- export const removeDataSourceFieldPrefix = (id?: string) =>
251
- id?.replace(DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX, '') || '';
234
+ export const getFieldType = (ds: DataSourceSchema | undefined, fieldNames: string[]) => {
235
+ let fields = ds?.fields;
236
+ let type = '';
237
+
238
+ for (const fieldName of fieldNames) {
239
+ if (!fields?.length) return '';
240
+
241
+ const field = fields.find((f) => f.name === fieldName);
242
+ if (!field) return '';
243
+
244
+ type = field.type || '';
245
+ fields = field.fields;
246
+ }
247
+
248
+ return type;
249
+ };
@@ -411,3 +411,28 @@ export const isIncludeDataSource = (node: MNode, oldNode: MNode) => {
411
411
 
412
412
  return isIncludeDataSource;
413
413
  };
414
+
415
+ export const buildChangeRecords = (value: any, basePath: string) => {
416
+ const changeRecords: { propPath: string; value: any }[] = [];
417
+
418
+ // 递归构建 changeRecords
419
+ const buildChangeRecords = (obj: any, basePath: string) => {
420
+ Object.entries(obj).forEach(([key, value]) => {
421
+ if (value !== undefined) {
422
+ const currentPath = basePath ? `${basePath}.${key}` : key;
423
+
424
+ if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
425
+ // 递归处理嵌套对象
426
+ buildChangeRecords(value, currentPath);
427
+ } else {
428
+ // 处理基础类型值
429
+ changeRecords.push({ propPath: currentPath, value });
430
+ }
431
+ }
432
+ });
433
+ };
434
+
435
+ buildChangeRecords(value, basePath);
436
+
437
+ return changeRecords;
438
+ };
package/types/index.d.ts CHANGED
@@ -900,8 +900,12 @@ type BeforeAdd = (config: MNode, parent: MContainer) => Promise<MNode> | MNode;
900
900
  type GetConfig = (config: FormConfig) => Promise<FormConfig> | FormConfig;
901
901
  interface EditorInstallOptions {
902
902
  parseDSL: <T = any>(dsl: string) => T;
903
- customCreateMonacoEditor: (monaco: typeof monaco, codeEditorEl: HTMLElement, options: monaco.editor.IStandaloneEditorConstructionOptions) => monaco.editor.IStandaloneCodeEditor;
904
- customCreateMonacoDiffEditor: (monaco: typeof monaco, codeEditorEl: HTMLElement, options: monaco.editor.IStandaloneEditorConstructionOptions) => monaco.editor.IStandaloneDiffEditor;
903
+ customCreateMonacoEditor: (monaco: typeof monaco, codeEditorEl: HTMLElement, options: monaco.editor.IStandaloneEditorConstructionOptions & {
904
+ editorCustomType?: string;
905
+ }) => monaco.editor.IStandaloneCodeEditor;
906
+ customCreateMonacoDiffEditor: (monaco: typeof monaco, codeEditorEl: HTMLElement, options: monaco.editor.IStandaloneEditorConstructionOptions & {
907
+ editorCustomType?: string;
908
+ }) => monaco.editor.IStandaloneDiffEditor;
905
909
  [key: string]: any;
906
910
  }
907
911
  interface Services {
@@ -1610,6 +1614,10 @@ declare const fixNodePosition: (config: MNode, parent: MContainer, stage: StageC
1610
1614
  declare const serializeConfig: (config: any) => string;
1611
1615
  declare const moveItemsInContainer: (sourceIndices: number[], parent: MContainer, targetIndex: number) => void;
1612
1616
  declare const isIncludeDataSource: (node: MNode, oldNode: MNode) => boolean;
1617
+ declare const buildChangeRecords: (value: any, basePath: string) => {
1618
+ propPath: string;
1619
+ value: any;
1620
+ }[];
1613
1621
 
1614
1622
  /**
1615
1623
  * 粘贴前置操作:返回分配了新id以及校准了坐标的配置
@@ -1638,7 +1646,7 @@ declare const getDisplayField: (dataSources: DataSourceSchema[], key: string) =>
1638
1646
  type: "var" | "text";
1639
1647
  }[];
1640
1648
  declare const getCascaderOptionsFromFields: (fields?: DataSchema[], dataSourceFieldType?: DataSourceFieldType[]) => CascaderOption[];
1641
- declare const removeDataSourceFieldPrefix: (id?: string) => string;
1649
+ declare const getFieldType: (ds: DataSourceSchema | undefined, fieldNames: string[]) => string;
1642
1650
 
1643
1651
  interface IdleTaskEvents {
1644
1652
  finish: [];
@@ -2480,6 +2488,7 @@ type __VLS_Props$u = {
2480
2488
  minRows?: number;
2481
2489
  maxRows?: number;
2482
2490
  };
2491
+ editorCustomType?: string;
2483
2492
  };
2484
2493
  declare const __VLS_export$w: _vue_runtime_core.DefineComponent<__VLS_Props$u, {
2485
2494
  values: _vue_reactivity.Ref<string, string>;
@@ -3881,5 +3890,5 @@ declare const _default: {
3881
3890
  install: (app: App, opt?: Partial<EditorInstallOptions | DesignPluginOptions | FormInstallOptions>) => void;
3882
3891
  };
3883
3892
 
3884
- export { CODE_DRAFT_STORAGE_KEY, COPY_CODE_STORAGE_KEY, COPY_DS_STORAGE_KEY, COPY_STORAGE_KEY, _default$8 as CodeBlockEditor, _default$j as CodeBlockList, _default$i as CodeBlockListPanel, CodeDeleteErrorType, _default$u as CodeSelect, _default$t as CodeSelectCol, ColumnLayout, _default$w as ComponentListPanel, _default$2 as CondOpSelect, _default$c as ContentMenu, DEFAULT_LEFT_COLUMN_WIDTH, DEFAULT_RIGHT_COLUMN_WIDTH, _default$g as DataSourceAddButton, _default$h as DataSourceConfigPanel, _default$m as DataSourceFieldSelect, _default$s as DataSourceFields, _default$p as DataSourceInput, _default$n as DataSourceMethodSelect, _default$q as DataSourceMethods, _default$r as DataSourceMocks, _default$o as DataSourceSelect, _default$3 as DisplayConds, DragType, _default$l as EventSelect, Fixed2Other, _default$7 as FloatingBox, H_GUIDE_LINE_STORAGE_KEY, _default$b as Icon, IdleTask, KeyBindingCommand, _default$k as KeyValue, Keys, LEFT_COLUMN_WIDTH_STORAGE_KEY, LayerOffset, _default$v as LayerPanel, Layout, _default$a as LayoutContainer, MIN_CENTER_COLUMN_WIDTH, MIN_LEFT_COLUMN_WIDTH, MIN_RIGHT_COLUMN_WIDTH, PROPS_PANEL_WIDTH_STORAGE_KEY, _default$4 as PageFragmentSelect, _default$e as PropsFormPanel, _default$f as PropsPanel, RIGHT_COLUMN_WIDTH_STORAGE_KEY, _default$9 as Resizer, ScrollViewer, SideItemKey, _default$a as SplitView, _default$1 as StyleSetter, _default$x as TMagicCodeEditor, _default$y as TMagicEditor, _default$d as ToolButton, _default$6 as Tree, _default$5 as TreeNode, UI_SELECT_MODE_EVENT_NAME, UndoRedo, V_GUIDE_LINE_STORAGE_KEY, advancedTabConfig, arrayOptions, beforePaste, change2Fixed, _default$I as codeBlockService, _default$H as dataSourceService, debug, _default as default, _default$G as depService, displayTabConfig, _default$F as editorService, eqOptions, error, eventTabConfig, _default$E as eventsService, fillConfig, fixNodeLeft, fixNodePosition, generatePageName, generatePageNameByApp, getAddParent, getCascaderOptionsFromFields, getDefaultConfig, getDisplayField, getEditorConfig, getFormConfig, getFormValue, getGuideLineFromCache, getInitPositionStyle, getNodeIndex, getPageFragmentList, getPageList, getPageNameList, getPositionInContainer, getRelativeStyle, _default$D as historyService, info, isIncludeDataSource, log, moveItemsInContainer, numberOptions, _default$C as propsService, removeDataSourceFieldPrefix, serializeConfig, setChildrenLayout, setEditorConfig, setLayout, _default$B as stageOverlayService, _default$A as storageService, styleTabConfig, _default$z as uiService, updateStatus, useCodeBlockEdit, useEditorContentHeight, useFilter, useFloatBox, useGetSo, useNextFloatBoxPosition, useNodeStatus, useServices, useStage, useWindowRect, warn };
3893
+ export { CODE_DRAFT_STORAGE_KEY, COPY_CODE_STORAGE_KEY, COPY_DS_STORAGE_KEY, COPY_STORAGE_KEY, _default$8 as CodeBlockEditor, _default$j as CodeBlockList, _default$i as CodeBlockListPanel, CodeDeleteErrorType, _default$u as CodeSelect, _default$t as CodeSelectCol, ColumnLayout, _default$w as ComponentListPanel, _default$2 as CondOpSelect, _default$c as ContentMenu, DEFAULT_LEFT_COLUMN_WIDTH, DEFAULT_RIGHT_COLUMN_WIDTH, _default$g as DataSourceAddButton, _default$h as DataSourceConfigPanel, _default$m as DataSourceFieldSelect, _default$s as DataSourceFields, _default$p as DataSourceInput, _default$n as DataSourceMethodSelect, _default$q as DataSourceMethods, _default$r as DataSourceMocks, _default$o as DataSourceSelect, _default$3 as DisplayConds, DragType, _default$l as EventSelect, Fixed2Other, _default$7 as FloatingBox, H_GUIDE_LINE_STORAGE_KEY, _default$b as Icon, IdleTask, KeyBindingCommand, _default$k as KeyValue, Keys, LEFT_COLUMN_WIDTH_STORAGE_KEY, LayerOffset, _default$v as LayerPanel, Layout, _default$a as LayoutContainer, MIN_CENTER_COLUMN_WIDTH, MIN_LEFT_COLUMN_WIDTH, MIN_RIGHT_COLUMN_WIDTH, PROPS_PANEL_WIDTH_STORAGE_KEY, _default$4 as PageFragmentSelect, _default$e as PropsFormPanel, _default$f as PropsPanel, RIGHT_COLUMN_WIDTH_STORAGE_KEY, _default$9 as Resizer, ScrollViewer, SideItemKey, _default$a as SplitView, _default$1 as StyleSetter, _default$x as TMagicCodeEditor, _default$y as TMagicEditor, _default$d as ToolButton, _default$6 as Tree, _default$5 as TreeNode, UI_SELECT_MODE_EVENT_NAME, UndoRedo, V_GUIDE_LINE_STORAGE_KEY, advancedTabConfig, arrayOptions, beforePaste, buildChangeRecords, change2Fixed, _default$I as codeBlockService, _default$H as dataSourceService, debug, _default as default, _default$G as depService, displayTabConfig, _default$F as editorService, eqOptions, error, eventTabConfig, _default$E as eventsService, fillConfig, fixNodeLeft, fixNodePosition, generatePageName, generatePageNameByApp, getAddParent, getCascaderOptionsFromFields, getDefaultConfig, getDisplayField, getEditorConfig, getFieldType, getFormConfig, getFormValue, getGuideLineFromCache, getInitPositionStyle, getNodeIndex, getPageFragmentList, getPageList, getPageNameList, getPositionInContainer, getRelativeStyle, _default$D as historyService, info, isIncludeDataSource, log, moveItemsInContainer, numberOptions, _default$C as propsService, serializeConfig, setChildrenLayout, setEditorConfig, setLayout, _default$B as stageOverlayService, _default$A as storageService, styleTabConfig, _default$z as uiService, updateStatus, useCodeBlockEdit, useEditorContentHeight, useFilter, useFloatBox, useGetSo, useNextFloatBoxPosition, useNodeStatus, useServices, useStage, useWindowRect, warn };
3885
3894
  export type { AddMNode, AddPrefixToObject, AsyncAfterHook, AsyncBeforeHook, AsyncHookPlugin, BeforeAdd, CodeBlockListPanelSlots, CodeBlockListSlots, CodeDslItem, CodeParamStatement, CodeRelation, CodeState, CombineInfo, ComponentGroup, ComponentGroupState, ComponentItem, ComponentListPanelSlots, CustomContentMenuFunction, DataSourceListSlots, DatasourceTypeOption, EditorInstallOptions, EditorNodeInfo, EditorSlots, EventBus, EventBusEvent, FrameworkSlots, GetColumnWidth, GetConfig, HistoryState, IdleTaskEvents, KeyBindingCacheItem, KeyBindingItem, LayerNodeSlots, LayerNodeStatus, LayerPanelSlots, ListState, MenuBarData, MenuButton, MenuComponent, MenuItem, PageBarSortOptions, PartSortableOptions, PastePosition, PropsFormConfigFunction, PropsFormValueFunction, PropsPanelSlots, PropsState, ScrollViewerEvent, Services, SetColumnWidth, SideBarData, SideComponent, SideItem, SidebarSlots, StageOptions, StageOverlayState, StageRect, StepValue, StoreState, StoreStateKey, SyncAfterHook, SyncBeforeHook, SyncHookPlugin, TreeNodeData, UiState, WorkspaceSlots };