@tmagic/editor 1.5.0-beta.9 → 1.5.1

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 (99) hide show
  1. package/dist/{style.css → tmagic-editor.css} +228 -22
  2. package/dist/tmagic-editor.js +1670 -1012
  3. package/dist/tmagic-editor.umd.cjs +1705 -1048
  4. package/package.json +14 -12
  5. package/src/Editor.vue +24 -6
  6. package/src/components/CodeBlockEditor.vue +14 -8
  7. package/src/components/CodeParams.vue +5 -5
  8. package/src/components/ContentMenu.vue +18 -18
  9. package/src/components/FloatingBox.vue +3 -3
  10. package/src/components/Resizer.vue +4 -4
  11. package/src/components/ScrollBar.vue +3 -3
  12. package/src/components/ScrollViewer.vue +3 -3
  13. package/src/components/SplitView.vue +2 -2
  14. package/src/components/ToolButton.vue +2 -1
  15. package/src/editorProps.ts +6 -2
  16. package/src/fields/Code.vue +1 -2
  17. package/src/fields/CodeSelect.vue +13 -11
  18. package/src/fields/CodeSelectCol.vue +32 -5
  19. package/src/fields/CondOpSelect.vue +5 -2
  20. package/src/fields/DataSourceFields.vue +31 -12
  21. package/src/fields/DataSourceInput.vue +2 -2
  22. package/src/fields/DataSourceMethods.vue +72 -14
  23. package/src/fields/DataSourceMocks.vue +0 -1
  24. package/src/fields/DisplayConds.vue +8 -3
  25. package/src/fields/EventSelect.vue +28 -12
  26. package/src/fields/KeyValue.vue +17 -12
  27. package/src/fields/UISelect.vue +6 -3
  28. package/src/hooks/index.ts +0 -1
  29. package/src/hooks/use-code-block-edit.ts +3 -3
  30. package/src/hooks/use-data-source-edit.ts +3 -2
  31. package/src/hooks/use-filter.ts +1 -1
  32. package/src/hooks/use-getso.ts +7 -7
  33. package/src/hooks/use-node-status.ts +2 -2
  34. package/src/index.ts +2 -1
  35. package/src/initService.ts +177 -74
  36. package/src/layouts/CodeEditor.vue +2 -2
  37. package/src/layouts/Framework.vue +13 -12
  38. package/src/layouts/NavMenu.vue +2 -2
  39. package/src/layouts/page-bar/AddButton.vue +29 -9
  40. package/src/layouts/page-bar/PageBar.vue +79 -66
  41. package/src/layouts/page-bar/PageBarScrollContainer.vue +84 -98
  42. package/src/layouts/page-bar/PageList.vue +5 -3
  43. package/src/layouts/page-bar/Search.vue +67 -0
  44. package/src/layouts/props-panel/FormPanel.vue +123 -0
  45. package/src/layouts/props-panel/PropsPanel.vue +146 -0
  46. package/src/layouts/props-panel/use-style-panel.ts +29 -0
  47. package/src/layouts/sidebar/Sidebar.vue +7 -1
  48. package/src/layouts/sidebar/code-block/CodeBlockList.vue +18 -2
  49. package/src/layouts/sidebar/code-block/CodeBlockListPanel.vue +35 -4
  50. package/src/layouts/sidebar/code-block/useContentMenu.ts +83 -0
  51. package/src/layouts/sidebar/data-source/DataSourceConfigPanel.vue +7 -5
  52. package/src/layouts/sidebar/data-source/DataSourceList.vue +13 -8
  53. package/src/layouts/sidebar/data-source/DataSourceListPanel.vue +40 -4
  54. package/src/layouts/sidebar/data-source/useContentMenu.ts +81 -0
  55. package/src/layouts/sidebar/layer/LayerMenu.vue +7 -13
  56. package/src/layouts/sidebar/layer/LayerPanel.vue +11 -4
  57. package/src/layouts/sidebar/layer/use-click.ts +2 -2
  58. package/src/layouts/sidebar/layer/use-keybinding.ts +2 -2
  59. package/src/layouts/sidebar/layer/use-node-status.ts +2 -3
  60. package/src/layouts/workspace/Workspace.vue +13 -3
  61. package/src/layouts/workspace/viewer/NodeListMenu.vue +3 -3
  62. package/src/layouts/workspace/viewer/Stage.vue +41 -11
  63. package/src/layouts/workspace/viewer/StageOverlay.vue +2 -2
  64. package/src/layouts/workspace/viewer/ViewerMenu.vue +4 -6
  65. package/src/services/dataSource.ts +12 -5
  66. package/src/services/dep.ts +61 -13
  67. package/src/services/editor.ts +46 -51
  68. package/src/services/storage.ts +2 -1
  69. package/src/services/ui.ts +1 -0
  70. package/src/theme/common/var.scss +12 -10
  71. package/src/theme/component-list-panel.scss +9 -7
  72. package/src/theme/content-menu.scss +7 -5
  73. package/src/theme/data-source.scss +3 -1
  74. package/src/theme/floating-box.scss +4 -2
  75. package/src/theme/framework.scss +7 -5
  76. package/src/theme/index.scss +4 -5
  77. package/src/theme/key-value.scss +2 -2
  78. package/src/theme/layer-panel.scss +3 -1
  79. package/src/theme/layout.scss +1 -1
  80. package/src/theme/nav-menu.scss +7 -5
  81. package/src/theme/page-bar.scss +51 -27
  82. package/src/theme/props-panel.scss +81 -1
  83. package/src/theme/resizer.scss +1 -1
  84. package/src/theme/search-input.scss +1 -0
  85. package/src/theme/sidebar.scss +4 -2
  86. package/src/theme/stage.scss +3 -1
  87. package/src/theme/theme.scss +28 -28
  88. package/src/theme/tree.scss +14 -12
  89. package/src/type.ts +10 -1
  90. package/src/utils/content-menu.ts +2 -2
  91. package/src/utils/data-source/formConfigs/http.ts +2 -0
  92. package/src/utils/data-source/index.ts +2 -2
  93. package/src/utils/editor.ts +78 -22
  94. package/src/utils/idle-task.ts +36 -4
  95. package/src/utils/props.ts +48 -6
  96. package/types/index.d.ts +2312 -2080
  97. package/src/hooks/use-data-source-method.ts +0 -100
  98. package/src/layouts/PropsPanel.vue +0 -131
  99. package/src/layouts/page-bar/SwitchTypeButton.vue +0 -45
@@ -1,10 +1,14 @@
1
1
  <template>
2
2
  <div class="m-editor-page-bar-tabs">
3
- <SwitchTypeButton v-if="!disabledPageFragment" v-model="active" />
4
-
5
- <PageBarScrollContainer :type="active" :page-bar-sort-options="pageBarSortOptions">
3
+ <PageBarScrollContainer
4
+ ref="pageBarScrollContainer"
5
+ :page-bar-sort-options="pageBarSortOptions"
6
+ :length="list.length"
7
+ >
6
8
  <template #prepend>
7
- <AddButton :type="active"></AddButton>
9
+ <slot name="page-bar-add-button"><AddButton></AddButton></slot>
10
+
11
+ <Search v-model:query="query"></Search>
8
12
  <PageList :list="list">
9
13
  <template #page-list-popover="{ list }"><slot name="page-list-popover" :list="list"></slot></template>
10
14
  </PageList>
@@ -13,8 +17,9 @@
13
17
  <div
14
18
  v-for="item in list"
15
19
  class="m-editor-page-bar-item"
20
+ ref="pageBarItems"
16
21
  :key="item.id"
17
- :page-id="item.id"
22
+ :data-page-id="item.id"
18
23
  :class="{ active: page?.id === item.id }"
19
24
  @click="switchPage(item.id)"
20
25
  >
@@ -63,94 +68,64 @@
63
68
  </template>
64
69
 
65
70
  <script lang="ts" setup>
66
- import { computed, inject, ref, watch } from 'vue';
71
+ import { computed, inject, ref, useTemplateRef, watch } from 'vue';
67
72
  import { CaretBottom, Delete, DocumentCopy } from '@element-plus/icons-vue';
68
73
 
69
74
  import { type Id, type MPage, type MPageFragment, NodeType } from '@tmagic/core';
70
75
  import { TMagicIcon, TMagicPopover } from '@tmagic/design';
71
- import { isPage, isPageFragment } from '@tmagic/utils';
72
76
 
73
77
  import ToolButton from '@editor/components/ToolButton.vue';
74
78
  import type { PageBarSortOptions, Services } from '@editor/type';
75
- import { getPageFragmentList, getPageList } from '@editor/utils';
76
79
 
77
80
  import AddButton from './AddButton.vue';
78
81
  import PageBarScrollContainer from './PageBarScrollContainer.vue';
79
82
  import PageList from './PageList.vue';
80
- import SwitchTypeButton from './SwitchTypeButton.vue';
83
+ import Search from './Search.vue';
81
84
 
82
85
  defineOptions({
83
86
  name: 'MEditorPageBar',
84
87
  });
85
88
 
86
- defineProps<{
87
- disabledPageFragment: boolean;
88
- pageBarSortOptions?: PageBarSortOptions;
89
- }>();
90
-
91
- const active = ref<NodeType.PAGE | NodeType.PAGE_FRAGMENT>(NodeType.PAGE);
89
+ const props = withDefaults(
90
+ defineProps<{
91
+ disabledPageFragment: boolean;
92
+ pageBarSortOptions?: PageBarSortOptions;
93
+ filterFunction?: (page: MPage | MPageFragment, keyword: string) => boolean;
94
+ }>(),
95
+ {
96
+ filterFunction: (page, keyword) => page.name?.includes(keyword) || `${page.id}`.includes(keyword),
97
+ },
98
+ );
92
99
 
93
100
  const services = inject<Services>('services');
94
101
  const editorService = services?.editorService;
95
102
 
96
103
  const root = computed(() => editorService?.get('root'));
97
104
  const page = computed(() => editorService?.get('page'));
98
- const pageList = computed(() => getPageList(root.value));
99
- const pageFragmentList = computed(() => getPageFragmentList(root.value));
100
105
 
101
- const list = computed(() => (active.value === NodeType.PAGE ? pageList.value : pageFragmentList.value));
102
-
103
- const activePage = ref<Id>('');
104
- const activePageFragment = ref<Id>('');
105
-
106
- watch(
107
- page,
108
- (page) => {
109
- if (!page) {
110
- if (active.value === NodeType.PAGE) {
111
- activePage.value = '';
112
- }
113
- if (active.value === NodeType.PAGE_FRAGMENT) {
114
- activePageFragment.value = '';
115
- }
116
- return;
117
- }
118
-
119
- if (isPage(page)) {
120
- activePage.value = page?.id;
121
- if (active.value !== NodeType.PAGE) {
122
- active.value = NodeType.PAGE;
123
- }
124
- } else if (isPageFragment(page)) {
125
- activePageFragment.value = page?.id;
126
- if (active.value !== NodeType.PAGE_FRAGMENT) {
127
- active.value = NodeType.PAGE_FRAGMENT;
128
- }
129
- }
130
- },
131
- {
132
- immediate: true,
133
- },
134
- );
106
+ const query = ref<{
107
+ pageType: NodeType[];
108
+ keyword: string;
109
+ }>({
110
+ pageType: [NodeType.PAGE, NodeType.PAGE_FRAGMENT],
111
+ keyword: '',
112
+ });
135
113
 
136
- watch(active, (active) => {
137
- if (active === NodeType.PAGE) {
138
- if (!activePage.value && !pageList.value.length) {
139
- editorService?.selectRoot();
140
- return;
141
- }
142
- switchPage(activePage.value);
143
- return;
114
+ const list = computed(() => {
115
+ const { pageType, keyword } = query.value;
116
+ if (pageType.length === 0) {
117
+ return [];
144
118
  }
145
119
 
146
- if (active === NodeType.PAGE_FRAGMENT) {
147
- // 之前没有选中过页面片并且当前没有页面片
148
- if (!activePageFragment.value && !pageFragmentList.value.length) {
149
- editorService?.selectRoot();
150
- return;
120
+ return (root.value?.items || []).filter((item) => {
121
+ if (pageType.includes(item.type)) {
122
+ if (keyword) {
123
+ return props.filterFunction(item, keyword);
124
+ }
125
+ return true;
151
126
  }
152
- switchPage(activePageFragment.value || pageFragmentList.value[0].id);
153
- }
127
+ return false;
128
+ });
154
129
  });
155
130
 
156
131
  const switchPage = (id: Id) => {
@@ -168,4 +143,42 @@ const copy = (node: MPage | MPageFragment) => {
168
143
  const remove = (node: MPage | MPageFragment) => {
169
144
  editorService?.remove(node);
170
145
  };
146
+
147
+ const pageBarScrollContainer = useTemplateRef<InstanceType<typeof PageBarScrollContainer>>('pageBarScrollContainer');
148
+ const pageBarItems = useTemplateRef<HTMLDivElement[]>('pageBarItems');
149
+ watch(page, (page) => {
150
+ if (
151
+ !page ||
152
+ !pageBarScrollContainer.value?.itemsContainerWidth ||
153
+ !pageBarItems.value ||
154
+ pageBarItems.value.length < 2
155
+ ) {
156
+ return;
157
+ }
158
+
159
+ const firstItem = pageBarItems.value[0];
160
+ const lastItem = pageBarItems.value[pageBarItems.value.length - 1];
161
+
162
+ if (page.id === firstItem.dataset.pageId) {
163
+ pageBarScrollContainer.value.scroll('start');
164
+ } else if (page.id === lastItem.dataset.pageId) {
165
+ pageBarScrollContainer.value.scroll('end');
166
+ } else {
167
+ const pageItem = pageBarItems.value.find((item) => item.dataset.pageId === page.id);
168
+ if (!pageItem) {
169
+ return;
170
+ }
171
+
172
+ const pageItemRect = pageItem.getBoundingClientRect();
173
+ const offsetLeft = pageItemRect.left - firstItem.getBoundingClientRect().left;
174
+ const { itemsContainerWidth } = pageBarScrollContainer.value;
175
+
176
+ const left = itemsContainerWidth - offsetLeft - pageItemRect.width;
177
+
178
+ const translateLeft = pageBarScrollContainer.value.getTranslateLeft();
179
+ if (offsetLeft + translateLeft < 0 || offsetLeft + pageItemRect.width > itemsContainerWidth - translateLeft) {
180
+ pageBarScrollContainer.value.scrollTo(left);
181
+ }
182
+ }
183
+ });
171
184
  </script>
@@ -1,42 +1,34 @@
1
1
  <template>
2
2
  <div class="m-editor-page-bar" ref="pageBar">
3
3
  <slot name="prepend"></slot>
4
-
5
- <div v-if="canScroll" class="m-editor-page-bar-item m-editor-page-bar-item-icon" @click="scroll('left')">
6
- <Icon :icon="ArrowLeftBold"></Icon>
4
+ <div v-if="length" class="m-editor-page-bar-items" ref="itemsContainer">
5
+ <slot></slot>
7
6
  </div>
8
7
 
9
8
  <div
10
- v-if="(type === NodeType.PAGE && pageLength) || (type === NodeType.PAGE_FRAGMENT && pageFragmentLength)"
11
- class="m-editor-page-bar-items"
12
- ref="itemsContainer"
13
- :style="`width: ${itemsContainerWidth}px`"
9
+ v-if="canScroll"
10
+ class="m-editor-page-bar-item m-editor-page-bar-item-icon m-editor-page-bar-item-left-icon"
11
+ @click="scroll('left')"
14
12
  >
15
- <slot></slot>
13
+ <Icon :icon="ArrowLeftBold"></Icon>
16
14
  </div>
17
15
 
18
- <div v-if="canScroll" class="m-editor-page-bar-item m-editor-page-bar-item-icon" @click="scroll('right')">
16
+ <div
17
+ v-if="canScroll"
18
+ class="m-editor-page-bar-item m-editor-page-bar-item-icon m-editor-page-bar-item-right-icon"
19
+ @click="scroll('right')"
20
+ >
19
21
  <Icon :icon="ArrowRightBold"></Icon>
20
22
  </div>
21
23
  </div>
22
24
  </template>
23
25
 
24
26
  <script setup lang="ts">
25
- import {
26
- computed,
27
- type ComputedRef,
28
- inject,
29
- nextTick,
30
- onBeforeUnmount,
31
- onMounted,
32
- ref,
33
- watch,
34
- type WatchStopHandle,
35
- } from 'vue';
27
+ import { computed, inject, nextTick, onBeforeUnmount, onMounted, ref, useTemplateRef, watch } from 'vue';
36
28
  import { ArrowLeftBold, ArrowRightBold } from '@element-plus/icons-vue';
37
- import Sortable, { SortableEvent } from 'sortablejs';
29
+ import Sortable, { type SortableEvent } from 'sortablejs';
38
30
 
39
- import { Id, NodeType } from '@tmagic/core';
31
+ import type { Id } from '@tmagic/core';
40
32
 
41
33
  import Icon from '@editor/components/Icon.vue';
42
34
  import type { PageBarSortOptions, Services } from '@editor/type';
@@ -46,15 +38,15 @@ defineOptions({
46
38
  });
47
39
 
48
40
  const props = defineProps<{
49
- type: NodeType.PAGE | NodeType.PAGE_FRAGMENT;
50
41
  pageBarSortOptions?: PageBarSortOptions;
42
+ length: number;
51
43
  }>();
52
44
 
53
45
  const services = inject<Services>('services');
54
46
  const editorService = services?.editorService;
55
47
  const uiService = services?.uiService;
56
48
 
57
- const itemsContainer = ref<HTMLElement>();
49
+ const itemsContainer = useTemplateRef<HTMLElement>('itemsContainer');
58
50
  const canScroll = ref(false);
59
51
 
60
52
  const showAddPageButton = computed(() => uiService?.get('showAddPageButton'));
@@ -63,11 +55,12 @@ const showPageListButton = computed(() => uiService?.get('showPageListButton'));
63
55
  const itemsContainerWidth = ref(0);
64
56
 
65
57
  const setCanScroll = () => {
66
- // 减去新增、左移、右移三个按钮的宽度
58
+ // 减去新增、搜索、页面列表、左移、右移5个按钮的宽度
67
59
  // 37 = icon width 16 + padding 10 * 2 + border-right 1
68
60
  itemsContainerWidth.value =
69
61
  (pageBar.value?.clientWidth || 0) -
70
62
  37 * 2 -
63
+ 37 -
71
64
  (showAddPageButton.value ? 37 : 21) -
72
65
  (showPageListButton.value ? 37 : 0);
73
66
 
@@ -82,7 +75,7 @@ const resizeObserver = new ResizeObserver(() => {
82
75
  setCanScroll();
83
76
  });
84
77
 
85
- const pageBar = ref<HTMLDivElement>();
78
+ const pageBar = useTemplateRef<HTMLDivElement>('pageBar');
86
79
  onMounted(() => {
87
80
  pageBar.value && resizeObserver.observe(pageBar.value);
88
81
  });
@@ -94,99 +87,92 @@ onBeforeUnmount(() => {
94
87
  let translateLeft = 0;
95
88
 
96
89
  const scroll = (type: 'left' | 'right' | 'start' | 'end') => {
97
- if (!itemsContainer.value) return;
90
+ if (!itemsContainer.value || !canScroll.value) return;
98
91
 
99
92
  const maxScrollLeft = itemsContainer.value.scrollWidth - itemsContainerWidth.value;
100
93
 
101
94
  if (type === 'left') {
102
- translateLeft += 100;
103
-
104
- if (translateLeft > 0) {
105
- translateLeft = 0;
106
- }
95
+ scrollTo(translateLeft + 200);
107
96
  } else if (type === 'right') {
108
- translateLeft -= 100;
109
-
110
- if (-translateLeft > maxScrollLeft) {
111
- translateLeft = -maxScrollLeft;
112
- }
97
+ scrollTo(translateLeft - 200);
113
98
  } else if (type === 'start') {
114
- translateLeft = 0;
99
+ scrollTo(0);
115
100
  } else if (type === 'end') {
116
- translateLeft = -maxScrollLeft;
101
+ scrollTo(-maxScrollLeft);
102
+ }
103
+ };
104
+
105
+ const scrollTo = (value: number) => {
106
+ if (!itemsContainer.value || !canScroll.value) return;
107
+ const maxScrollLeft = itemsContainer.value.scrollWidth - itemsContainerWidth.value;
108
+
109
+ if (value >= 0) {
110
+ value = 0;
117
111
  }
118
112
 
113
+ if (-value > maxScrollLeft) {
114
+ value = -maxScrollLeft;
115
+ }
116
+
117
+ translateLeft = value;
118
+
119
119
  itemsContainer.value.style.transform = `translate(${translateLeft}px, 0px)`;
120
120
  };
121
121
 
122
- const pageLength = computed(() => editorService?.get('pageLength') || 0);
123
- const pageFragmentLength = computed(() => editorService?.get('pageFragmentLength') || 0);
124
-
125
- const crateWatchLength = (length: ComputedRef<number>) =>
126
- watch(
127
- length,
128
- (length = 0, preLength = 0) => {
129
- setTimeout(() => {
130
- setCanScroll();
131
- if (length < preLength) {
122
+ watch(
123
+ () => props.length,
124
+ (length = 0, preLength = 0) => {
125
+ setTimeout(() => {
126
+ setCanScroll();
127
+ nextTick(() => {
128
+ if (length < preLength || preLength === 0) {
132
129
  scroll('start');
133
130
  } else {
134
131
  scroll('end');
135
132
  }
136
- if (length > 1) {
137
- const el = document.querySelector('.m-editor-page-bar-items') as HTMLElement;
138
- let beforeDragList: Id[] = [];
139
- const options = {
140
- ...{
141
- dataIdAttr: 'page-id', // 获取排序后的数据
142
- onStart: async (event: SortableEvent) => {
143
- if (typeof props.pageBarSortOptions?.beforeStart === 'function') {
144
- await props.pageBarSortOptions.beforeStart(event, sortable);
145
- }
146
- beforeDragList = sortable.toArray();
147
- },
148
- onUpdate: async (event: SortableEvent) => {
149
- await editorService?.sort(
150
- beforeDragList[event.oldIndex as number],
151
- beforeDragList[event.newIndex as number],
152
- );
153
- if (typeof props.pageBarSortOptions?.afterUpdate === 'function') {
154
- await props.pageBarSortOptions.afterUpdate(event, sortable);
155
- }
156
- },
133
+ });
134
+ if (length > 1) {
135
+ const el = document.querySelector('.m-editor-page-bar-items') as HTMLElement;
136
+ let beforeDragList: Id[] = [];
137
+ const options = {
138
+ ...{
139
+ dataIdAttr: 'page-id', // 获取排序后的数据
140
+ onStart: async (event: SortableEvent) => {
141
+ if (typeof props.pageBarSortOptions?.beforeStart === 'function') {
142
+ await props.pageBarSortOptions.beforeStart(event, sortable);
143
+ }
144
+ beforeDragList = sortable.toArray();
157
145
  },
158
- ...{
159
- ...(props.pageBarSortOptions ? props.pageBarSortOptions : {}),
146
+ onUpdate: async (event: SortableEvent) => {
147
+ await editorService?.sort(
148
+ beforeDragList[event.oldIndex as number],
149
+ beforeDragList[event.newIndex as number],
150
+ );
151
+ if (typeof props.pageBarSortOptions?.afterUpdate === 'function') {
152
+ await props.pageBarSortOptions.afterUpdate(event, sortable);
153
+ }
160
154
  },
161
- };
162
- if (!el) return;
163
- const sortable = new Sortable(el, options);
164
- }
165
- });
166
- },
167
- {
168
- immediate: true,
169
- },
170
- );
171
-
172
- let unWatchPageLength: WatchStopHandle | null;
173
- let unWatchPageFragmentLength: WatchStopHandle | null;
174
-
175
- watch(
176
- () => props.type,
177
- (type) => {
178
- if (type === NodeType.PAGE) {
179
- unWatchPageFragmentLength?.();
180
- unWatchPageFragmentLength = null;
181
- unWatchPageLength = crateWatchLength(pageLength);
182
- } else {
183
- unWatchPageLength?.();
184
- unWatchPageLength = null;
185
- unWatchPageFragmentLength = crateWatchLength(pageFragmentLength);
186
- }
155
+ },
156
+ ...{
157
+ ...(props.pageBarSortOptions ? props.pageBarSortOptions : {}),
158
+ },
159
+ };
160
+ if (!el) return;
161
+ const sortable = new Sortable(el, options);
162
+ }
163
+ });
187
164
  },
188
165
  {
189
166
  immediate: true,
190
167
  },
191
168
  );
169
+
170
+ defineExpose({
171
+ itemsContainerWidth,
172
+ scroll,
173
+ scrollTo,
174
+ getTranslateLeft() {
175
+ return translateLeft;
176
+ },
177
+ });
192
178
  </script>
@@ -18,6 +18,7 @@
18
18
  :data="{
19
19
  type: 'button',
20
20
  text: item.devconfig?.tabName || item.name || item.id,
21
+ className: item.id === page?.id ? 'active' : '',
21
22
  handler: () => switchPage(item.id),
22
23
  }"
23
24
  :key="index"
@@ -47,7 +48,7 @@ defineOptions({
47
48
  });
48
49
 
49
50
  defineProps<{
50
- list: MPage[] | MPageFragment[];
51
+ list: (MPage | MPageFragment)[];
51
52
  }>();
52
53
 
53
54
  const services = inject<Services>('services');
@@ -55,7 +56,8 @@ const uiService = services?.uiService;
55
56
  const editorService = services?.editorService;
56
57
 
57
58
  const showPageListButton = computed(() => uiService?.get('showPageListButton'));
58
- const switchPage = (id: Id) => {
59
- editorService?.select(id);
59
+ const page = computed(() => editorService?.get('page'));
60
+ const switchPage = async (id: Id) => {
61
+ await editorService?.select(id);
60
62
  };
61
63
  </script>
@@ -0,0 +1,67 @@
1
+ <template>
2
+ <div class="m-editor-page-bar-item m-editor-page-bar-item-icon m-editor-page-bar-search">
3
+ <Icon :icon="Search" @click="visible = !visible" :class="{ 'icon-active': visible }"></Icon>
4
+ <Teleport to=".m-editor-page-bar-tabs" v-if="visible">
5
+ <MForm
6
+ v-if="query"
7
+ class="m-editor-page-bar-search-panel"
8
+ :inline="true"
9
+ :config="formConfig"
10
+ :init-values="query"
11
+ :prevent-submit-default="true"
12
+ @change="onFormChange"
13
+ ></MForm>
14
+ </Teleport>
15
+ </div>
16
+ </template>
17
+
18
+ <script setup lang="ts">
19
+ import { ref } from 'vue';
20
+ import { Search } from '@element-plus/icons-vue';
21
+
22
+ import { NodeType } from '@tmagic/core';
23
+ import { createForm, MForm } from '@tmagic/form';
24
+
25
+ import Icon from '@editor/components/Icon.vue';
26
+
27
+ interface Query {
28
+ pageType: NodeType[];
29
+ keyword: string;
30
+ }
31
+
32
+ const emit = defineEmits<{
33
+ search: [value: Query];
34
+ }>();
35
+
36
+ const query = defineModel<Query>('query');
37
+
38
+ const formConfig = createForm([
39
+ {
40
+ type: 'checkbox-group',
41
+ name: 'pageType',
42
+ options: [
43
+ {
44
+ value: NodeType.PAGE,
45
+ text: '页面',
46
+ },
47
+ {
48
+ value: NodeType.PAGE_FRAGMENT,
49
+ text: '页面片段',
50
+ },
51
+ ],
52
+ },
53
+ {
54
+ name: 'keyword',
55
+ type: 'text',
56
+ placeholder: '请输入关键字',
57
+ clearable: true,
58
+ },
59
+ ]);
60
+
61
+ const visible = ref(false);
62
+
63
+ const onFormChange = (values: Query) => {
64
+ query.value = values;
65
+ emit('search', values);
66
+ };
67
+ </script>
@@ -0,0 +1,123 @@
1
+ <template>
2
+ <div class="m-editor-props-form-panel">
3
+ <slot name="props-form-panel-header"></slot>
4
+
5
+ <TMagicScrollbar>
6
+ <MForm
7
+ ref="configForm"
8
+ :class="propsPanelSize"
9
+ :popper-class="`m-editor-props-panel-popper ${propsPanelSize}`"
10
+ :label-width="labelWidth"
11
+ :label-position="labelPosition"
12
+ :size="propsPanelSize"
13
+ :init-values="values"
14
+ :config="config"
15
+ :extend-state="extendState"
16
+ @change="submit"
17
+ @error="errorHandler"
18
+ ></MForm>
19
+ </TMagicScrollbar>
20
+
21
+ <TMagicButton
22
+ v-if="!disabledShowSrc"
23
+ class="m-editor-props-panel-src-icon"
24
+ circle
25
+ title="源码"
26
+ :type="showSrc ? 'primary' : ''"
27
+ @click="showSrc = !showSrc"
28
+ >
29
+ <MIcon :icon="DocumentIcon"></MIcon>
30
+ </TMagicButton>
31
+
32
+ <CodeEditor
33
+ v-if="showSrc"
34
+ class="m-editor-props-panel-src-code"
35
+ :height="`${editorContentHeight}px`"
36
+ :init-values="codeValueKey ? values[codeValueKey] : values"
37
+ :options="codeOptions"
38
+ :parse="true"
39
+ @save="saveCode"
40
+ ></CodeEditor>
41
+ </div>
42
+ </template>
43
+
44
+ <script setup lang="ts">
45
+ import { computed, getCurrentInstance, inject, onMounted, ref, useTemplateRef, watchEffect } from 'vue';
46
+ import { Document as DocumentIcon } from '@element-plus/icons-vue';
47
+
48
+ import { TMagicButton, TMagicScrollbar } from '@tmagic/design';
49
+ import type { ContainerChangeEventData, FormConfig, FormState, FormValue } from '@tmagic/form';
50
+ import { MForm } from '@tmagic/form';
51
+
52
+ import MIcon from '@editor/components/Icon.vue';
53
+ import { useEditorContentHeight } from '@editor/hooks/use-editor-content-height';
54
+ import type { Services } from '@editor/type';
55
+
56
+ import CodeEditor from '../CodeEditor.vue';
57
+
58
+ defineSlots<{
59
+ 'props-form-panel-header'(props: {}): any;
60
+ }>();
61
+
62
+ defineOptions({
63
+ name: 'MEditorFormPanel',
64
+ });
65
+
66
+ const props = defineProps<{
67
+ config: FormConfig;
68
+ values: FormValue;
69
+ disabledShowSrc?: boolean;
70
+ labelWidth?: string;
71
+ codeValueKey?: string;
72
+ labelPosition?: string;
73
+ extendState?: (state: FormState) => Record<string, any> | Promise<Record<string, any>>;
74
+ }>();
75
+
76
+ const emit = defineEmits<{
77
+ submit: [values: any, eventData?: ContainerChangeEventData];
78
+ 'submit-error': [e: any];
79
+ 'form-error': [e: any];
80
+ mounted: [internalInstance: any];
81
+ }>();
82
+
83
+ const services = inject<Services>('services');
84
+ const codeOptions = inject('codeOptions', {});
85
+
86
+ const showSrc = ref(false);
87
+ const propsPanelSize = computed(() => services?.uiService.get('propsPanelSize') || 'small');
88
+ const { height: editorContentHeight } = useEditorContentHeight();
89
+ const stage = computed(() => services?.editorService.get('stage'));
90
+
91
+ const configForm = useTemplateRef<InstanceType<typeof MForm>>('configForm');
92
+
93
+ watchEffect(() => {
94
+ if (configForm.value) {
95
+ configForm.value.formState.stage = stage.value;
96
+ configForm.value.formState.services = services;
97
+ }
98
+ });
99
+
100
+ const internalInstance = getCurrentInstance();
101
+ onMounted(() => {
102
+ emit('mounted', internalInstance);
103
+ });
104
+
105
+ const submit = async (v: FormValue, eventData: ContainerChangeEventData) => {
106
+ try {
107
+ const values = await configForm.value?.submitForm();
108
+ emit('submit', values, eventData);
109
+ } catch (e: any) {
110
+ emit('submit-error', e);
111
+ }
112
+ };
113
+
114
+ const errorHandler = (e: any) => {
115
+ emit('form-error', e);
116
+ };
117
+
118
+ const saveCode = (values: any) => {
119
+ emit('submit', props.codeValueKey ? { [props.codeValueKey]: values } : values);
120
+ };
121
+
122
+ defineExpose({ configForm, submit });
123
+ </script>