@tmagic/form 1.8.0-beta.15 → 1.8.0-beta.16

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.
@@ -145,6 +145,17 @@ var Form_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCompo
145
145
  }
146
146
  });
147
147
  /**
148
+ * formState 的内置 key 快照(keyProp / values / $emit / fields / post 等)。
149
+ *
150
+ * 在 `extendState` 首次合并前捕获,`applyExtendState` 会据此禁止 `extendState`
151
+ * 覆盖这些已有字段(只能新增字段),避免表单核心状态被外部意外改写。
152
+ *
153
+ * 之所以在此处(effect 之外)捕获而不是在 `applyExtendState` 内动态取:
154
+ * `watchEffect` 会在依赖变化时重跑,若动态取,`extendState` 自己新增的字段在第二次
155
+ * 合并时也会被当成「已有 key」而拒绝刷新;这里只锁定内置字段即可规避该问题。
156
+ */
157
+ const reservedStateKeys = new Set(Reflect.ownKeys(formState));
158
+ /**
148
159
  * `extendState` 的同步段(直到第一个 `await` 之前)所访问的任何响应式数据,
149
160
  * 都会被 `watchEffect` 自动跟踪。这样可以兼容历史用法 ——
150
161
  *
@@ -179,7 +190,7 @@ var Form_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCompo
179
190
  return;
180
191
  }
181
192
  if (stale) return;
182
- applyExtendState(formState, state);
193
+ applyExtendState(formState, state, reservedStateKeys);
183
194
  });
184
195
  provide("mForm", formState);
185
196
  /**
@@ -54,7 +54,8 @@ var mountFormInstance = (options) => {
54
54
  console.error("[MForm] extendState failed:", e);
55
55
  return;
56
56
  }
57
- const apply = (state) => applyExtendState(form.formState, state);
57
+ const reservedStateKeys = new Set(Reflect.ownKeys(form.formState));
58
+ const apply = (state) => applyExtendState(form.formState, state, reservedStateKeys);
58
59
  if (result && typeof result.then === "function") result.then(apply, (e) => console.error("[MForm] extendState failed:", e));
59
60
  else apply(result);
60
61
  }, {
@@ -211,15 +211,19 @@ var sortChange = (data, { prop, order }) => {
211
211
  * - accessor 描述符(`{ get stage() { return ... } }`)按原样 defineProperty,调用方
212
212
  * 可控制读时求值;强制 `configurable: true` 以便下一次合并可再 define。
213
213
  *
214
- * 注意:formState 上由 props 派生的字段(keyProp / popperClass / config / initValues /
215
- * isCompare / lastValues / parentValues)是只读 getter(无 setter),extendState 若以
216
- * 普通字段形式返回同名 key,直接赋值会让 proxy set trap 失败并抛出
217
- * `TypeError: 'set' on proxy: trap returned falsish`,这里统一跳过并告警;
218
- * 如确需覆盖,可在 extendState 中以 get 访问器形式返回。
214
+ * 注意:extendState 只能向 formState「新增」字段,不允许覆盖其已有 key。
215
+ * 调用方可通过 `reservedKeys` 传入合并前已存在的内置 key 快照(keyProp / popperClass /
216
+ * config / initValues / isCompare / lastValues / parentValues / values / $emit / fields /
217
+ * post 等),命中这些 key 时统一跳过并告警。
218
+ *
219
+ * 兜底:未传 `reservedKeys` 时,仍会拦截 props 派生的只读 getter 字段(无 setter),
220
+ * 否则以普通字段形式赋值会让 proxy 的 set trap 抛出
221
+ * `TypeError: 'set' on proxy: trap returned falsish`。
219
222
  */
220
- var applyExtendState = (formState, state) => {
223
+ var applyExtendState = (formState, state, reservedKeys) => {
221
224
  if (!state) return;
222
225
  for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(state))) {
226
+ if (reservedKeys?.has(key)) continue;
223
227
  if (!("value" in descriptor)) {
224
228
  descriptor.configurable = true;
225
229
  Object.defineProperty(formState, key, descriptor);
@@ -89,7 +89,7 @@ var stringifyExampleValue = (value) => {
89
89
  }
90
90
  return String(value);
91
91
  };
92
- var MAX_SUGGESTION_OPTIONS = 5;
92
+ var MAX_SUGGESTION_OPTIONS = 20;
93
93
  /**
94
94
  * 生成「请使用以下某一个值:xxx;xxx」形式的参考建议;无可选值时返回空字符串(不追加建议)。
95
95
  * 可选值超过 MAX_SUGGESTION_OPTIONS 个时仅展示前若干个并以「等」省略。
@@ -2816,7 +2816,7 @@
2816
2816
  }
2817
2817
  return String(value);
2818
2818
  };
2819
- var MAX_SUGGESTION_OPTIONS = 5;
2819
+ var MAX_SUGGESTION_OPTIONS = 20;
2820
2820
  /**
2821
2821
  * 生成「请使用以下某一个值:xxx;xxx」形式的参考建议;无可选值时返回空字符串(不追加建议)。
2822
2822
  * 可选值超过 MAX_SUGGESTION_OPTIONS 个时仅展示前若干个并以「等」省略。
@@ -3340,15 +3340,19 @@
3340
3340
  * - accessor 描述符(`{ get stage() { return ... } }`)按原样 defineProperty,调用方
3341
3341
  * 可控制读时求值;强制 `configurable: true` 以便下一次合并可再 define。
3342
3342
  *
3343
- * 注意:formState 上由 props 派生的字段(keyProp / popperClass / config / initValues /
3344
- * isCompare / lastValues / parentValues)是只读 getter(无 setter),extendState 若以
3345
- * 普通字段形式返回同名 key,直接赋值会让 proxy set trap 失败并抛出
3346
- * `TypeError: 'set' on proxy: trap returned falsish`,这里统一跳过并告警;
3347
- * 如确需覆盖,可在 extendState 中以 get 访问器形式返回。
3343
+ * 注意:extendState 只能向 formState「新增」字段,不允许覆盖其已有 key。
3344
+ * 调用方可通过 `reservedKeys` 传入合并前已存在的内置 key 快照(keyProp / popperClass /
3345
+ * config / initValues / isCompare / lastValues / parentValues / values / $emit / fields /
3346
+ * post 等),命中这些 key 时统一跳过并告警。
3347
+ *
3348
+ * 兜底:未传 `reservedKeys` 时,仍会拦截 props 派生的只读 getter 字段(无 setter),
3349
+ * 否则以普通字段形式赋值会让 proxy 的 set trap 抛出
3350
+ * `TypeError: 'set' on proxy: trap returned falsish`。
3348
3351
  */
3349
- var applyExtendState = (formState, state) => {
3352
+ var applyExtendState = (formState, state, reservedKeys) => {
3350
3353
  if (!state) return;
3351
3354
  for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(state))) {
3355
+ if (reservedKeys?.has(key)) continue;
3352
3356
  if (!("value" in descriptor)) {
3353
3357
  descriptor.configurable = true;
3354
3358
  Object.defineProperty(formState, key, descriptor);
@@ -4167,6 +4171,17 @@
4167
4171
  }
4168
4172
  });
4169
4173
  /**
4174
+ * formState 的内置 key 快照(keyProp / values / $emit / fields / post 等)。
4175
+ *
4176
+ * 在 `extendState` 首次合并前捕获,`applyExtendState` 会据此禁止 `extendState`
4177
+ * 覆盖这些已有字段(只能新增字段),避免表单核心状态被外部意外改写。
4178
+ *
4179
+ * 之所以在此处(effect 之外)捕获而不是在 `applyExtendState` 内动态取:
4180
+ * `watchEffect` 会在依赖变化时重跑,若动态取,`extendState` 自己新增的字段在第二次
4181
+ * 合并时也会被当成「已有 key」而拒绝刷新;这里只锁定内置字段即可规避该问题。
4182
+ */
4183
+ const reservedStateKeys = new Set(Reflect.ownKeys(formState));
4184
+ /**
4170
4185
  * `extendState` 的同步段(直到第一个 `await` 之前)所访问的任何响应式数据,
4171
4186
  * 都会被 `watchEffect` 自动跟踪。这样可以兼容历史用法 ——
4172
4187
  *
@@ -4201,7 +4216,7 @@
4201
4216
  return;
4202
4217
  }
4203
4218
  if (stale) return;
4204
- applyExtendState(formState, state);
4219
+ applyExtendState(formState, state, reservedStateKeys);
4205
4220
  });
4206
4221
  (0, vue.provide)("mForm", formState);
4207
4222
  /**
@@ -4456,7 +4471,8 @@
4456
4471
  console.error("[MForm] extendState failed:", e);
4457
4472
  return;
4458
4473
  }
4459
- const apply = (state) => applyExtendState(form.formState, state);
4474
+ const reservedStateKeys = new Set(Reflect.ownKeys(form.formState));
4475
+ const apply = (state) => applyExtendState(form.formState, state, reservedStateKeys);
4460
4476
  if (result && typeof result.then === "function") result.then(apply, (e) => console.error("[MForm] extendState failed:", e));
4461
4477
  else apply(result);
4462
4478
  }, {
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.8.0-beta.15",
2
+ "version": "1.8.0-beta.16",
3
3
  "name": "@tmagic/form",
4
4
  "type": "module",
5
5
  "sideEffects": [
@@ -52,9 +52,9 @@
52
52
  "peerDependencies": {
53
53
  "vue": "^3.5.40",
54
54
  "typescript": "^6.0.3",
55
- "@tmagic/design": "1.8.0-beta.15",
56
- "@tmagic/form-schema": "1.8.0-beta.15",
57
- "@tmagic/utils": "1.8.0-beta.15"
55
+ "@tmagic/design": "1.8.0-beta.16",
56
+ "@tmagic/utils": "1.8.0-beta.16",
57
+ "@tmagic/form-schema": "1.8.0-beta.16"
58
58
  },
59
59
  "peerDependenciesMeta": {
60
60
  "typescript": {
package/src/Form.vue CHANGED
@@ -261,6 +261,18 @@ const formState: FormState = reactive<FormState>({
261
261
  },
262
262
  });
263
263
 
264
+ /**
265
+ * formState 的内置 key 快照(keyProp / values / $emit / fields / post 等)。
266
+ *
267
+ * 在 `extendState` 首次合并前捕获,`applyExtendState` 会据此禁止 `extendState`
268
+ * 覆盖这些已有字段(只能新增字段),避免表单核心状态被外部意外改写。
269
+ *
270
+ * 之所以在此处(effect 之外)捕获而不是在 `applyExtendState` 内动态取:
271
+ * `watchEffect` 会在依赖变化时重跑,若动态取,`extendState` 自己新增的字段在第二次
272
+ * 合并时也会被当成「已有 key」而拒绝刷新;这里只锁定内置字段即可规避该问题。
273
+ */
274
+ const reservedStateKeys = new Set<string | symbol>(Reflect.ownKeys(formState));
275
+
264
276
  /**
265
277
  * `extendState` 的同步段(直到第一个 `await` 之前)所访问的任何响应式数据,
266
278
  * 都会被 `watchEffect` 自动跟踪。这样可以兼容历史用法 ——
@@ -299,7 +311,7 @@ watchEffect(async (onCleanup) => {
299
311
  }
300
312
  if (stale) return;
301
313
 
302
- applyExtendState(formState, state);
314
+ applyExtendState(formState, state, reservedStateKeys);
303
315
  });
304
316
 
305
317
  provide('mForm', formState);
package/src/submitForm.ts CHANGED
@@ -204,10 +204,14 @@ const mountFormInstance = <T>(options: MountFormInstanceOptions<T>): Promise<T>
204
204
  console.error('[MForm] extendState failed:', e);
205
205
  return;
206
206
  }
207
+ // formState 的内置 key 快照:在 extendState 合并前捕获,
208
+ // 供 applyExtendState 禁止 extendState 覆盖这些已有字段(只能新增),
209
+ // 与 Form.vue 中 reservedStateKeys 的语义保持一致。
210
+ const reservedStateKeys = new Set<string | symbol>(Reflect.ownKeys(form.formState));
207
211
  // 合并逻辑收口在 applyExtendState:props 派生的只读 getter 字段
208
212
  // (keyProp 等)以普通字段形式返回时会被跳过并告警,避免 proxy set 抛错
209
213
  const apply = (state: Record<string, any> | null | undefined) =>
210
- applyExtendState(form.formState, state);
214
+ applyExtendState(form.formState, state, reservedStateKeys);
211
215
  if (result && typeof result.then === 'function') {
212
216
  result.then(apply, (e: any) => console.error('[MForm] extendState failed:', e));
213
217
  } else {
package/src/utils/form.ts CHANGED
@@ -449,16 +449,27 @@ export const sortChange = (data: any[], { prop, order }: SortProp) => {
449
449
  * - accessor 描述符(`{ get stage() { return ... } }`)按原样 defineProperty,调用方
450
450
  * 可控制读时求值;强制 `configurable: true` 以便下一次合并可再 define。
451
451
  *
452
- * 注意:formState 上由 props 派生的字段(keyProp / popperClass / config / initValues /
453
- * isCompare / lastValues / parentValues)是只读 getter(无 setter),extendState 若以
454
- * 普通字段形式返回同名 key,直接赋值会让 proxy set trap 失败并抛出
455
- * `TypeError: 'set' on proxy: trap returned falsish`,这里统一跳过并告警;
456
- * 如确需覆盖,可在 extendState 中以 get 访问器形式返回。
452
+ * 注意:extendState 只能向 formState「新增」字段,不允许覆盖其已有 key。
453
+ * 调用方可通过 `reservedKeys` 传入合并前已存在的内置 key 快照(keyProp / popperClass /
454
+ * config / initValues / isCompare / lastValues / parentValues / values / $emit / fields /
455
+ * post 等),命中这些 key 时统一跳过并告警。
456
+ *
457
+ * 兜底:未传 `reservedKeys` 时,仍会拦截 props 派生的只读 getter 字段(无 setter),
458
+ * 否则以普通字段形式赋值会让 proxy 的 set trap 抛出
459
+ * `TypeError: 'set' on proxy: trap returned falsish`。
457
460
  */
458
- export const applyExtendState = (formState: FormState, state: Record<string, any> | null | undefined): void => {
461
+ export const applyExtendState = (
462
+ formState: FormState,
463
+ state: Record<string, any> | null | undefined,
464
+ reservedKeys?: Set<string | symbol>,
465
+ ): void => {
459
466
  if (!state) return;
460
467
 
461
468
  for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(state))) {
469
+ if (reservedKeys?.has(key)) {
470
+ continue;
471
+ }
472
+
462
473
  if (!('value' in descriptor)) {
463
474
  descriptor.configurable = true;
464
475
  Object.defineProperty(formState, key, descriptor);
@@ -142,7 +142,7 @@ const stringifyExampleValue = (value: any): string => {
142
142
  };
143
143
 
144
144
  // 参考建议中最多展示的可选值个数,超出以「等」省略。
145
- const MAX_SUGGESTION_OPTIONS = 5;
145
+ const MAX_SUGGESTION_OPTIONS = 20;
146
146
 
147
147
  /**
148
148
  * 生成「请使用以下某一个值:xxx;xxx」形式的参考建议;无可选值时返回空字符串(不追加建议)。
package/types/index.d.ts CHANGED
@@ -290,13 +290,16 @@ declare const sortChange: (data: any[], {
290
290
  * - accessor 描述符(`{ get stage() { return ... } }`)按原样 defineProperty,调用方
291
291
  * 可控制读时求值;强制 `configurable: true` 以便下一次合并可再 define。
292
292
  *
293
- * 注意:formState 上由 props 派生的字段(keyProp / popperClass / config / initValues /
294
- * isCompare / lastValues / parentValues)是只读 getter(无 setter),extendState 若以
295
- * 普通字段形式返回同名 key,直接赋值会让 proxy set trap 失败并抛出
296
- * `TypeError: 'set' on proxy: trap returned falsish`,这里统一跳过并告警;
297
- * 如确需覆盖,可在 extendState 中以 get 访问器形式返回。
293
+ * 注意:extendState 只能向 formState「新增」字段,不允许覆盖其已有 key。
294
+ * 调用方可通过 `reservedKeys` 传入合并前已存在的内置 key 快照(keyProp / popperClass /
295
+ * config / initValues / isCompare / lastValues / parentValues / values / $emit / fields /
296
+ * post 等),命中这些 key 时统一跳过并告警。
297
+ *
298
+ * 兜底:未传 `reservedKeys` 时,仍会拦截 props 派生的只读 getter 字段(无 setter),
299
+ * 否则以普通字段形式赋值会让 proxy 的 set trap 抛出
300
+ * `TypeError: 'set' on proxy: trap returned falsish`。
298
301
  */
299
- declare const applyExtendState: (formState: schema_d_exports.FormState, state: Record<string, any> | null | undefined) => void;
302
+ declare const applyExtendState: (formState: schema_d_exports.FormState, state: Record<string, any> | null | undefined, reservedKeys?: Set<string | symbol>) => void;
300
303
  declare const createObjectProp: (prop: string, key: string, name?: string | number) => string;
301
304
  //#endregion
302
305
  //#region temp/packages/form/src/utils/useAddField.d.ts