@tmagic/form 1.7.14-beta.3 → 1.8.0-beta.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.
@@ -52,14 +52,45 @@ var Form_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineCom
52
52
  const lastValuesProcessed = ref({});
53
53
  const fields = /* @__PURE__ */ new Map();
54
54
  const requestFuc = getConfig("request");
55
+ /**
56
+ * formState 实现说明:
57
+ *
58
+ * 1. 与 props 直接对应的字段(config / initValues / lastValues / isCompare / parentValues /
59
+ * keyProp / popperClass)使用「访问器(getter)」定义,每次读取都会回到 `props.xxx`
60
+ * 取最新值,不存在「props 变了但 formState 还没同步过来」的中间态。
61
+ *
62
+ * 2. `values` / `lastValuesProcessed` 是 ref,Vue 的 `reactive` 会自动解包,因此每次
63
+ * 访问 `formState.values` / `formState.lastValuesProcessed` 也都是当前 ref 值。
64
+ *
65
+ * 3. `extendState` 注入的字段在下方的 `watchEffect` 中合并到 `formState`:
66
+ * - data 描述符(普通字段)通过 `formState[key] = value` 写入,走 reactive proxy 的
67
+ * set,触发依赖通知;`extendState` 同步段读到的响应式数据变化时会自动重跑,
68
+ * 把最新值刷进 formState。
69
+ * - accessor 描述符(`{ get stage() { return ... } }`)按原样写入,调用方可以控制
70
+ * 读时求值,每次读取都会重新执行 getter。
71
+ */
55
72
  const formState = reactive({
56
- keyProp: props.keyProp,
57
- popperClass: props.popperClass,
58
- config: props.config,
59
- initValues: props.initValues,
60
- isCompare: props.isCompare,
61
- lastValues: props.lastValues,
62
- parentValues: props.parentValues,
73
+ get keyProp() {
74
+ return props.keyProp;
75
+ },
76
+ get popperClass() {
77
+ return props.popperClass;
78
+ },
79
+ get config() {
80
+ return props.config;
81
+ },
82
+ get initValues() {
83
+ return props.initValues;
84
+ },
85
+ get isCompare() {
86
+ return props.isCompare;
87
+ },
88
+ get lastValues() {
89
+ return props.lastValues;
90
+ },
91
+ get parentValues() {
92
+ return props.parentValues;
93
+ },
63
94
  values,
64
95
  lastValuesProcessed,
65
96
  $emit: emit,
@@ -76,19 +107,46 @@ var Form_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineCom
76
107
  });
77
108
  }
78
109
  });
79
- watchEffect(async () => {
80
- formState.initValues = props.initValues;
81
- formState.lastValues = props.lastValues;
82
- formState.isCompare = props.isCompare;
83
- formState.config = props.config;
84
- formState.keyProp = props.keyProp;
85
- formState.popperClass = props.popperClass;
86
- formState.parentValues = props.parentValues;
87
- if (typeof props.extendState === "function") {
88
- const state = await props.extendState(formState) || {};
89
- Object.entries(state).forEach(([key, value]) => {
90
- formState[key] = value;
91
- });
110
+ /**
111
+ * `extendState` 的同步段(直到第一个 `await` 之前)所访问的任何响应式数据,
112
+ * 都会被 `watchEffect` 自动跟踪。这样可以兼容历史用法 ——
113
+ *
114
+ * extendState: (formState) => ({
115
+ * username: store.username, // 同步读 store,会被跟踪
116
+ * env: store.env,
117
+ * })
118
+ *
119
+ * `store.username` 变化时,整个 effect 重跑,新值会被刷进 `formState`。
120
+ *
121
+ * prop 派生字段(initValues / config / ...)已经在上方用 getter 定义,
122
+ * 这里不再重复同步;因此 `props.initValues` 这类高频变化也不会再触发
123
+ * `extendState` 重跑(旧版的性能问题修复点)。
124
+ *
125
+ * 实现细节:
126
+ * - data 描述符:通过 `formState[key] = value` 走 reactive proxy 的 set,
127
+ * 触发依赖通知;与旧版「逐项赋值」语义完全等价。
128
+ * - accessor 描述符(`{ get stage() {...} }`)按原样写入 formState,调用方
129
+ * 可以自行控制读时求值;强制 `configurable: true` 以便下一次重跑可再 define。
130
+ */
131
+ watchEffect(async (onCleanup) => {
132
+ const { extendState } = props;
133
+ if (typeof extendState !== "function") return;
134
+ let stale = false;
135
+ onCleanup(() => {
136
+ stale = true;
137
+ });
138
+ let state = {};
139
+ try {
140
+ state = await extendState(formState) || {};
141
+ } catch (e) {
142
+ console.error("[MForm] extendState failed:", e);
143
+ return;
144
+ }
145
+ if (stale) return;
146
+ for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(state))) if ("value" in descriptor) formState[key] = state[key];
147
+ else {
148
+ descriptor.configurable = true;
149
+ Object.defineProperty(formState, key, descriptor);
92
150
  }
93
151
  });
94
152
  provide("mForm", formState);
@@ -3358,14 +3358,45 @@
3358
3358
  const lastValuesProcessed = (0, vue.ref)({});
3359
3359
  const fields = /* @__PURE__ */ new Map();
3360
3360
  const requestFuc = getConfig("request");
3361
+ /**
3362
+ * formState 实现说明:
3363
+ *
3364
+ * 1. 与 props 直接对应的字段(config / initValues / lastValues / isCompare / parentValues /
3365
+ * keyProp / popperClass)使用「访问器(getter)」定义,每次读取都会回到 `props.xxx`
3366
+ * 取最新值,不存在「props 变了但 formState 还没同步过来」的中间态。
3367
+ *
3368
+ * 2. `values` / `lastValuesProcessed` 是 ref,Vue 的 `reactive` 会自动解包,因此每次
3369
+ * 访问 `formState.values` / `formState.lastValuesProcessed` 也都是当前 ref 值。
3370
+ *
3371
+ * 3. `extendState` 注入的字段在下方的 `watchEffect` 中合并到 `formState`:
3372
+ * - data 描述符(普通字段)通过 `formState[key] = value` 写入,走 reactive proxy 的
3373
+ * set,触发依赖通知;`extendState` 同步段读到的响应式数据变化时会自动重跑,
3374
+ * 把最新值刷进 formState。
3375
+ * - accessor 描述符(`{ get stage() { return ... } }`)按原样写入,调用方可以控制
3376
+ * 读时求值,每次读取都会重新执行 getter。
3377
+ */
3361
3378
  const formState = (0, vue.reactive)({
3362
- keyProp: props.keyProp,
3363
- popperClass: props.popperClass,
3364
- config: props.config,
3365
- initValues: props.initValues,
3366
- isCompare: props.isCompare,
3367
- lastValues: props.lastValues,
3368
- parentValues: props.parentValues,
3379
+ get keyProp() {
3380
+ return props.keyProp;
3381
+ },
3382
+ get popperClass() {
3383
+ return props.popperClass;
3384
+ },
3385
+ get config() {
3386
+ return props.config;
3387
+ },
3388
+ get initValues() {
3389
+ return props.initValues;
3390
+ },
3391
+ get isCompare() {
3392
+ return props.isCompare;
3393
+ },
3394
+ get lastValues() {
3395
+ return props.lastValues;
3396
+ },
3397
+ get parentValues() {
3398
+ return props.parentValues;
3399
+ },
3369
3400
  values,
3370
3401
  lastValuesProcessed,
3371
3402
  $emit: emit,
@@ -3382,19 +3413,46 @@
3382
3413
  });
3383
3414
  }
3384
3415
  });
3385
- (0, vue.watchEffect)(async () => {
3386
- formState.initValues = props.initValues;
3387
- formState.lastValues = props.lastValues;
3388
- formState.isCompare = props.isCompare;
3389
- formState.config = props.config;
3390
- formState.keyProp = props.keyProp;
3391
- formState.popperClass = props.popperClass;
3392
- formState.parentValues = props.parentValues;
3393
- if (typeof props.extendState === "function") {
3394
- const state = await props.extendState(formState) || {};
3395
- Object.entries(state).forEach(([key, value]) => {
3396
- formState[key] = value;
3397
- });
3416
+ /**
3417
+ * `extendState` 的同步段(直到第一个 `await` 之前)所访问的任何响应式数据,
3418
+ * 都会被 `watchEffect` 自动跟踪。这样可以兼容历史用法 ——
3419
+ *
3420
+ * extendState: (formState) => ({
3421
+ * username: store.username, // 同步读 store,会被跟踪
3422
+ * env: store.env,
3423
+ * })
3424
+ *
3425
+ * `store.username` 变化时,整个 effect 重跑,新值会被刷进 `formState`。
3426
+ *
3427
+ * prop 派生字段(initValues / config / ...)已经在上方用 getter 定义,
3428
+ * 这里不再重复同步;因此 `props.initValues` 这类高频变化也不会再触发
3429
+ * `extendState` 重跑(旧版的性能问题修复点)。
3430
+ *
3431
+ * 实现细节:
3432
+ * - data 描述符:通过 `formState[key] = value` 走 reactive proxy 的 set,
3433
+ * 触发依赖通知;与旧版「逐项赋值」语义完全等价。
3434
+ * - accessor 描述符(`{ get stage() {...} }`)按原样写入 formState,调用方
3435
+ * 可以自行控制读时求值;强制 `configurable: true` 以便下一次重跑可再 define。
3436
+ */
3437
+ (0, vue.watchEffect)(async (onCleanup) => {
3438
+ const { extendState } = props;
3439
+ if (typeof extendState !== "function") return;
3440
+ let stale = false;
3441
+ onCleanup(() => {
3442
+ stale = true;
3443
+ });
3444
+ let state = {};
3445
+ try {
3446
+ state = await extendState(formState) || {};
3447
+ } catch (e) {
3448
+ console.error("[MForm] extendState failed:", e);
3449
+ return;
3450
+ }
3451
+ if (stale) return;
3452
+ for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(state))) if ("value" in descriptor) formState[key] = state[key];
3453
+ else {
3454
+ descriptor.configurable = true;
3455
+ Object.defineProperty(formState, key, descriptor);
3398
3456
  }
3399
3457
  });
3400
3458
  (0, vue.provide)("mForm", formState);
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.7.14-beta.3",
2
+ "version": "1.8.0-beta.1",
3
3
  "name": "@tmagic/form",
4
4
  "type": "module",
5
5
  "sideEffects": [
@@ -52,9 +52,9 @@
52
52
  "peerDependencies": {
53
53
  "vue": "^3.5.34",
54
54
  "typescript": "^6.0.3",
55
- "@tmagic/design": "1.7.14-beta.3",
56
- "@tmagic/utils": "1.7.14-beta.3",
57
- "@tmagic/form-schema": "1.7.14-beta.3"
55
+ "@tmagic/design": "1.8.0-beta.1",
56
+ "@tmagic/form-schema": "1.8.0-beta.1",
57
+ "@tmagic/utils": "1.8.0-beta.1"
58
58
  },
59
59
  "peerDependenciesMeta": {
60
60
  "typescript": {
package/src/Form.vue CHANGED
@@ -92,14 +92,45 @@ const fields = new Map<string, any>();
92
92
 
93
93
  const requestFuc = getConfig('request') as Function;
94
94
 
95
+ /**
96
+ * formState 实现说明:
97
+ *
98
+ * 1. 与 props 直接对应的字段(config / initValues / lastValues / isCompare / parentValues /
99
+ * keyProp / popperClass)使用「访问器(getter)」定义,每次读取都会回到 `props.xxx`
100
+ * 取最新值,不存在「props 变了但 formState 还没同步过来」的中间态。
101
+ *
102
+ * 2. `values` / `lastValuesProcessed` 是 ref,Vue 的 `reactive` 会自动解包,因此每次
103
+ * 访问 `formState.values` / `formState.lastValuesProcessed` 也都是当前 ref 值。
104
+ *
105
+ * 3. `extendState` 注入的字段在下方的 `watchEffect` 中合并到 `formState`:
106
+ * - data 描述符(普通字段)通过 `formState[key] = value` 写入,走 reactive proxy 的
107
+ * set,触发依赖通知;`extendState` 同步段读到的响应式数据变化时会自动重跑,
108
+ * 把最新值刷进 formState。
109
+ * - accessor 描述符(`{ get stage() { return ... } }`)按原样写入,调用方可以控制
110
+ * 读时求值,每次读取都会重新执行 getter。
111
+ */
95
112
  const formState: FormState = reactive<FormState>({
96
- keyProp: props.keyProp,
97
- popperClass: props.popperClass,
98
- config: props.config,
99
- initValues: props.initValues,
100
- isCompare: props.isCompare,
101
- lastValues: props.lastValues,
102
- parentValues: props.parentValues,
113
+ get keyProp() {
114
+ return props.keyProp;
115
+ },
116
+ get popperClass() {
117
+ return props.popperClass;
118
+ },
119
+ get config() {
120
+ return props.config;
121
+ },
122
+ get initValues() {
123
+ return props.initValues;
124
+ },
125
+ get isCompare() {
126
+ return props.isCompare;
127
+ },
128
+ get lastValues() {
129
+ return props.lastValues;
130
+ },
131
+ get parentValues() {
132
+ return props.parentValues;
133
+ },
103
134
  values,
104
135
  lastValuesProcessed,
105
136
  $emit: emit as (_event: string, ..._args: any[]) => void,
@@ -119,20 +150,52 @@ const formState: FormState = reactive<FormState>({
119
150
  },
120
151
  });
121
152
 
122
- watchEffect(async () => {
123
- formState.initValues = props.initValues;
124
- formState.lastValues = props.lastValues;
125
- formState.isCompare = props.isCompare;
126
- formState.config = props.config;
127
- formState.keyProp = props.keyProp;
128
- formState.popperClass = props.popperClass;
129
- formState.parentValues = props.parentValues;
130
-
131
- if (typeof props.extendState === 'function') {
132
- const state = (await props.extendState(formState)) || {};
133
- Object.entries(state).forEach(([key, value]) => {
134
- formState[key] = value;
135
- });
153
+ /**
154
+ * `extendState` 的同步段(直到第一个 `await` 之前)所访问的任何响应式数据,
155
+ * 都会被 `watchEffect` 自动跟踪。这样可以兼容历史用法 ——
156
+ *
157
+ * extendState: (formState) => ({
158
+ * username: store.username, // 同步读 store,会被跟踪
159
+ * env: store.env,
160
+ * })
161
+ *
162
+ * 当 `store.username` 变化时,整个 effect 重跑,新值会被刷进 `formState`。
163
+ *
164
+ * prop 派生字段(initValues / config / ...)已经在上方用 getter 定义,
165
+ * 这里不再重复同步;因此 `props.initValues` 这类高频变化也不会再触发
166
+ * `extendState` 重跑(旧版的性能问题修复点)。
167
+ *
168
+ * 实现细节:
169
+ * - data 描述符:通过 `formState[key] = value` 走 reactive proxy 的 set,
170
+ * 触发依赖通知;与旧版「逐项赋值」语义完全等价。
171
+ * - accessor 描述符(`{ get stage() {...} }`)按原样写入 formState,调用方
172
+ * 可以自行控制读时求值;强制 `configurable: true` 以便下一次重跑可再 define。
173
+ */
174
+ watchEffect(async (onCleanup) => {
175
+ const { extendState } = props;
176
+ if (typeof extendState !== 'function') return;
177
+
178
+ let stale = false;
179
+ onCleanup(() => {
180
+ stale = true;
181
+ });
182
+
183
+ let state: Record<string, any> = {};
184
+ try {
185
+ state = (await extendState(formState)) || {};
186
+ } catch (e) {
187
+ console.error('[MForm] extendState failed:', e);
188
+ return;
189
+ }
190
+ if (stale) return;
191
+
192
+ for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(state))) {
193
+ if ('value' in descriptor) {
194
+ (formState as any)[key] = (state as any)[key];
195
+ } else {
196
+ descriptor.configurable = true;
197
+ Object.defineProperty(formState, key, descriptor);
198
+ }
136
199
  }
137
200
  });
138
201