@tmagic/editor 1.4.3 → 1.4.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.
Files changed (60) hide show
  1. package/dist/style.css +17 -3
  2. package/dist/tmagic-editor.js +1309 -1208
  3. package/dist/tmagic-editor.umd.cjs +1327 -1224
  4. package/package.json +19 -24
  5. package/src/Editor.vue +6 -1
  6. package/src/editorProps.ts +3 -0
  7. package/src/fields/CodeSelectCol.vue +26 -18
  8. package/src/fields/DataSourceFieldSelect.vue +23 -61
  9. package/src/fields/DataSourceMethodSelect.vue +25 -31
  10. package/src/fields/DataSourceSelect.vue +49 -13
  11. package/src/fields/EventSelect.vue +37 -14
  12. package/src/hooks/use-editor-content-height.ts +11 -5
  13. package/src/layouts/PropsPanel.vue +3 -1
  14. package/src/layouts/sidebar/Sidebar.vue +24 -8
  15. package/src/layouts/sidebar/code-block/CodeBlockListPanel.vue +6 -1
  16. package/src/layouts/sidebar/data-source/DataSourceListPanel.vue +6 -1
  17. package/src/layouts/workspace/viewer/Stage.vue +7 -6
  18. package/src/services/editor.ts +2 -2
  19. package/src/services/ui.ts +1 -0
  20. package/src/theme/data-source-field.scss +12 -0
  21. package/src/theme/props-panel.scss +1 -1
  22. package/src/theme/theme.scss +1 -0
  23. package/src/type.ts +31 -2
  24. package/src/utils/content-menu.ts +7 -3
  25. package/src/utils/data-source/index.ts +39 -3
  26. package/src/utils/editor.ts +14 -7
  27. package/types/components/CodeBlockEditor.vue.d.ts +21 -34
  28. package/types/components/CodeParams.vue.d.ts +2 -2
  29. package/types/components/ContentMenu.vue.d.ts +4 -4
  30. package/types/components/FloatingBox.vue.d.ts +41 -38
  31. package/types/components/ScrollViewer.vue.d.ts +1 -1
  32. package/types/components/ToolButton.vue.d.ts +6 -6
  33. package/types/components/Tree.vue.d.ts +2 -2
  34. package/types/editorProps.d.ts +3 -0
  35. package/types/fields/CodeLink.vue.d.ts +2 -2
  36. package/types/fields/DataSourceFields.vue.d.ts +32 -78
  37. package/types/fields/DataSourceInput.vue.d.ts +2 -2
  38. package/types/fields/DataSourceMethods.vue.d.ts +2 -2
  39. package/types/fields/DataSourceMocks.vue.d.ts +31 -76
  40. package/types/fields/KeyValue.vue.d.ts +2 -2
  41. package/types/fields/UISelect.vue.d.ts +2 -2
  42. package/types/hooks/use-code-block-edit.d.ts +18 -6
  43. package/types/hooks/use-data-source-edit.d.ts +18 -6
  44. package/types/hooks/use-data-source-method.d.ts +18 -6
  45. package/types/layouts/CodeEditor.vue.d.ts +1 -1
  46. package/types/layouts/PropsPanel.vue.d.ts +40 -38
  47. package/types/layouts/sidebar/Sidebar.vue.d.ts +7 -7
  48. package/types/layouts/sidebar/code-block/CodeBlockList.vue.d.ts +1 -1
  49. package/types/layouts/sidebar/data-source/DataSourceConfigPanel.vue.d.ts +20 -30
  50. package/types/layouts/sidebar/data-source/DataSourceList.vue.d.ts +1 -1
  51. package/types/layouts/sidebar/layer/LayerMenu.vue.d.ts +8 -8
  52. package/types/layouts/sidebar/layer/LayerPanel.vue.d.ts +4 -4
  53. package/types/layouts/sidebar/layer/use-click.d.ts +13 -13
  54. package/types/layouts/workspace/Workspace.vue.d.ts +4 -4
  55. package/types/layouts/workspace/viewer/Stage.vue.d.ts +4 -4
  56. package/types/layouts/workspace/viewer/ViewerMenu.vue.d.ts +8 -8
  57. package/types/services/dataSource.d.ts +1 -0
  58. package/types/services/ui.d.ts +19 -1
  59. package/types/type.d.ts +26 -2
  60. package/types/utils/data-source/index.d.ts +3 -2
@@ -15,7 +15,7 @@
15
15
  <TMagicButton class="create-button" type="primary" :size="size" :disabled="disabled" @click="addEvent()"
16
16
  >添加事件</TMagicButton
17
17
  >
18
- <m-form-panel
18
+ <MPanel
19
19
  v-for="(cardItem, index) in model[name]"
20
20
  :key="index"
21
21
  :disabled="disabled"
@@ -26,14 +26,14 @@
26
26
  @change="onChangeHandler"
27
27
  >
28
28
  <template #header>
29
- <m-form-container
29
+ <MContainer
30
30
  class="fullWidth"
31
31
  :config="eventNameConfig"
32
32
  :model="cardItem"
33
33
  :disabled="disabled"
34
34
  :size="size"
35
35
  @change="onChangeHandler"
36
- ></m-form-container>
36
+ ></MContainer>
37
37
  <TMagicButton
38
38
  style="color: #f56c6c"
39
39
  link
@@ -43,7 +43,7 @@
43
43
  @click="removeEvent(index)"
44
44
  ></TMagicButton>
45
45
  </template>
46
- </m-form-panel>
46
+ </MPanel>
47
47
  </div>
48
48
  </div>
49
49
  </template>
@@ -55,10 +55,13 @@ import { has } from 'lodash-es';
55
55
 
56
56
  import type { EventOption } from '@tmagic/core';
57
57
  import { TMagicButton } from '@tmagic/design';
58
- import type { FieldProps, FormState } from '@tmagic/form';
58
+ import type { CascaderOption, FieldProps, FormState, PanelConfig } from '@tmagic/form';
59
+ import { MContainer, MPanel } from '@tmagic/form';
59
60
  import { ActionType } from '@tmagic/schema';
61
+ import { DATA_SOURCE_FIELDS_CHANGE_EVENT_PREFIX } from '@tmagic/utils';
60
62
 
61
63
  import type { CodeSelectColConfig, DataSourceMethodSelectConfig, EventSelectConfig, Services } from '@editor/type';
64
+ import { getCascaderOptionsFromFields } from '@editor/utils';
62
65
 
63
66
  defineOptions({
64
67
  name: 'MFieldsEventSelect',
@@ -77,26 +80,45 @@ const codeBlockService = services?.codeBlockService;
77
80
 
78
81
  // 事件名称下拉框表单配置
79
82
  const eventNameConfig = computed(() => {
83
+ const fieldType = props.config.src === 'component' ? 'select' : 'cascader';
80
84
  const defaultEventNameConfig = {
81
85
  name: 'name',
82
86
  text: '事件',
83
- type: 'select',
87
+ type: fieldType,
84
88
  labelWidth: '40px',
89
+ checkStrictly: true,
90
+ valueSeparator: '.',
85
91
  options: (mForm: FormState, { formValue }: any) => {
86
- let events: EventOption[] = [];
92
+ let events: EventOption[] | CascaderOption[] = [];
87
93
 
88
94
  if (!eventsService || !dataSourceService) return events;
89
95
 
90
96
  if (props.config.src === 'component') {
91
97
  events = eventsService.getEvent(formValue.type);
92
- } else if (props.config.src === 'datasource') {
93
- events = dataSourceService.getFormEvent(formValue.type);
98
+ return events.map((option) => ({
99
+ text: option.label,
100
+ value: option.value,
101
+ }));
94
102
  }
103
+ if (props.config.src === 'datasource') {
104
+ // 从数据源类型中获取到相关事件
105
+ events = dataSourceService.getFormEvent(formValue.type);
106
+ // 从数据源类型和实例中分别获取数据以追加数据变化的事件
107
+ const dataSource = dataSourceService.getDataSourceById(formValue.id);
108
+ const fields = dataSource?.fields || [];
109
+ if (fields.length > 0) {
110
+ return [
111
+ ...events,
112
+ {
113
+ label: '数据变化',
114
+ value: DATA_SOURCE_FIELDS_CHANGE_EVENT_PREFIX,
115
+ children: getCascaderOptionsFromFields(fields),
116
+ },
117
+ ];
118
+ }
95
119
 
96
- return events.map((option) => ({
97
- text: option.label,
98
- value: option.value,
99
- }));
120
+ return events;
121
+ }
100
122
  },
101
123
  };
102
124
  return { ...defaultEventNameConfig, ...props.config.eventNameConfig };
@@ -227,7 +249,8 @@ const tableConfig = computed(() => ({
227
249
  }));
228
250
 
229
251
  // 组件动作组表单配置
230
- const actionsConfig = computed(() => ({
252
+ const actionsConfig = computed<PanelConfig>(() => ({
253
+ type: 'panel',
231
254
  items: [
232
255
  {
233
256
  type: 'group-list',
@@ -1,4 +1,4 @@
1
- import { computed, inject, ref, watchEffect } from 'vue';
1
+ import { computed, inject, ref, watch } from 'vue';
2
2
 
3
3
  import type { Services } from '@editor/type';
4
4
 
@@ -9,10 +9,16 @@ export const useEditorContentHeight = () => {
9
9
  const editorContentHeight = computed(() => frameworkHeight.value - navMenuHeight.value);
10
10
 
11
11
  const height = ref(0);
12
- watchEffect(() => {
13
- if (height.value > 0 && height.value === editorContentHeight.value) return;
14
- height.value = editorContentHeight.value;
15
- });
12
+ watch(
13
+ editorContentHeight,
14
+ () => {
15
+ if (height.value > 0 && height.value === editorContentHeight.value) return;
16
+ height.value = editorContentHeight.value;
17
+ },
18
+ {
19
+ immediate: true,
20
+ },
21
+ );
16
22
 
17
23
  return {
18
24
  height,
@@ -3,7 +3,7 @@
3
3
  <slot name="props-panel-header"></slot>
4
4
  <MForm
5
5
  ref="configForm"
6
- :class="`m-editor-props-panel ${propsPanelSize}`"
6
+ :class="propsPanelSize"
7
7
  :popper-class="`m-editor-props-panel-popper ${propsPanelSize}`"
8
8
  :size="propsPanelSize"
9
9
  :init-values="values"
@@ -14,6 +14,7 @@
14
14
  ></MForm>
15
15
 
16
16
  <TMagicButton
17
+ v-if="!disabledShowSrc"
17
18
  class="m-editor-props-panel-src-icon"
18
19
  circle
19
20
  size="large"
@@ -57,6 +58,7 @@ defineOptions({
57
58
  });
58
59
 
59
60
  defineProps<{
61
+ disabledShowSrc?: boolean;
60
62
  extendState?: (state: FormState) => Record<string, any> | Promise<Record<string, any>>;
61
63
  }>();
62
64
 
@@ -8,7 +8,8 @@
8
8
  draggable="true"
9
9
  :key="config.$key ?? index"
10
10
  :class="{ 'is-active': activeTabName === config.text }"
11
- @click="activeTabName = config.text || `${index}`"
11
+ :style="config.tabStyle || {}"
12
+ @click="activeTabName = config.text || config.$key || `${index}`"
12
13
  @dragstart="dragstartHandler"
13
14
  @dragend="dragendHandler(config.$key, $event)"
14
15
  >
@@ -20,7 +21,7 @@
20
21
  class="m-editor-sidebar-content"
21
22
  v-for="(config, index) in sideBarItems"
22
23
  :key="config.$key ?? index"
23
- v-show="activeTabName === config.text"
24
+ v-show="[config.text, config.$key, `${index}`].includes(activeTabName)"
24
25
  >
25
26
  <component
26
27
  v-if="config && !floatBoxStates[config.$key]?.status"
@@ -151,6 +152,7 @@ import {
151
152
  type SidebarSlots,
152
153
  type SideComponent,
153
154
  type SideItem,
155
+ SideItemKey,
154
156
  } from '@editor/type';
155
157
 
156
158
  import CodeBlockListPanel from './code-block/CodeBlockListPanel.vue';
@@ -171,7 +173,11 @@ const props = withDefaults(
171
173
  customContentMenu?: (menus: (MenuButton | MenuComponent)[], type: string) => (MenuButton | MenuComponent)[];
172
174
  }>(),
173
175
  {
174
- data: () => ({ type: 'tabs', status: '组件', items: ['component-list', 'layer', 'code-block', 'data-source'] }),
176
+ data: () => ({
177
+ type: 'tabs',
178
+ status: '组件',
179
+ items: [SideItemKey.COMPONENT_LIST, SideItemKey.LAYER, SideItemKey.CODE_BLOCK, SideItemKey.DATA_SOURCE],
180
+ }),
175
181
  },
176
182
  );
177
183
 
@@ -184,8 +190,8 @@ const activeTabName = ref(props.data?.status);
184
190
 
185
191
  const getItemConfig = (data: SideItem): SideComponent => {
186
192
  const map: Record<string, SideComponent> = {
187
- 'component-list': {
188
- $key: 'component-list',
193
+ [SideItemKey.COMPONENT_LIST]: {
194
+ $key: SideItemKey.COMPONENT_LIST,
189
195
  type: 'component',
190
196
  icon: Goods,
191
197
  text: '组件',
@@ -204,7 +210,7 @@ const getItemConfig = (data: SideItem): SideComponent => {
204
210
  component: LayerPanel,
205
211
  slots: {},
206
212
  },
207
- 'code-block': {
213
+ [SideItemKey.CODE_BLOCK]: {
208
214
  $key: 'code-block',
209
215
  type: 'component',
210
216
  icon: EditPen,
@@ -212,8 +218,8 @@ const getItemConfig = (data: SideItem): SideComponent => {
212
218
  component: CodeBlockListPanel,
213
219
  slots: {},
214
220
  },
215
- 'data-source': {
216
- $key: 'data-source',
221
+ [SideItemKey.DATA_SOURCE]: {
222
+ $key: SideItemKey.DATA_SOURCE,
217
223
  type: 'component',
218
224
  icon: Coin,
219
225
  text: '数据源',
@@ -227,6 +233,16 @@ const getItemConfig = (data: SideItem): SideComponent => {
227
233
 
228
234
  const sideBarItems = computed(() => props.data.items.map((item) => getItemConfig(item)));
229
235
 
236
+ watch(
237
+ sideBarItems,
238
+ (items) => {
239
+ services?.uiService.set('sideBarItems', items);
240
+ },
241
+ {
242
+ immediate: true,
243
+ },
244
+ );
245
+
230
246
  watch(
231
247
  () => props.data.status,
232
248
  (status) => {
@@ -36,7 +36,7 @@ import type { Id } from '@tmagic/schema';
36
36
  import CodeBlockEditor from '@editor/components/CodeBlockEditor.vue';
37
37
  import SearchInput from '@editor/components/SearchInput.vue';
38
38
  import { useCodeBlockEdit } from '@editor/hooks/use-code-block-edit';
39
- import type { CodeBlockListPanelSlots, CodeDeleteErrorType, Services } from '@editor/type';
39
+ import type { CodeBlockListPanelSlots, CodeDeleteErrorType, EventBus, Services } from '@editor/type';
40
40
 
41
41
  import CodeBlockList from './CodeBlockList.vue';
42
42
 
@@ -50,6 +50,7 @@ defineProps<{
50
50
  customError?: (id: Id, errorType: CodeDeleteErrorType) => any;
51
51
  }>();
52
52
 
53
+ const eventBus = inject<EventBus>('eventBus');
53
54
  const { codeBlockService } = inject<Services>('services') || {};
54
55
 
55
56
  const editable = computed(() => codeBlockService?.getEditStatus());
@@ -62,4 +63,8 @@ const codeBlockList = ref<InstanceType<typeof CodeBlockList>>();
62
63
  const filterTextChangeHandler = (val: string) => {
63
64
  codeBlockList.value?.filter(val);
64
65
  };
66
+
67
+ eventBus?.on('edit-code', (id: string) => {
68
+ editCode(id);
69
+ });
65
70
  </script>
@@ -46,7 +46,7 @@ import { TMagicButton, TMagicPopover, TMagicScrollbar } from '@tmagic/design';
46
46
  import SearchInput from '@editor/components/SearchInput.vue';
47
47
  import ToolButton from '@editor/components/ToolButton.vue';
48
48
  import { useDataSourceEdit } from '@editor/hooks/use-data-source-edit';
49
- import type { DataSourceListSlots, Services } from '@editor/type';
49
+ import type { DataSourceListSlots, EventBus, Services } from '@editor/type';
50
50
 
51
51
  import DataSourceConfigPanel from './DataSourceConfigPanel.vue';
52
52
  import DataSourceList from './DataSourceList.vue';
@@ -57,6 +57,7 @@ defineOptions({
57
57
  name: 'MEditorDataSourceListPanel',
58
58
  });
59
59
 
60
+ const eventBus = inject<EventBus>('eventBus');
60
61
  const { dataSourceService } = inject<Services>('services') || {};
61
62
 
62
63
  const { editDialog, dataSourceValues, dialogTitle, editable, editHandler, submitDataSourceHandler } =
@@ -98,4 +99,8 @@ const dataSourceList = ref<InstanceType<typeof DataSourceList>>();
98
99
  const filterTextChangeHandler = (val: string) => {
99
100
  dataSourceList.value?.filter(val);
100
101
  };
102
+
103
+ eventBus?.on('edit-data-source', (id: string) => {
104
+ editHandler(id);
105
+ });
101
106
  </script>
@@ -45,7 +45,8 @@ import { computed, inject, markRaw, nextTick, onBeforeUnmount, onMounted, ref, t
45
45
  import { cloneDeep } from 'lodash-es';
46
46
 
47
47
  import type { MApp, MContainer } from '@tmagic/schema';
48
- import StageCore, { calcValueByFontsize, getOffset, Runtime } from '@tmagic/stage';
48
+ import StageCore, { getOffset, Runtime } from '@tmagic/stage';
49
+ import { calcValueByFontsize } from '@tmagic/utils';
49
50
 
50
51
  import ScrollViewer from '@editor/components/ScrollViewer.vue';
51
52
  import { useStage } from '@editor/hooks/use-stage';
@@ -223,18 +224,18 @@ const dropHandler = async (e: DragEvent) => {
223
224
  top = e.clientY - containerRect.top + scrollTop;
224
225
  left = e.clientX - containerRect.left + scrollLeft;
225
226
 
226
- if (parentEl && doc) {
227
+ if (parentEl) {
227
228
  const { left: parentLeft, top: parentTop } = getOffset(parentEl);
228
- left = left - calcValueByFontsize(doc, parentLeft) * zoom.value;
229
- top = top - calcValueByFontsize(doc, parentTop) * zoom.value;
229
+ left = left - parentLeft * zoom.value;
230
+ top = top - parentTop * zoom.value;
230
231
  }
231
232
  }
232
233
 
233
234
  config.data.style = {
234
235
  ...style,
235
236
  position,
236
- top: top / zoom.value,
237
- left: left / zoom.value,
237
+ top: calcValueByFontsize(doc, top / zoom.value),
238
+ left: calcValueByFontsize(doc, left / zoom.value),
238
239
  };
239
240
 
240
241
  config.data.inputEvent = e;
@@ -23,7 +23,7 @@ import { Writable } from 'type-fest';
23
23
  import { DepTargetType } from '@tmagic/dep';
24
24
  import type { Id, MApp, MComponent, MContainer, MNode, MPage, MPageFragment } from '@tmagic/schema';
25
25
  import { NodeType } from '@tmagic/schema';
26
- import { getNodePath, isNumber, isPage, isPageFragment, isPop } from '@tmagic/utils';
26
+ import { calcValueByFontsize, getNodePath, isNumber, isPage, isPageFragment, isPop } from '@tmagic/utils';
27
27
 
28
28
  import BaseService from '@editor/services//BaseService';
29
29
  import propsService from '@editor/services//props';
@@ -741,7 +741,7 @@ class Editor extends BaseService {
741
741
  const el = doc.getElementById(`${node.id}`);
742
742
  const parentEl = layout === Layout.FIXED ? doc.body : el?.offsetParent;
743
743
  if (parentEl && el) {
744
- node.style.left = (parentEl.clientWidth - el.clientWidth) / 2;
744
+ node.style.left = calcValueByFontsize(doc, (parentEl.clientWidth - el.clientWidth) / 2);
745
745
  node.style.right = '';
746
746
  }
747
747
  } else if (parent.style && isNumber(parent.style?.width) && isNumber(node.style?.width)) {
@@ -48,6 +48,7 @@ const state = reactive<UiState>({
48
48
  propsPanelSize: 'small',
49
49
  showAddPageButton: true,
50
50
  hideSlideBar: false,
51
+ sideBarItems: [],
51
52
  navMenuRect: {
52
53
  left: 0,
53
54
  top: 0,
@@ -0,0 +1,12 @@
1
+ .m-fields-data-source-select,
2
+ .m-fields-data-source-field-select,
3
+ .m-fields-data-source-method-select .data-source-method-select-container,
4
+ .m-fields-code-select-col .code-select-container {
5
+ width: 100%;
6
+ display: flex;
7
+ align-items: center;
8
+
9
+ .m-fields-select-action-button {
10
+ margin-left: 5px;
11
+ }
12
+ }
@@ -1,5 +1,5 @@
1
1
  .m-editor-props-panel {
2
- padding: 0 10px;
2
+ padding: 0 10px 50px 10px;
3
3
 
4
4
  .m-editor-props-panel-src-icon {
5
5
  position: absolute;
@@ -24,3 +24,4 @@
24
24
  @import "./tree.scss";
25
25
  @import "./floating-box.scss";
26
26
  @import "./page-fragment-select.scss";
27
+ @import "./data-source-field.scss";
package/src/type.ts CHANGED
@@ -17,6 +17,7 @@
17
17
  */
18
18
 
19
19
  import type { Component } from 'vue';
20
+ import type EventEmitter from 'events';
20
21
  import type { PascalCasedProperties } from 'type-fest';
21
22
 
22
23
  import type { ChildConfig, ColumnConfig, FilterFunction, FormConfig, FormItem, Input } from '@tmagic/form';
@@ -238,6 +239,8 @@ export interface UiState {
238
239
  showAddPageButton: boolean;
239
240
  /** 是否隐藏侧边栏 */
240
241
  hideSlideBar: boolean;
242
+ /** 侧边栏面板配置 */
243
+ sideBarItems: SideComponent[];
241
244
 
242
245
  // navMenu 的宽高
243
246
  navMenuRect: {
@@ -370,8 +373,10 @@ export interface MenuBarData {
370
373
  export interface SideComponent extends MenuComponent {
371
374
  /** 显示文案 */
372
375
  text: string;
376
+ /** tab样式 */
377
+ tabStyle?: string | Record<string, any>;
373
378
  /** vue组件或url */
374
- icon: Component<{}, {}, any>;
379
+ icon?: any;
375
380
  /** slide 唯一标识 key */
376
381
  $key: string;
377
382
 
@@ -384,12 +389,19 @@ export interface SideComponent extends MenuComponent {
384
389
  };
385
390
  }
386
391
 
392
+ export enum SideItemKey {
393
+ COMPONENT_LIST = 'component-list',
394
+ LAYER = 'layer',
395
+ CODE_BLOCK = 'code-block',
396
+ DATA_SOURCE = 'data-source',
397
+ }
398
+
387
399
  /**
388
400
  * component-list: 组件列表
389
401
  * layer: 已选组件树
390
402
  * code-block: 代码块
391
403
  */
392
- export type SideItem = 'component-list' | 'layer' | 'code-block' | 'data-source' | SideComponent;
404
+ export type SideItem = `${SideItemKey}` | SideComponent;
393
405
 
394
406
  /** 工具栏 */
395
407
  export interface SideBarData {
@@ -621,6 +633,8 @@ export interface DataSourceSelect extends FormItem, Input {
621
633
  * value: 要编译(数据源data)
622
634
  * */
623
635
  value?: 'id' | 'value';
636
+ /** 是否可以编辑数据源,disable表示的是是否可以选择数据源 */
637
+ notEditable?: boolean | FilterFunction;
624
638
  }
625
639
 
626
640
  export interface DataSourceMethodSelectConfig extends FormItem {
@@ -640,6 +654,8 @@ export interface DataSourceFieldSelectConfig extends FormItem {
640
654
  checkStrictly?: boolean;
641
655
  dataSourceFieldType?: DataSourceFieldType[];
642
656
  fieldConfig?: ChildConfig;
657
+ /** 是否可以编辑数据源,disable表示的是是否可以选择数据源 */
658
+ notEditable?: boolean | FilterFunction;
643
659
  }
644
660
 
645
661
  /** 可新增的数据源类型选项 */
@@ -714,3 +730,16 @@ export type SyncHookPlugin<
714
730
  C extends Record<T[number], (...args: any) => any>,
715
731
  > = AddPrefixToObject<PascalCasedProperties<SyncBeforeHook<T, C>>, 'before'> &
716
732
  AddPrefixToObject<PascalCasedProperties<SyncAfterHook<T, C>>, 'after'>;
733
+
734
+ export interface EventBusEvent {
735
+ 'edit-data-source': [id: string];
736
+ 'edit-code': [id: string];
737
+ }
738
+
739
+ export interface EventBus extends EventEmitter {
740
+ on<Name extends keyof EventBusEvent, Param extends EventBusEvent[Name]>(
741
+ eventName: Name,
742
+ listener: (...args: Param) => void,
743
+ ): this;
744
+ emit<Name extends keyof EventBusEvent, Param extends EventBusEvent[Name]>(eventName: Name, ...args: Param): boolean;
745
+ }
@@ -2,7 +2,7 @@ import { computed, markRaw, Ref } from 'vue';
2
2
  import { CopyDocument, Delete, DocumentCopy } from '@element-plus/icons-vue';
3
3
 
4
4
  import { Id, MContainer, NodeType } from '@tmagic/schema';
5
- import { isPage, isPageFragment } from '@tmagic/utils';
5
+ import { calcValueByFontsize, isPage, isPageFragment } from '@tmagic/utils';
6
6
 
7
7
  import ContentMenu from '@editor/components/ContentMenu.vue';
8
8
  import type { MenuButton, Services } from '@editor/type';
@@ -46,8 +46,12 @@ export const usePasteMenu = (menu?: Ref<InstanceType<typeof ContentMenu> | undef
46
46
  const stage = services?.editorService?.get('stage');
47
47
  const rect = menu.value.$el.getBoundingClientRect();
48
48
  const parentRect = stage?.container?.getBoundingClientRect();
49
- const initialLeft = (rect.left || 0) - (parentRect?.left || 0);
50
- const initialTop = (rect.top || 0) - (parentRect?.top || 0);
49
+ const initialLeft =
50
+ calcValueByFontsize(stage?.renderer.getDocument(), (rect.left || 0) - (parentRect?.left || 0)) /
51
+ services.uiService.get('zoom');
52
+ const initialTop =
53
+ calcValueByFontsize(stage?.renderer.getDocument(), (rect.top || 0) - (parentRect?.top || 0)) /
54
+ services.uiService.get('zoom');
51
55
  services?.editorService?.paste({ left: initialLeft, top: initialTop });
52
56
  } else {
53
57
  services?.editorService?.paste();
@@ -1,5 +1,5 @@
1
- import { FormConfig, FormState } from '@tmagic/form';
2
- import { DataSchema, DataSourceSchema } from '@tmagic/schema';
1
+ import { CascaderOption, FormConfig, FormState } from '@tmagic/form';
2
+ import { DataSchema, DataSourceFieldType, DataSourceSchema } from '@tmagic/schema';
3
3
 
4
4
  import BaseFormConfig from './formConfigs/base';
5
5
  import HttpFormConfig from './formConfigs/http';
@@ -32,7 +32,6 @@ const fillConfig = (config: FormConfig): FormConfig => [
32
32
  },
33
33
  {
34
34
  title: '事件配置',
35
- display: false,
36
35
  items: [
37
36
  {
38
37
  name: 'events',
@@ -198,3 +197,40 @@ export const getDisplayField = (dataSources: DataSourceSchema[], key: string) =>
198
197
 
199
198
  return displayState;
200
199
  };
200
+
201
+ export const getCascaderOptionsFromFields = (
202
+ fields: DataSchema[] = [],
203
+ dataSourceFieldType: DataSourceFieldType[] = ['any'],
204
+ ): CascaderOption[] => {
205
+ const child: CascaderOption[] = [];
206
+ fields.forEach((field) => {
207
+ if (!dataSourceFieldType.length) {
208
+ dataSourceFieldType.push('any');
209
+ }
210
+
211
+ const children = getCascaderOptionsFromFields(field.fields, dataSourceFieldType);
212
+
213
+ const item = {
214
+ label: field.title || field.name,
215
+ value: field.name,
216
+ children,
217
+ };
218
+
219
+ const fieldType = field.type || 'any';
220
+ if (dataSourceFieldType.includes('any') || dataSourceFieldType.includes(fieldType)) {
221
+ child.push(item);
222
+ return;
223
+ }
224
+
225
+ if (!dataSourceFieldType.includes(fieldType) && !['array', 'object', 'any'].includes(fieldType)) {
226
+ return;
227
+ }
228
+
229
+ if (!children.length && ['object', 'array', 'any'].includes(field.type || '')) {
230
+ return;
231
+ }
232
+
233
+ child.push(item);
234
+ });
235
+ return child;
236
+ };
@@ -21,7 +21,7 @@ import serialize from 'serialize-javascript';
21
21
  import type { Id, MApp, MContainer, MNode, MPage, MPageFragment } from '@tmagic/schema';
22
22
  import { NodeType } from '@tmagic/schema';
23
23
  import type StageCore from '@tmagic/stage';
24
- import { getNodePath, isNumber, isPage, isPageFragment, isPop } from '@tmagic/utils';
24
+ import { calcValueByFontsize, getNodePath, isNumber, isPage, isPageFragment, isPop } from '@tmagic/utils';
25
25
 
26
26
  import { Layout } from '@editor/type';
27
27
  export const COPY_STORAGE_KEY = '$MagicEditorCopyData';
@@ -106,13 +106,16 @@ const getMiddleTop = (node: MNode, parentNode: MNode, stage: StageCore | null) =
106
106
  }
107
107
 
108
108
  const { height: parentHeight } = parentNode.style;
109
-
109
+ // wrapperHeight 是未 calcValue的高度, 所以要将其calcValueByFontsize一下, 否则在pad or pc端计算的结果有误
110
+ const { scrollTop = 0, wrapperHeight } = stage.mask;
111
+ const wrapperHeightDeal = calcValueByFontsize(stage.renderer.getDocument()!, wrapperHeight);
112
+ const scrollTopDeal = calcValueByFontsize(stage.renderer.getDocument()!, scrollTop);
110
113
  if (isPage(parentNode)) {
111
- const { scrollTop = 0, wrapperHeight } = stage.mask;
112
- return (wrapperHeight - height) / 2 + scrollTop;
114
+ return (wrapperHeightDeal - height) / 2 + scrollTopDeal;
113
115
  }
114
116
 
115
- return (parentHeight - height) / 2;
117
+ // 如果容器的元素高度大于当前视口高度的2倍, 添加的元素居中位置也会看不见, 所以要取最小值计算
118
+ return (Math.min(parentHeight, wrapperHeightDeal) - height) / 2;
116
119
  };
117
120
 
118
121
  export const getInitPositionStyle = (style: Record<string, any> = {}, layout: Layout) => {
@@ -238,8 +241,12 @@ export const fixNodeLeft = (config: MNode, parent: MContainer, doc?: Document) =
238
241
  const parentEl = doc.getElementById(`${parent.id}`);
239
242
 
240
243
  const left = Number(config.style?.left) || 0;
241
- if (el && parentEl && el.offsetWidth + left > parentEl.offsetWidth) {
242
- return parentEl.offsetWidth - el.offsetWidth;
244
+ if (el && parentEl) {
245
+ const calcParentOffsetWidth = calcValueByFontsize(doc, parentEl.offsetWidth);
246
+ const calcElOffsetWidth = calcValueByFontsize(doc, el.offsetWidth);
247
+ if (calcElOffsetWidth + left > calcParentOffsetWidth) {
248
+ return calcParentOffsetWidth - calcElOffsetWidth;
249
+ }
243
250
  }
244
251
 
245
252
  return config.style.left;
@@ -1,46 +1,33 @@
1
1
  import type { CodeBlockContent } from '@tmagic/schema';
2
- declare const _default: import("vue").DefineComponent<{
3
- width: import("vue").PropType<number>;
4
- visible: import("vue").PropType<boolean>;
5
- content: {
6
- type: import("vue").PropType<CodeBlockContent>;
7
- required: true;
8
- };
9
- disabled: {
10
- type: import("vue").PropType<boolean>;
11
- };
12
- isDataSource: {
13
- type: import("vue").PropType<boolean>;
14
- };
15
- dataSourceType: {
16
- type: import("vue").PropType<string>;
17
- };
18
- }, {
2
+ declare let __VLS_typeProps: {
3
+ content: CodeBlockContent;
4
+ disabled?: boolean;
5
+ isDataSource?: boolean;
6
+ dataSourceType?: string;
7
+ };
8
+ type __VLS_PublicProps = {
9
+ 'width'?: number;
10
+ 'visible'?: boolean;
11
+ } & typeof __VLS_typeProps;
12
+ declare const _default: import("vue").DefineComponent<__VLS_TypePropsToOption<__VLS_PublicProps>, {
19
13
  show(): Promise<void>;
20
14
  hide(): Promise<void>;
21
15
  }, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
22
16
  "update:width": (width: number) => void;
23
17
  "update:visible": (visible: boolean) => void;
24
18
  submit: (values: CodeBlockContent) => void;
25
- }, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
26
- width: import("vue").PropType<number>;
27
- visible: import("vue").PropType<boolean>;
28
- content: {
29
- type: import("vue").PropType<CodeBlockContent>;
30
- required: true;
31
- };
32
- disabled: {
33
- type: import("vue").PropType<boolean>;
34
- };
35
- isDataSource: {
36
- type: import("vue").PropType<boolean>;
37
- };
38
- dataSourceType: {
39
- type: import("vue").PropType<string>;
40
- };
41
- }>> & {
19
+ }, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<__VLS_TypePropsToOption<__VLS_PublicProps>>> & {
42
20
  onSubmit?: ((values: CodeBlockContent) => any) | undefined;
43
21
  "onUpdate:width"?: ((width: number) => any) | undefined;
44
22
  "onUpdate:visible"?: ((visible: boolean) => any) | undefined;
45
23
  }, {}, {}>;
46
24
  export default _default;
25
+ type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
26
+ type __VLS_TypePropsToOption<T> = {
27
+ [K in keyof T]-?: {} extends Pick<T, K> ? {
28
+ type: import('vue').PropType<__VLS_NonUndefinedable<T[K]>>;
29
+ } : {
30
+ type: import('vue').PropType<T[K]>;
31
+ required: true;
32
+ };
33
+ };