@tmagic/editor 1.5.0-beta.11 → 1.5.0-beta.13

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.
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.5.0-beta.11",
2
+ "version": "1.5.0-beta.13",
3
3
  "name": "@tmagic/editor",
4
4
  "type": "module",
5
5
  "sideEffects": [
@@ -56,11 +56,11 @@
56
56
  "moveable": "^0.53.0",
57
57
  "serialize-javascript": "^6.0.0",
58
58
  "sortablejs": "^1.15.2",
59
- "@tmagic/design": "1.5.0-beta.11",
60
- "@tmagic/stage": "1.5.0-beta.11",
61
- "@tmagic/form": "1.5.0-beta.11",
62
- "@tmagic/table": "1.5.0-beta.11",
63
- "@tmagic/utils": "1.5.0-beta.11"
59
+ "@tmagic/design": "1.5.0-beta.13",
60
+ "@tmagic/stage": "1.5.0-beta.13",
61
+ "@tmagic/form": "1.5.0-beta.13",
62
+ "@tmagic/table": "1.5.0-beta.13",
63
+ "@tmagic/utils": "1.5.0-beta.13"
64
64
  },
65
65
  "devDependencies": {
66
66
  "@types/events": "^3.0.0",
@@ -81,7 +81,7 @@
81
81
  "monaco-editor": "^0.48.0",
82
82
  "typescript": "*",
83
83
  "vue": "^3.5.0",
84
- "@tmagic/core": "1.5.0-beta.11"
84
+ "@tmagic/core": "1.5.0-beta.13"
85
85
  },
86
86
  "peerDependenciesMeta": {
87
87
  "typescript": {
package/src/Editor.vue CHANGED
@@ -1,5 +1,9 @@
1
1
  <template>
2
- <Framework :disabled-page-fragment="disabledPageFragment" :page-bar-sort-options="pageBarSortOptions">
2
+ <Framework
3
+ :disabled-page-fragment="disabledPageFragment"
4
+ :page-bar-sort-options="pageBarSortOptions"
5
+ :page-filter-function="pageFilterFunction"
6
+ >
3
7
  <template #header>
4
8
  <slot name="header"></slot>
5
9
  </template>
@@ -114,6 +118,7 @@
114
118
  </template>
115
119
 
116
120
  <template #page-bar><slot name="page-bar"></slot></template>
121
+ <template #page-bar-add-button><slot name="page-bar-add-button"></slot></template>
117
122
  <template #page-bar-title="{ page }"><slot name="page-bar-title" :page="page"></slot></template>
118
123
  <template #page-bar-popover="{ page }"><slot name="page-bar-popover" :page="page"></slot></template>
119
124
  <template #page-list-popover="{ list }"><slot name="page-list-popover" :list="list"></slot></template>
@@ -1,4 +1,4 @@
1
- import type { DataSourceSchema, EventOption, Id, MApp, MNode } from '@tmagic/core';
1
+ import type { DataSourceSchema, EventOption, Id, MApp, MNode, MPage, MPageFragment } from '@tmagic/core';
2
2
  import type { FormConfig, FormState } from '@tmagic/form';
3
3
  import StageCore, {
4
4
  CONTAINER_HIGHLIGHT_CLASS_NAME,
@@ -97,6 +97,8 @@ export interface EditorProps {
97
97
  extendFormState?: (state: FormState) => Record<string, any> | Promise<Record<string, any>>;
98
98
  /** 页面顺序拖拽配置参数 */
99
99
  pageBarSortOptions?: PageBarSortOptions;
100
+ /** 页面搜索函数 */
101
+ pageFilterFunction?: (page: MPage | MPageFragment, keyword: string) => boolean;
100
102
  }
101
103
 
102
104
  export const defaultEditorProps = {
@@ -1,5 +1,5 @@
1
1
  import { onBeforeUnmount, reactive, toRaw, watch } from 'vue';
2
- import { cloneDeep, debounce } from 'lodash-es';
2
+ import { cloneDeep } from 'lodash-es';
3
3
 
4
4
  import type {
5
5
  CodeBlockContent,
@@ -19,7 +19,7 @@ import {
19
19
  DepTargetType,
20
20
  Target,
21
21
  } from '@tmagic/core';
22
- import { isPage, traverseNode } from '@tmagic/utils';
22
+ import { getNodes, isPage, traverseNode } from '@tmagic/utils';
23
23
 
24
24
  import PropsPanel from './layouts/PropsPanel.vue';
25
25
  import { EditorProps } from './editorProps';
@@ -252,63 +252,24 @@ export const initServiceEvents = (
252
252
  return stage?.renderer?.runtime?.getApp?.();
253
253
  };
254
254
 
255
- const updateDataSourceSchema = () => {
256
- const root = editorService.get('root');
257
-
258
- if (root?.dataSources) {
259
- getApp()?.dataSourceManager?.updateSchema(root.dataSources);
260
- }
261
- };
262
-
263
- const targetAddHandler = (target: Target) => {
264
- const root = editorService.get('root');
265
- if (!root) return;
266
-
267
- if (target.type === DepTargetType.DATA_SOURCE) {
268
- if (!root.dataSourceDeps) {
269
- root.dataSourceDeps = {};
270
- }
271
- root.dataSourceDeps[target.id] = target.deps;
272
- }
273
-
274
- if (target.type === DepTargetType.DATA_SOURCE_COND) {
275
- if (!root.dataSourceCondDeps) {
276
- root.dataSourceCondDeps = {};
277
- }
278
- root.dataSourceCondDeps[target.id] = target.deps;
279
- }
280
- };
281
-
282
- const targetRemoveHandler = (id: string | number) => {
255
+ const updateDataSourceSchema = (nodes: MNode[], deep: boolean) => {
283
256
  const root = editorService.get('root');
257
+ const app = getApp();
284
258
 
285
- if (root?.dataSourceDeps) {
286
- delete root.dataSourceDeps[id];
259
+ if (root && app?.dsl) {
260
+ app.dsl.dataSourceDeps = root.dataSourceDeps;
261
+ app.dsl.dataSourceCondDeps = root.dataSourceCondDeps;
262
+ app.dsl.dataSources = root.dataSources;
287
263
  }
288
264
 
289
- if (root?.dataSourceCondDeps) {
290
- delete root.dataSourceCondDeps[id];
265
+ if (root?.dataSources) {
266
+ getApp()?.dataSourceManager?.updateSchema(root.dataSources);
291
267
  }
292
- };
293
268
 
294
- const collectedHandler = debounce((nodes: MNode[], deep: boolean) => {
295
- const root = editorService.get('root');
296
269
  const stage = editorService.get('stage');
297
270
 
298
271
  if (!root || !stage) return;
299
272
 
300
- const app = getApp();
301
-
302
- if (!app) return;
303
-
304
- if (app.dsl) {
305
- app.dsl.dataSourceDeps = root.dataSourceDeps;
306
- app.dsl.dataSourceCondDeps = root.dataSourceCondDeps;
307
- app.dsl.dataSources = root.dataSources;
308
- }
309
-
310
- updateDataSourceSchema();
311
-
312
273
  const allNodes: MNode[] = [];
313
274
 
314
275
  if (deep) {
@@ -335,11 +296,60 @@ export const initServiceEvents = (
335
296
  });
336
297
  });
337
298
  });
338
- }, 300);
299
+ };
300
+
301
+ const afterUpdateNodes = (nodes: MNode[]) => {
302
+ const root = editorService.get('root');
303
+ if (!root) return;
304
+ const stage = editorService.get('stage');
305
+ const app = getApp();
306
+ if (app?.dsl) {
307
+ app.dsl.dataSourceDeps = root.dataSourceDeps;
308
+ }
309
+ for (const node of nodes) {
310
+ stage?.update({
311
+ config: cloneDeep(node),
312
+ parentId: editorService.getParentById(node.id)?.id,
313
+ root: cloneDeep(root),
314
+ });
315
+ }
316
+ };
317
+
318
+ const targetAddHandler = (target: Target) => {
319
+ const root = editorService.get('root');
320
+ if (!root) return;
321
+
322
+ if (target.type === DepTargetType.DATA_SOURCE) {
323
+ if (!root.dataSourceDeps) {
324
+ root.dataSourceDeps = {};
325
+ }
326
+ root.dataSourceDeps[target.id] = target.deps;
327
+ }
328
+
329
+ if (target.type === DepTargetType.DATA_SOURCE_COND) {
330
+ if (!root.dataSourceCondDeps) {
331
+ root.dataSourceCondDeps = {};
332
+ }
333
+ root.dataSourceCondDeps[target.id] = target.deps;
334
+ }
335
+ };
336
+
337
+ const targetRemoveHandler = (id: string | number) => {
338
+ const root = editorService.get('root');
339
+
340
+ if (!root) return;
341
+
342
+ if (root.dataSourceDeps) {
343
+ delete root.dataSourceDeps[id];
344
+ }
345
+
346
+ if (root.dataSourceCondDeps) {
347
+ delete root.dataSourceCondDeps[id];
348
+ }
349
+ };
339
350
 
340
351
  depService.on('add-target', targetAddHandler);
341
352
  depService.on('remove-target', targetRemoveHandler);
342
- depService.on('collected', collectedHandler);
343
353
 
344
354
  const initDataSourceDepTarget = (ds: DataSourceSchema) => {
345
355
  depService.addTarget(createDataSourceTarget(ds, reactive({})));
@@ -347,28 +357,33 @@ export const initServiceEvents = (
347
357
  depService.addTarget(createDataSourceCondTarget(ds, reactive({})));
348
358
  };
349
359
 
350
- const collectIdle = (nodes: MNode[], deep: boolean) => {
351
- nodes.forEach((node) => {
352
- let pageId: Id | undefined;
353
-
354
- if (isPage(node)) {
355
- pageId = node.id;
356
- } else {
357
- const info = editorService.getNodeInfo(node.id);
358
- pageId = info.page?.id;
359
- }
360
- depService.collectIdle([node], { pageId }, deep);
361
- });
362
- };
360
+ const collectIdle = (nodes: MNode[], deep: boolean) =>
361
+ Promise.all(
362
+ nodes.map((node) => {
363
+ let pageId: Id | undefined;
364
+
365
+ if (isPage(node)) {
366
+ pageId = node.id;
367
+ } else {
368
+ const info = editorService.getNodeInfo(node.id);
369
+ pageId = info.page?.id;
370
+ }
371
+ return depService.collectIdle([node], { pageId }, deep);
372
+ }),
373
+ );
363
374
 
364
375
  // 新增节点,收集依赖
365
376
  const nodeAddHandler = (nodes: MNode[]) => {
366
- collectIdle(nodes, true);
377
+ collectIdle(nodes, true).then(() => {
378
+ afterUpdateNodes(nodes);
379
+ });
367
380
  };
368
381
 
369
382
  // 节点更新,收集依赖
370
383
  const nodeUpdateHandler = (nodes: MNode[]) => {
371
- collectIdle(nodes, true);
384
+ collectIdle(nodes, true).then(() => {
385
+ afterUpdateNodes(nodes);
386
+ });
372
387
  };
373
388
 
374
389
  // 节点删除,清除对齐的依赖收集
@@ -378,7 +393,9 @@ export const initServiceEvents = (
378
393
 
379
394
  // 由于历史记录变化是更新整个page,所以历史记录变化时,需要重新收集依赖
380
395
  const historyChangeHandler = (page: MPage | MPageFragment) => {
381
- collectIdle([page], true);
396
+ collectIdle([page], true).then(() => {
397
+ updateDataSourceSchema([page], true);
398
+ });
382
399
  };
383
400
 
384
401
  editorService.on('history-change', historyChangeHandler);
@@ -413,7 +430,9 @@ export const initServiceEvents = (
413
430
  removeDataSourceTarget(config.id);
414
431
  initDataSourceDepTarget(config);
415
432
 
416
- collectIdle(root?.items || [], true);
433
+ collectIdle(root?.items || [], true).then(() => {
434
+ updateDataSourceSchema(root?.items || [], true);
435
+ });
417
436
  };
418
437
 
419
438
  const removeDataSourceTarget = (id: string) => {
@@ -423,8 +442,14 @@ export const initServiceEvents = (
423
442
  };
424
443
 
425
444
  const dataSourceRemoveHandler = (id: string) => {
445
+ const root = editorService.get('root');
446
+ const nodeIds = Object.keys(root?.dataSourceDeps?.[id] || {});
447
+ const nodes = getNodes(nodeIds, root?.items);
448
+ collectIdle(nodes, false).then(() => {
449
+ updateDataSourceSchema(nodes, false);
450
+ });
451
+
426
452
  removeDataSourceTarget(id);
427
- getApp()?.dataSourceManager?.removeDataSource(id);
428
453
  };
429
454
 
430
455
  dataSourceService.on('add', dataSourceAddHandler);
@@ -434,7 +459,6 @@ export const initServiceEvents = (
434
459
  onBeforeUnmount(() => {
435
460
  depService.off('add-target', targetAddHandler);
436
461
  depService.off('remove-target', targetRemoveHandler);
437
- depService.off('collected', collectedHandler);
438
462
 
439
463
  editorService.off('history-change', historyChangeHandler);
440
464
  editorService.off('root-change', rootChangeHandler);
@@ -38,7 +38,12 @@
38
38
  </slot>
39
39
 
40
40
  <slot name="page-bar">
41
- <PageBar :disabled-page-fragment="disabledPageFragment" :page-bar-sort-options="pageBarSortOptions">
41
+ <PageBar
42
+ :disabled-page-fragment="disabledPageFragment"
43
+ :page-bar-sort-options="pageBarSortOptions"
44
+ :filter-function="pageFilterFunction"
45
+ >
46
+ <template #page-bar-add-button><slot name="page-bar-add-button"></slot></template>
42
47
  <template #page-bar-title="{ page }"><slot name="page-bar-title" :page="page"></slot></template>
43
48
  <template #page-bar-popover="{ page }"><slot name="page-bar-popover" :page="page"></slot></template>
44
49
  <template #page-list-popover="{ list }"><slot name="page-list-popover" :list="list"></slot></template>
@@ -61,6 +66,7 @@
61
66
  <script lang="ts" setup>
62
67
  import { computed, inject, onBeforeUnmount, onMounted, ref, watch } from 'vue';
63
68
 
69
+ import type { MPage, MPageFragment } from '@tmagic/core';
64
70
  import { TMagicScrollbar } from '@tmagic/design';
65
71
 
66
72
  import SplitView from '@editor/components/SplitView.vue';
@@ -80,6 +86,7 @@ defineOptions({
80
86
  defineProps<{
81
87
  disabledPageFragment: boolean;
82
88
  pageBarSortOptions?: PageBarSortOptions;
89
+ pageFilterFunction?: (page: MPage | MPageFragment, keyword: string) => boolean;
83
90
  }>();
84
91
 
85
92
  const DEFAULT_LEFT_COLUMN_WIDTH = 310;
@@ -3,9 +3,31 @@
3
3
  v-if="showAddPageButton"
4
4
  id="m-editor-page-bar-add-icon"
5
5
  class="m-editor-page-bar-item m-editor-page-bar-item-icon"
6
- @click="addPage"
7
6
  >
8
- <Icon :icon="Plus"></Icon>
7
+ <TMagicPopover popper-class="data-source-list-panel-add-menu">
8
+ <template #reference>
9
+ <Icon :icon="Plus"></Icon>
10
+ </template>
11
+
12
+ <ToolButton
13
+ :data="{
14
+ type: 'button',
15
+ text: '页面',
16
+ handler: () => {
17
+ addPage(NodeType.PAGE);
18
+ },
19
+ }"
20
+ ></ToolButton>
21
+ <ToolButton
22
+ :data="{
23
+ type: 'button',
24
+ text: '页面片',
25
+ handler: () => {
26
+ addPage(NodeType.PAGE_FRAGMENT);
27
+ },
28
+ }"
29
+ ></ToolButton>
30
+ </TMagicPopover>
9
31
  </div>
10
32
  <div v-else style="width: 21px"></div>
11
33
  </template>
@@ -15,8 +37,10 @@ import { computed, inject, toRaw } from 'vue';
15
37
  import { Plus } from '@element-plus/icons-vue';
16
38
 
17
39
  import { NodeType } from '@tmagic/core';
40
+ import { TMagicPopover } from '@tmagic/design';
18
41
 
19
42
  import Icon from '@editor/components/Icon.vue';
43
+ import ToolButton from '@editor/components/ToolButton.vue';
20
44
  import type { Services } from '@editor/type';
21
45
  import { generatePageNameByApp } from '@editor/utils/editor';
22
46
 
@@ -24,23 +48,19 @@ defineOptions({
24
48
  name: 'MEditorPageBarAddButton',
25
49
  });
26
50
 
27
- const props = defineProps<{
28
- type: NodeType.PAGE | NodeType.PAGE_FRAGMENT;
29
- }>();
30
-
31
51
  const services = inject<Services>('services');
32
52
  const uiService = services?.uiService;
33
53
  const editorService = services?.editorService;
34
54
 
35
55
  const showAddPageButton = computed(() => uiService?.get('showAddPageButton'));
36
56
 
37
- const addPage = () => {
57
+ const addPage = (type: NodeType.PAGE | NodeType.PAGE_FRAGMENT) => {
38
58
  if (!editorService) return;
39
59
  const root = toRaw(editorService.get('root'));
40
60
  if (!root) throw new Error('root 不能为空');
41
61
  const pageConfig = {
42
- type: props.type,
43
- name: generatePageNameByApp(root, props.type),
62
+ type,
63
+ name: generatePageNameByApp(root, type),
44
64
  items: [],
45
65
  };
46
66
  editorService.add(pageConfig);
@@ -1,10 +1,10 @@
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 :page-bar-sort-options="pageBarSortOptions" :length="list.length">
6
4
  <template #prepend>
7
- <AddButton :type="active"></AddButton>
5
+ <slot name="page-bar-add-button"><AddButton></AddButton></slot>
6
+
7
+ <Search v-model:query="query"></Search>
8
8
  <PageList :list="list">
9
9
  <template #page-list-popover="{ list }"><slot name="page-list-popover" :list="list"></slot></template>
10
10
  </PageList>
@@ -63,94 +63,64 @@
63
63
  </template>
64
64
 
65
65
  <script lang="ts" setup>
66
- import { computed, inject, ref, watch } from 'vue';
66
+ import { computed, inject, ref } from 'vue';
67
67
  import { CaretBottom, Delete, DocumentCopy } from '@element-plus/icons-vue';
68
68
 
69
69
  import { type Id, type MPage, type MPageFragment, NodeType } from '@tmagic/core';
70
70
  import { TMagicIcon, TMagicPopover } from '@tmagic/design';
71
- import { isPage, isPageFragment } from '@tmagic/utils';
72
71
 
73
72
  import ToolButton from '@editor/components/ToolButton.vue';
74
73
  import type { PageBarSortOptions, Services } from '@editor/type';
75
- import { getPageFragmentList, getPageList } from '@editor/utils';
76
74
 
77
75
  import AddButton from './AddButton.vue';
78
76
  import PageBarScrollContainer from './PageBarScrollContainer.vue';
79
77
  import PageList from './PageList.vue';
80
- import SwitchTypeButton from './SwitchTypeButton.vue';
78
+ import Search from './Search.vue';
81
79
 
82
80
  defineOptions({
83
81
  name: 'MEditorPageBar',
84
82
  });
85
83
 
86
- defineProps<{
87
- disabledPageFragment: boolean;
88
- pageBarSortOptions?: PageBarSortOptions;
89
- }>();
90
-
91
- const active = ref<NodeType.PAGE | NodeType.PAGE_FRAGMENT>(NodeType.PAGE);
84
+ const props = withDefaults(
85
+ defineProps<{
86
+ disabledPageFragment: boolean;
87
+ pageBarSortOptions?: PageBarSortOptions;
88
+ filterFunction?: (page: MPage | MPageFragment, keyword: string) => boolean;
89
+ }>(),
90
+ {
91
+ filterFunction: (page, keyword) => page.name?.includes(keyword) || `${page.id}`.includes(keyword),
92
+ },
93
+ );
92
94
 
93
95
  const services = inject<Services>('services');
94
96
  const editorService = services?.editorService;
95
97
 
96
98
  const root = computed(() => editorService?.get('root'));
97
99
  const page = computed(() => editorService?.get('page'));
98
- const pageList = computed(() => getPageList(root.value));
99
- const pageFragmentList = computed(() => getPageFragmentList(root.value));
100
-
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
100
 
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
- );
101
+ const query = ref<{
102
+ pageType: NodeType[];
103
+ keyword: string;
104
+ }>({
105
+ pageType: [NodeType.PAGE, NodeType.PAGE_FRAGMENT],
106
+ keyword: '',
107
+ });
135
108
 
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;
109
+ const list = computed(() => {
110
+ const { pageType, keyword } = query.value;
111
+ if (pageType.length === 0) {
112
+ return [];
144
113
  }
145
114
 
146
- if (active === NodeType.PAGE_FRAGMENT) {
147
- // 之前没有选中过页面片并且当前没有页面片
148
- if (!activePageFragment.value && !pageFragmentList.value.length) {
149
- editorService?.selectRoot();
150
- return;
115
+ return (root.value?.items || []).filter((item) => {
116
+ if (pageType.includes(item.type)) {
117
+ if (keyword) {
118
+ return props.filterFunction(item, keyword);
119
+ }
120
+ return true;
151
121
  }
152
- switchPage(activePageFragment.value || pageFragmentList.value[0].id);
153
- }
122
+ return false;
123
+ });
154
124
  });
155
125
 
156
126
  const switchPage = (id: Id) => {