@tmagic/editor 1.8.0-beta.26 → 1.8.0-beta.27

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.
@@ -1,4 +1,5 @@
1
- import { computed } from "vue";
1
+ import { FORM_CONTEXT_KEY, mergeFormContexts } from "@tmagic/form";
2
+ import { computed, inject, unref } from "vue";
2
3
  //#region packages/editor/src/hooks/use-form-context.ts
3
4
  /**
4
5
  * 编辑器注入给表单的业务上下文:`services` 与当前画布 `stage`。
@@ -6,14 +7,23 @@ import { computed } from "vue";
6
7
  * 由 `Editor.vue`(provide `FORM_CONTEXT_KEY`)、`FormPanel.vue` 与 `useCompareForm`
7
8
  * 共用。`stage` 走 computed 而非快照,保证切换画布后配置回调读到的是最新实例。
8
9
  *
10
+ * 宿主可能在 `<MEditor>` 外层 provide 了自己的业务字段,这里必须把那一层合并进来:
11
+ * 否则编辑器再 provide 一次会把宿主整层遮蔽掉,属性面板、对比表单里的配置回调就
12
+ * 读不到宿主字段了。`services` / `stage` 由编辑器兜底,优先级高于宿主同名字段。
13
+ *
9
14
  * 字段类型见 `@editor/type` 里对 `@tmagic/form-schema` 的 `FormContext` 模块增强。
10
15
  */
11
- var useEditorFormContext = (getServices) => computed(() => {
12
- const services = getServices();
13
- return {
14
- services,
15
- stage: services?.editorService.get("stage")
16
- };
17
- });
16
+ var useEditorFormContext = (getServices) => {
17
+ const hostContext = inject(FORM_CONTEXT_KEY, void 0);
18
+ return computed(() => {
19
+ const services = getServices();
20
+ const host = unref(hostContext);
21
+ if (host && host.services === services) return host;
22
+ return mergeFormContexts(host, {
23
+ services,
24
+ stage: services?.editorService.get("stage")
25
+ });
26
+ });
27
+ };
18
28
  //#endregion
19
29
  export { useEditorFormContext };
@@ -73,6 +73,7 @@ var initServiceState = (props, { editorService, historyService, componentListSer
73
73
  uiService.resetState();
74
74
  componentListService.resetState();
75
75
  codeBlockService.resetState();
76
+ eventsService.resetState();
76
77
  keybindingService.reset();
77
78
  depService.reset();
78
79
  });
@@ -47,8 +47,8 @@ var Events = class extends BaseService {
47
47
  return cloneDeep(methodMap[toLine(type)]) || [];
48
48
  }
49
49
  resetState() {
50
- eventMap = reactive({});
51
- methodMap = reactive({});
50
+ Object.keys(eventMap).forEach((type) => delete eventMap[type]);
51
+ Object.keys(methodMap).forEach((type) => delete methodMap[type]);
52
52
  }
53
53
  destroy() {
54
54
  this.resetState();
@@ -55,13 +55,20 @@ var getCodeBlockFormConfig = (options = {}) => {
55
55
  name: "timing",
56
56
  type: "select",
57
57
  options: () => {
58
- const list = [{
59
- text: "初始化前",
60
- value: "beforeInit"
61
- }, {
62
- text: "初始化后",
63
- value: "afterInit"
64
- }];
58
+ const list = [
59
+ {
60
+ text: "初始化前",
61
+ value: "beforeInit"
62
+ },
63
+ {
64
+ text: "初始化后",
65
+ value: "afterInit"
66
+ },
67
+ {
68
+ text: "页面渲染后",
69
+ value: "mounted"
70
+ }
71
+ ];
65
72
  if (dataSourceType?.() !== "base") {
66
73
  list.push({
67
74
  text: "请求前",
@@ -9120,8 +9120,8 @@
9120
9120
  return cloneDeep(methodMap[(0, _tmagic_utils.toLine)(type)]) || [];
9121
9121
  }
9122
9122
  resetState() {
9123
- eventMap = (0, vue.reactive)({});
9124
- methodMap = (0, vue.reactive)({});
9123
+ Object.keys(eventMap).forEach((type) => delete eventMap[type]);
9124
+ Object.keys(methodMap).forEach((type) => delete methodMap[type]);
9125
9125
  }
9126
9126
  destroy() {
9127
9127
  this.resetState();
@@ -5057,13 +5057,18 @@
5057
5057
  //#region packages/editor/src/hooks/use-form-context.ts
5058
5058
  var useEditorFormContext;
5059
5059
  var init_use_form_context = __esmMin((() => {
5060
- useEditorFormContext = (getServices) => (0, vue.computed)(() => {
5061
- const services = getServices();
5062
- return {
5063
- services,
5064
- stage: services?.editorService.get("stage")
5065
- };
5066
- });
5060
+ useEditorFormContext = (getServices) => {
5061
+ const hostContext = (0, vue.inject)(_tmagic_form.FORM_CONTEXT_KEY, void 0);
5062
+ return (0, vue.computed)(() => {
5063
+ const services = getServices();
5064
+ const host = (0, vue.unref)(hostContext);
5065
+ if (host && host.services === services) return host;
5066
+ return (0, _tmagic_form.mergeFormContexts)(host, {
5067
+ services,
5068
+ stage: services?.editorService.get("stage")
5069
+ });
5070
+ });
5071
+ };
5067
5072
  }));
5068
5073
  //#endregion
5069
5074
  //#region packages/editor/src/utils/config.ts
@@ -5130,13 +5135,20 @@
5130
5135
  name: "timing",
5131
5136
  type: "select",
5132
5137
  options: () => {
5133
- const list = [{
5134
- text: "初始化前",
5135
- value: "beforeInit"
5136
- }, {
5137
- text: "初始化后",
5138
- value: "afterInit"
5139
- }];
5138
+ const list = [
5139
+ {
5140
+ text: "初始化前",
5141
+ value: "beforeInit"
5142
+ },
5143
+ {
5144
+ text: "初始化后",
5145
+ value: "afterInit"
5146
+ },
5147
+ {
5148
+ text: "页面渲染后",
5149
+ value: "mounted"
5150
+ }
5151
+ ];
5140
5152
  if (dataSourceType?.() !== "base") {
5141
5153
  list.push({
5142
5154
  text: "请求前",
@@ -11208,8 +11220,8 @@
11208
11220
  return cloneDeep$1(methodMap[(0, _tmagic_utils.toLine)(type)]) || [];
11209
11221
  }
11210
11222
  resetState() {
11211
- eventMap = (0, vue.reactive)({});
11212
- methodMap = (0, vue.reactive)({});
11223
+ Object.keys(eventMap).forEach((type) => delete eventMap[type]);
11224
+ Object.keys(methodMap).forEach((type) => delete methodMap[type]);
11213
11225
  }
11214
11226
  destroy() {
11215
11227
  this.resetState();
@@ -20074,6 +20086,7 @@
20074
20086
  uiService.resetState();
20075
20087
  componentListService.resetState();
20076
20088
  codeBlockService.resetState();
20089
+ eventsService.resetState();
20077
20090
  keybindingService.reset();
20078
20091
  depService.reset();
20079
20092
  });
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.8.0-beta.26",
2
+ "version": "1.8.0-beta.27",
3
3
  "name": "@tmagic/editor",
4
4
  "type": "module",
5
5
  "sideEffects": [
@@ -63,11 +63,11 @@
63
63
  "moveable": "^0.53.0",
64
64
  "serialize-javascript": "^7.0.7",
65
65
  "sortablejs": "^1.15.7",
66
- "@tmagic/design": "1.8.0-beta.26",
67
- "@tmagic/form": "1.8.0-beta.26",
68
- "@tmagic/stage": "1.8.0-beta.26",
69
- "@tmagic/table": "1.8.0-beta.26",
70
- "@tmagic/utils": "1.8.0-beta.26"
66
+ "@tmagic/design": "1.8.0-beta.27",
67
+ "@tmagic/stage": "1.8.0-beta.27",
68
+ "@tmagic/table": "1.8.0-beta.27",
69
+ "@tmagic/form": "1.8.0-beta.27",
70
+ "@tmagic/utils": "1.8.0-beta.27"
71
71
  },
72
72
  "devDependencies": {
73
73
  "@types/events": "^3.0.3",
@@ -81,7 +81,7 @@
81
81
  "type-fest": "^5.2.0",
82
82
  "typescript": "^6.0.3",
83
83
  "vue": "^3.5.41",
84
- "@tmagic/core": "1.8.0-beta.26"
84
+ "@tmagic/core": "1.8.0-beta.27"
85
85
  },
86
86
  "peerDependenciesMeta": {
87
87
  "typescript": {
@@ -16,9 +16,9 @@
16
16
  * limitations under the License.
17
17
  */
18
18
 
19
- import { computed, type ComputedRef } from 'vue';
19
+ import { computed, type ComputedRef, inject, unref } from 'vue';
20
20
 
21
- import type { FormContext } from '@tmagic/form';
21
+ import { FORM_CONTEXT_KEY, type FormContext, mergeFormContexts } from '@tmagic/form';
22
22
 
23
23
  import type { Services } from '@editor/type';
24
24
 
@@ -28,13 +28,29 @@ import type { Services } from '@editor/type';
28
28
  * 由 `Editor.vue`(provide `FORM_CONTEXT_KEY`)、`FormPanel.vue` 与 `useCompareForm`
29
29
  * 共用。`stage` 走 computed 而非快照,保证切换画布后配置回调读到的是最新实例。
30
30
  *
31
+ * 宿主可能在 `<MEditor>` 外层 provide 了自己的业务字段,这里必须把那一层合并进来:
32
+ * 否则编辑器再 provide 一次会把宿主整层遮蔽掉,属性面板、对比表单里的配置回调就
33
+ * 读不到宿主字段了。`services` / `stage` 由编辑器兜底,优先级高于宿主同名字段。
34
+ *
31
35
  * 字段类型见 `@editor/type` 里对 `@tmagic/form-schema` 的 `FormContext` 模块增强。
32
36
  */
33
- export const useEditorFormContext = (getServices: () => Services | undefined): ComputedRef<FormContext> =>
34
- computed(() => {
37
+ export const useEditorFormContext = (getServices: () => Services | undefined): ComputedRef<FormContext> => {
38
+ // inject 只能在 setup 期取值,因此本 hook 必须在 setup 中调用(`use` 前缀即此约定)。
39
+ // 返回的 computed 可以随便传递,但 hook 本身不能延迟到事件回调或 onMounted 里再调。
40
+ const hostContext = inject(FORM_CONTEXT_KEY, undefined);
41
+
42
+ return computed(() => {
35
43
  const services = getServices();
36
- return {
44
+ const host = unref(hostContext);
45
+
46
+ // 上层(通常是 Editor.vue)已经用同一份 services 合并过了。FormPanel / useCompareForm
47
+ // 都是它的后代,再合并一次只会多套一层 Proxy,让每次属性 miss 多一轮线性查找。
48
+ // services 相同即可判定 stage 也相同——两边都是从同一个 editorService 读的。
49
+ if (host && host.services === services) return host;
50
+
51
+ return mergeFormContexts(host, {
37
52
  services,
38
53
  stage: services?.editorService.get('stage'),
39
- };
54
+ });
40
55
  });
56
+ };
@@ -254,6 +254,7 @@ export const initServiceState = (
254
254
  uiService.resetState();
255
255
  componentListService.resetState();
256
256
  codeBlockService.resetState();
257
+ eventsService.resetState();
257
258
  keybindingService.reset();
258
259
  depService.reset();
259
260
  });
@@ -35,8 +35,8 @@ const canUsePluginMethods = {
35
35
  type AsyncMethodName = Writable<(typeof canUsePluginMethods)['async']>;
36
36
  type SyncMethodName = Writable<(typeof canUsePluginMethods)['sync']>;
37
37
 
38
- let eventMap: Record<string, EventOption[]> = reactive({});
39
- let methodMap: Record<string, EventOption[]> = reactive({});
38
+ const eventMap: Record<string, EventOption[]> = reactive({});
39
+ const methodMap: Record<string, EventOption[]> = reactive({});
40
40
 
41
41
  class Events extends BaseService {
42
42
  constructor() {
@@ -75,8 +75,9 @@ class Events extends BaseService {
75
75
  }
76
76
 
77
77
  public resetState() {
78
- eventMap = reactive({});
79
- methodMap = reactive({});
78
+ // 原地清空而不是重新赋值,保留 reactive 代理身份,已建立的 computed / 渲染副作用才能收到更新
79
+ Object.keys(eventMap).forEach((type) => delete eventMap[type]);
80
+ Object.keys(methodMap).forEach((type) => delete methodMap[type]);
80
81
  }
81
82
 
82
83
  public destroy() {
package/src/type.ts CHANGED
@@ -225,6 +225,7 @@ export interface StageOptions {
225
225
  beforeDblclick?: (event: MouseEvent) => Promise<boolean | void> | boolean | void;
226
226
  }
227
227
 
228
+ // #region NodeInvalidInfo
228
229
  /**
229
230
  * 节点校验错误信息,按来源(属性表单 / 样式表单)分别保存错误文案。
230
231
  * 属性表单与样式表单是两个独立的 FormPanel,均指向同一节点,故以来源为键,
@@ -237,9 +238,12 @@ export interface NodeInvalidInfo {
237
238
  /** 样式表单校验错误文案(可能为包含 <br> 的 HTML) */
238
239
  style?: string;
239
240
  }
241
+ // #endregion NodeInvalidInfo
240
242
 
243
+ // #region NodeInvalidSource
241
244
  /** 节点校验错误来源 */
242
245
  export type NodeInvalidSource = keyof NodeInvalidInfo;
246
+ // #endregion NodeInvalidSource
243
247
 
244
248
  export interface StoreState {
245
249
  root: MApp | null;
@@ -312,6 +316,7 @@ export interface StageRect {
312
316
  height: number | string;
313
317
  }
314
318
 
319
+ // #region UiState
315
320
  export interface UiState {
316
321
  /** 当前点击画布是否触发选中,true: 不触发,false: 触发,默认为false */
317
322
  uiSelectMode: boolean;
@@ -369,6 +374,7 @@ export interface UiState {
369
374
  height: number;
370
375
  };
371
376
  }
377
+ // #endregion UiState
372
378
 
373
379
  // #region EditorNodeInfo
374
380
  export interface EditorNodeInfo {
@@ -103,6 +103,7 @@ export const getCodeBlockFormConfig = (options: GetCodeBlockFormConfigOptions =
103
103
  const list = [
104
104
  { text: '初始化前', value: 'beforeInit' },
105
105
  { text: '初始化后', value: 'afterInit' },
106
+ { text: '页面渲染后', value: 'mounted' },
106
107
  ];
107
108
  if (dataSourceType?.() !== 'base') {
108
109
  list.push({ text: '请求前', value: 'beforeRequest' });