@flowgram.ai/form 0.1.0
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/dist/esm/index.js +1547 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/index.d.mts +655 -0
- package/dist/index.d.ts +655 -0
- package/dist/index.js +1607 -0
- package/dist/index.js.map +1 -0
- package/package.json +55 -0
|
@@ -0,0 +1,1547 @@
|
|
|
1
|
+
// src/react/field.tsx
|
|
2
|
+
import * as React2 from "react";
|
|
3
|
+
import { isFunction } from "lodash";
|
|
4
|
+
import { DisposableCollection, useRefresh } from "@flowgram.ai/utils";
|
|
5
|
+
import { useReadonlyReactiveState } from "@flowgram.ai/reactive";
|
|
6
|
+
|
|
7
|
+
// src/utils/object.ts
|
|
8
|
+
import { clone, toPath } from "lodash";
|
|
9
|
+
var isObject = (obj) => obj !== null && typeof obj === "object";
|
|
10
|
+
var isInteger = (obj) => String(Math.floor(Number(obj))) === obj;
|
|
11
|
+
function getIn(obj, key, def, p = 0) {
|
|
12
|
+
const path = toPath(key);
|
|
13
|
+
while (obj && p < path.length) {
|
|
14
|
+
obj = obj[path[p++]];
|
|
15
|
+
}
|
|
16
|
+
if (p !== path.length && !obj) {
|
|
17
|
+
return def;
|
|
18
|
+
}
|
|
19
|
+
return obj === void 0 ? def : obj;
|
|
20
|
+
}
|
|
21
|
+
function shallowSetIn(obj, path, value) {
|
|
22
|
+
let res = clone(obj);
|
|
23
|
+
let resVal = res;
|
|
24
|
+
let i = 0;
|
|
25
|
+
let pathArray = toPath(path);
|
|
26
|
+
for (; i < pathArray.length - 1; i++) {
|
|
27
|
+
const currentPath = pathArray[i];
|
|
28
|
+
let currentObj = getIn(obj, pathArray.slice(0, i + 1));
|
|
29
|
+
if (currentObj && (isObject(currentObj) || Array.isArray(currentObj))) {
|
|
30
|
+
resVal = resVal[currentPath] = clone(currentObj);
|
|
31
|
+
} else {
|
|
32
|
+
const nextPath = pathArray[i + 1];
|
|
33
|
+
resVal = resVal[currentPath] = isInteger(nextPath) && Number(nextPath) >= 0 ? [] : {};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if ((i === 0 ? obj : resVal)[pathArray[i]] === value) {
|
|
37
|
+
return obj;
|
|
38
|
+
}
|
|
39
|
+
if (value === void 0) {
|
|
40
|
+
delete resVal[pathArray[i]];
|
|
41
|
+
} else {
|
|
42
|
+
resVal[pathArray[i]] = value;
|
|
43
|
+
}
|
|
44
|
+
if (i === 0 && value === void 0) {
|
|
45
|
+
delete res[pathArray[i]];
|
|
46
|
+
}
|
|
47
|
+
return res;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// src/utils/dom.ts
|
|
51
|
+
function isReactChangeEvent(e) {
|
|
52
|
+
return typeof e === "object" && e !== null && "target" in e && typeof e.target === "object";
|
|
53
|
+
}
|
|
54
|
+
function isCheckBoxEvent(e) {
|
|
55
|
+
return typeof e === "object" && e !== null && "target" in e && typeof e.target === "object" && e.target.type === "checkbox";
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// src/utils/glob.ts
|
|
59
|
+
import { flatten, get, isArray, isObject as isObject2 } from "lodash";
|
|
60
|
+
var Glob;
|
|
61
|
+
((Glob2) => {
|
|
62
|
+
Glob2.DIVIDER = ".";
|
|
63
|
+
Glob2.ALL = "*";
|
|
64
|
+
function isMatch(pattern, path) {
|
|
65
|
+
const patternArr = pattern.split(Glob2.DIVIDER);
|
|
66
|
+
const pathArr = path.split(Glob2.DIVIDER);
|
|
67
|
+
if (patternArr.length !== pathArr.length) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
return patternArr.every((pattern2, index) => {
|
|
71
|
+
if (pattern2 === Glob2.ALL) {
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
return pattern2 === pathArr[index];
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
Glob2.isMatch = isMatch;
|
|
78
|
+
function isMatchOrParent(pattern, path) {
|
|
79
|
+
if (pattern === "") {
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
const patternArr = pattern.split(Glob2.DIVIDER);
|
|
83
|
+
const pathArr = path.split(Glob2.DIVIDER);
|
|
84
|
+
if (patternArr.length > pathArr.length) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
for (let i = 0; i < patternArr.length; i++) {
|
|
88
|
+
if (patternArr[i] !== Glob2.ALL && patternArr[i] !== pathArr[i]) {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
Glob2.isMatchOrParent = isMatchOrParent;
|
|
95
|
+
function getParentPathByPattern(pattern, path) {
|
|
96
|
+
const patternArr = pattern.split(Glob2.DIVIDER);
|
|
97
|
+
const pathArr = path.split(Glob2.DIVIDER);
|
|
98
|
+
return pathArr.slice(0, patternArr.length).join(Glob2.DIVIDER);
|
|
99
|
+
}
|
|
100
|
+
Glob2.getParentPathByPattern = getParentPathByPattern;
|
|
101
|
+
function concatPath(p1, ...pathArr) {
|
|
102
|
+
const p2 = pathArr.shift();
|
|
103
|
+
if (p2 === void 0) return p1.toString();
|
|
104
|
+
let resultPath = "";
|
|
105
|
+
if (p1 === "" && p2 === "") {
|
|
106
|
+
resultPath = "";
|
|
107
|
+
} else if (p1 !== "" && p2 === "") {
|
|
108
|
+
resultPath = p1.toString();
|
|
109
|
+
} else if (p1 === "" && p2 !== "") {
|
|
110
|
+
resultPath = p2.toString();
|
|
111
|
+
} else {
|
|
112
|
+
resultPath = `${p1}${Glob2.DIVIDER}${p2}`;
|
|
113
|
+
}
|
|
114
|
+
if (pathArr.length > 0) {
|
|
115
|
+
return concatPath(resultPath, ...pathArr);
|
|
116
|
+
}
|
|
117
|
+
return resultPath;
|
|
118
|
+
}
|
|
119
|
+
function getSubPaths(paths, obj) {
|
|
120
|
+
if (!obj || typeof obj !== "object") {
|
|
121
|
+
return [];
|
|
122
|
+
}
|
|
123
|
+
return flatten(
|
|
124
|
+
paths.map((path) => {
|
|
125
|
+
const value = path === "" ? obj : get(obj, path);
|
|
126
|
+
if (isArray(value)) {
|
|
127
|
+
return value.map((_, index) => concatPath(path, index));
|
|
128
|
+
} else if (isObject2(value)) {
|
|
129
|
+
return Object.keys(value).map((key) => concatPath(path, key));
|
|
130
|
+
}
|
|
131
|
+
return [];
|
|
132
|
+
})
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
Glob2.getSubPaths = getSubPaths;
|
|
136
|
+
function splitPattern(pattern) {
|
|
137
|
+
const parts = pattern.split(Glob2.DIVIDER);
|
|
138
|
+
const res = [];
|
|
139
|
+
let i = 0;
|
|
140
|
+
let curPath = [];
|
|
141
|
+
while (i < parts.length) {
|
|
142
|
+
if (parts[i] === Glob2.ALL) {
|
|
143
|
+
if (curPath.length) {
|
|
144
|
+
res.push(curPath.join(Glob2.DIVIDER));
|
|
145
|
+
}
|
|
146
|
+
res.push(Glob2.ALL);
|
|
147
|
+
curPath = [];
|
|
148
|
+
} else {
|
|
149
|
+
curPath.push(parts[i]);
|
|
150
|
+
}
|
|
151
|
+
i += 1;
|
|
152
|
+
}
|
|
153
|
+
if (curPath.length) {
|
|
154
|
+
res.push(curPath.join(Glob2.DIVIDER));
|
|
155
|
+
}
|
|
156
|
+
return res;
|
|
157
|
+
}
|
|
158
|
+
Glob2.splitPattern = splitPattern;
|
|
159
|
+
function findMatchPaths2(obj, pattern) {
|
|
160
|
+
if (!obj || !pattern) {
|
|
161
|
+
return [];
|
|
162
|
+
}
|
|
163
|
+
const nextPaths = pattern.split(Glob2.DIVIDER);
|
|
164
|
+
let curKey = nextPaths.shift();
|
|
165
|
+
let curPaths = [];
|
|
166
|
+
let curValue = obj;
|
|
167
|
+
while (curKey) {
|
|
168
|
+
let isObject3 = typeof curValue === "object";
|
|
169
|
+
if (!isObject3) return [];
|
|
170
|
+
if (curKey === Glob2.ALL) {
|
|
171
|
+
const parentPath = curPaths.join(Glob2.DIVIDER);
|
|
172
|
+
return flatten(
|
|
173
|
+
Object.keys(curValue).map((key) => {
|
|
174
|
+
if (nextPaths.length === 0) {
|
|
175
|
+
return concatPath(parentPath, key);
|
|
176
|
+
}
|
|
177
|
+
return findMatchPaths2(curValue[key], `${nextPaths.join(Glob2.DIVIDER)}`).map(
|
|
178
|
+
(p) => concatPath(parentPath, key, p)
|
|
179
|
+
);
|
|
180
|
+
})
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
if (!(curKey in curValue)) return [];
|
|
184
|
+
curValue = curValue[curKey];
|
|
185
|
+
curPaths.push(curKey);
|
|
186
|
+
curKey = nextPaths.shift();
|
|
187
|
+
}
|
|
188
|
+
return [pattern];
|
|
189
|
+
}
|
|
190
|
+
Glob2.findMatchPaths = findMatchPaths2;
|
|
191
|
+
})(Glob || (Glob = {}));
|
|
192
|
+
|
|
193
|
+
// src/types/validate.ts
|
|
194
|
+
function isFieldWarning(f) {
|
|
195
|
+
if (f.level === "warning" /* Warning */) {
|
|
196
|
+
return true;
|
|
197
|
+
}
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
var ValidateTrigger = /* @__PURE__ */ ((ValidateTrigger2) => {
|
|
201
|
+
ValidateTrigger2["onChange"] = "onChange";
|
|
202
|
+
ValidateTrigger2["onBlur"] = "onBlur";
|
|
203
|
+
return ValidateTrigger2;
|
|
204
|
+
})(ValidateTrigger || {});
|
|
205
|
+
|
|
206
|
+
// src/core/utils.ts
|
|
207
|
+
import { isEmpty, isEqual } from "lodash";
|
|
208
|
+
|
|
209
|
+
// src/core/path.ts
|
|
210
|
+
import { toPath as toPath2 } from "lodash";
|
|
211
|
+
var Path = class _Path {
|
|
212
|
+
constructor(path) {
|
|
213
|
+
this._path = [];
|
|
214
|
+
this._path = toPath2(path);
|
|
215
|
+
}
|
|
216
|
+
get parent() {
|
|
217
|
+
if (this._path.length < 2) {
|
|
218
|
+
return void 0;
|
|
219
|
+
}
|
|
220
|
+
return new _Path(this._path.slice(0, -1));
|
|
221
|
+
}
|
|
222
|
+
toString() {
|
|
223
|
+
return this._path.join(".");
|
|
224
|
+
}
|
|
225
|
+
get value() {
|
|
226
|
+
return this._path;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* 仅计直系child
|
|
230
|
+
* @param path
|
|
231
|
+
*/
|
|
232
|
+
isChild(path) {
|
|
233
|
+
const target = new _Path(path).value;
|
|
234
|
+
const self = this.value;
|
|
235
|
+
if (target.length - self.length !== 1) {
|
|
236
|
+
return false;
|
|
237
|
+
}
|
|
238
|
+
for (let i = 0; i < self.length; i++) {
|
|
239
|
+
if (target[i] !== self[i]) {
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
return true;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* 比较两个数组path大小
|
|
247
|
+
* 返回小于0则path1<path2, 大于0 则path1>path2, 等于0则相等
|
|
248
|
+
* @param path1
|
|
249
|
+
* @param path2
|
|
250
|
+
*/
|
|
251
|
+
static compareArrayPath(path1, path2) {
|
|
252
|
+
let i = 0;
|
|
253
|
+
while (path1.value[i] && path2.value[i]) {
|
|
254
|
+
const index1 = parseInt(path1.value[i]);
|
|
255
|
+
const index2 = parseInt(path2.value[i]);
|
|
256
|
+
if (!isNaN(index1) && !isNaN(index2)) {
|
|
257
|
+
return index1 - index2;
|
|
258
|
+
} else if (path1.value[i] !== path2.value[i]) {
|
|
259
|
+
throw new Error(
|
|
260
|
+
`[Form] Path.compareArrayPath invalid input Error: two path should refers to the same array, but got path1: ${path1.toString()}, path2: ${path2.toString()}`
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
i++;
|
|
264
|
+
}
|
|
265
|
+
throw new Error(
|
|
266
|
+
`[Form] Path.compareArrayPath invalid input Error: got path1: ${path1.toString()}, path2: ${path2.toString()}`
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
isChildOrGrandChild(path) {
|
|
270
|
+
const target = new _Path(path).value;
|
|
271
|
+
const self = this.value;
|
|
272
|
+
if (target.length - self.length < 1) {
|
|
273
|
+
return false;
|
|
274
|
+
}
|
|
275
|
+
for (let i = 0; i < self.length; i++) {
|
|
276
|
+
if (target[i] !== self[i]) {
|
|
277
|
+
return false;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return true;
|
|
281
|
+
}
|
|
282
|
+
getArrayIndex(parent) {
|
|
283
|
+
return parseInt(this._path[parent.value.length]);
|
|
284
|
+
}
|
|
285
|
+
concat(name) {
|
|
286
|
+
if (typeof name === "string" || typeof name === "number") {
|
|
287
|
+
return new _Path(this._path.concat(new _Path(name.toString())._path));
|
|
288
|
+
}
|
|
289
|
+
throw new Error(
|
|
290
|
+
`[Form] Error in Path.concat: invalid param type, require number or string, but got ${typeof name}`
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
replaceParent(parent, newParent) {
|
|
294
|
+
if (parent.value.length > this.value.length) {
|
|
295
|
+
throw new Error(
|
|
296
|
+
`[Form] Error in Path.getChildSuffixByParent: invalid parent param: ${parent}, parent length should not greater than current length.`
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
const rest = [];
|
|
300
|
+
for (let i = 0; i < this.value.length; i++) {
|
|
301
|
+
if (i < parent.value.length && parent.value[i] !== this.value[i]) {
|
|
302
|
+
throw new Error(
|
|
303
|
+
`[Form] Error in Path.getChildSuffixByParent: invalid parent param: ${parent}`
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
if (i >= parent.value.length) {
|
|
307
|
+
rest.push(this.value[i]);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return new _Path(newParent.value.concat(rest));
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
// src/core/utils.ts
|
|
315
|
+
function updateFeedbacksName(feedbacks, name) {
|
|
316
|
+
return feedbacks.map((f) => ({
|
|
317
|
+
...f,
|
|
318
|
+
name
|
|
319
|
+
}));
|
|
320
|
+
}
|
|
321
|
+
function mergeFeedbacks(origin, source) {
|
|
322
|
+
if (!source) {
|
|
323
|
+
return origin;
|
|
324
|
+
}
|
|
325
|
+
if (!origin) {
|
|
326
|
+
return { ...source };
|
|
327
|
+
}
|
|
328
|
+
const changed = Object.keys(source).some(
|
|
329
|
+
(sourceKey) => !isEqual(origin[sourceKey], source[sourceKey])
|
|
330
|
+
);
|
|
331
|
+
if (changed) {
|
|
332
|
+
return {
|
|
333
|
+
...origin,
|
|
334
|
+
...source
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
return origin;
|
|
338
|
+
}
|
|
339
|
+
function clearFeedbacks(name, origin) {
|
|
340
|
+
if (!origin) {
|
|
341
|
+
return origin;
|
|
342
|
+
}
|
|
343
|
+
if (name in origin) {
|
|
344
|
+
delete origin[name];
|
|
345
|
+
}
|
|
346
|
+
return origin;
|
|
347
|
+
}
|
|
348
|
+
function shouldValidate(currentTrigger, formTrigger) {
|
|
349
|
+
return currentTrigger === formTrigger;
|
|
350
|
+
}
|
|
351
|
+
function getValidByErrors(errors) {
|
|
352
|
+
return errors ? Object.keys(errors).every((name) => isEmpty(errors[name])) : true;
|
|
353
|
+
}
|
|
354
|
+
var FieldEventUtils;
|
|
355
|
+
((FieldEventUtils2) => {
|
|
356
|
+
function shouldTriggerFieldChangeEvent(payload, fieldName) {
|
|
357
|
+
const { name: changedName, options } = payload;
|
|
358
|
+
if (Glob.isMatchOrParent(fieldName, changedName)) {
|
|
359
|
+
return true;
|
|
360
|
+
}
|
|
361
|
+
if (new Path(changedName).isChildOrGrandChild(fieldName)) {
|
|
362
|
+
if (options?.action === "array-append") {
|
|
363
|
+
return !new Path(changedName).isChildOrGrandChild(fieldName);
|
|
364
|
+
} else if (options?.action === "array-splice" && options?.indexes?.length) {
|
|
365
|
+
return Path.compareArrayPath(
|
|
366
|
+
new Path(fieldName),
|
|
367
|
+
new Path(changedName).concat(options.indexes[0])
|
|
368
|
+
) >= 0;
|
|
369
|
+
}
|
|
370
|
+
return true;
|
|
371
|
+
}
|
|
372
|
+
return false;
|
|
373
|
+
}
|
|
374
|
+
FieldEventUtils2.shouldTriggerFieldChangeEvent = shouldTriggerFieldChangeEvent;
|
|
375
|
+
function shouldTriggerFieldValidateWhenChange(payload, fieldName) {
|
|
376
|
+
const { name: changedName, options } = payload;
|
|
377
|
+
if (options?.action === "array-splice") {
|
|
378
|
+
return fieldName === changedName;
|
|
379
|
+
}
|
|
380
|
+
return FieldEventUtils2.shouldTriggerFieldChangeEvent(payload, fieldName);
|
|
381
|
+
}
|
|
382
|
+
FieldEventUtils2.shouldTriggerFieldValidateWhenChange = shouldTriggerFieldValidateWhenChange;
|
|
383
|
+
})(FieldEventUtils || (FieldEventUtils = {}));
|
|
384
|
+
|
|
385
|
+
// src/core/to-field.ts
|
|
386
|
+
function toField(model) {
|
|
387
|
+
const res = {
|
|
388
|
+
get name() {
|
|
389
|
+
return model.name;
|
|
390
|
+
},
|
|
391
|
+
get value() {
|
|
392
|
+
return model.value;
|
|
393
|
+
},
|
|
394
|
+
onChange: (e) => {
|
|
395
|
+
if (isReactChangeEvent(e)) {
|
|
396
|
+
model.value = isCheckBoxEvent(e) ? e.target.checked : e.target.value;
|
|
397
|
+
} else {
|
|
398
|
+
model.value = e;
|
|
399
|
+
}
|
|
400
|
+
},
|
|
401
|
+
onBlur() {
|
|
402
|
+
if (shouldValidate("onBlur" /* onBlur */, model.form.validationTrigger)) {
|
|
403
|
+
model.validate();
|
|
404
|
+
}
|
|
405
|
+
},
|
|
406
|
+
onFocus() {
|
|
407
|
+
model.state.isTouched = true;
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
Object.defineProperty(res, "key", {
|
|
411
|
+
enumerable: false,
|
|
412
|
+
get() {
|
|
413
|
+
return model.id;
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
Object.defineProperty(res, "_fieldModel", {
|
|
417
|
+
enumerable: false,
|
|
418
|
+
get() {
|
|
419
|
+
return model;
|
|
420
|
+
}
|
|
421
|
+
});
|
|
422
|
+
return res;
|
|
423
|
+
}
|
|
424
|
+
function toFieldState(modelState) {
|
|
425
|
+
return {
|
|
426
|
+
get isTouched() {
|
|
427
|
+
return modelState.isTouched;
|
|
428
|
+
},
|
|
429
|
+
get invalid() {
|
|
430
|
+
return modelState.invalid;
|
|
431
|
+
},
|
|
432
|
+
get isDirty() {
|
|
433
|
+
return modelState.isDirty;
|
|
434
|
+
},
|
|
435
|
+
get isValidating() {
|
|
436
|
+
return modelState.isValidating;
|
|
437
|
+
},
|
|
438
|
+
get errors() {
|
|
439
|
+
if (modelState.errors) {
|
|
440
|
+
return Object.values(modelState.errors).reduce((acc, arr) => acc.concat(arr), []);
|
|
441
|
+
}
|
|
442
|
+
return;
|
|
443
|
+
},
|
|
444
|
+
get warnings() {
|
|
445
|
+
if (modelState.warnings) {
|
|
446
|
+
return Object.values(modelState.warnings).reduce((acc, arr) => acc.concat(arr), []);
|
|
447
|
+
}
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// src/core/to-form.ts
|
|
454
|
+
function toForm(model) {
|
|
455
|
+
const res = {
|
|
456
|
+
initialValues: model.initialValues,
|
|
457
|
+
get values() {
|
|
458
|
+
return model.values;
|
|
459
|
+
},
|
|
460
|
+
state: toFormState(model.state),
|
|
461
|
+
getValueIn: (name) => model.getValueIn(name),
|
|
462
|
+
setValueIn: (name, value) => model.setValueIn(name, value)
|
|
463
|
+
};
|
|
464
|
+
Object.defineProperty(res, "_formModel", {
|
|
465
|
+
enumerable: false,
|
|
466
|
+
get() {
|
|
467
|
+
return model;
|
|
468
|
+
}
|
|
469
|
+
});
|
|
470
|
+
return res;
|
|
471
|
+
}
|
|
472
|
+
function toFormState(modelState) {
|
|
473
|
+
return {
|
|
474
|
+
get isTouched() {
|
|
475
|
+
return modelState.isTouched;
|
|
476
|
+
},
|
|
477
|
+
get invalid() {
|
|
478
|
+
return modelState.invalid;
|
|
479
|
+
},
|
|
480
|
+
get isDirty() {
|
|
481
|
+
return modelState.isDirty;
|
|
482
|
+
},
|
|
483
|
+
get isValidating() {
|
|
484
|
+
return modelState.isValidating;
|
|
485
|
+
},
|
|
486
|
+
// get dirtyFields() {
|
|
487
|
+
// return modelState.dirtyFields;
|
|
488
|
+
// },
|
|
489
|
+
// get isLoading() {
|
|
490
|
+
// return modelState.isLoading;
|
|
491
|
+
// },
|
|
492
|
+
// get touchedFields() {
|
|
493
|
+
// return modelState.touchedFields;
|
|
494
|
+
// },
|
|
495
|
+
get errors() {
|
|
496
|
+
return modelState.errors;
|
|
497
|
+
},
|
|
498
|
+
get warnings() {
|
|
499
|
+
return modelState.warnings;
|
|
500
|
+
}
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// src/react/utils.ts
|
|
505
|
+
import { useContext } from "react";
|
|
506
|
+
|
|
507
|
+
// src/react/context.ts
|
|
508
|
+
import React from "react";
|
|
509
|
+
var FormModelContext = React.createContext({});
|
|
510
|
+
var FieldModelContext = React.createContext({});
|
|
511
|
+
|
|
512
|
+
// src/react/utils.ts
|
|
513
|
+
function useFormModel() {
|
|
514
|
+
return useContext(FormModelContext);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// src/react/field.tsx
|
|
518
|
+
function Field({
|
|
519
|
+
name,
|
|
520
|
+
defaultValue,
|
|
521
|
+
render,
|
|
522
|
+
children,
|
|
523
|
+
deps
|
|
524
|
+
}) {
|
|
525
|
+
const formModel = useFormModel();
|
|
526
|
+
const fieldModel = formModel.getField(name) || formModel.createField(name);
|
|
527
|
+
const field = React2.useMemo(() => toField(fieldModel), [fieldModel]);
|
|
528
|
+
const fieldModelState = useReadonlyReactiveState(fieldModel.reactiveState);
|
|
529
|
+
const formModelState = useReadonlyReactiveState(formModel.reactiveState);
|
|
530
|
+
const fieldState = React2.useMemo(() => toFieldState(fieldModelState), [fieldModelState]);
|
|
531
|
+
const formState = toFormState(formModelState);
|
|
532
|
+
const refresh = useRefresh();
|
|
533
|
+
React2.useEffect(() => {
|
|
534
|
+
fieldModel.renderCount = fieldModel.renderCount + 1;
|
|
535
|
+
if (!formModel.getValueIn(name) !== void 0 && defaultValue !== void 0) {
|
|
536
|
+
formModel.setInitValueIn(name, defaultValue);
|
|
537
|
+
refresh();
|
|
538
|
+
}
|
|
539
|
+
const disposableCollection = new DisposableCollection();
|
|
540
|
+
disposableCollection.push(
|
|
541
|
+
fieldModel.onValueChange(() => {
|
|
542
|
+
refresh();
|
|
543
|
+
})
|
|
544
|
+
);
|
|
545
|
+
if (deps) {
|
|
546
|
+
deps.forEach((dep) => {
|
|
547
|
+
const disposable = formModel.getField(dep)?.onValueChange(() => {
|
|
548
|
+
refresh();
|
|
549
|
+
});
|
|
550
|
+
if (disposable) {
|
|
551
|
+
disposableCollection.push(disposable);
|
|
552
|
+
}
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
return () => {
|
|
556
|
+
disposableCollection.dispose();
|
|
557
|
+
if (fieldModel.renderCount > 1) {
|
|
558
|
+
fieldModel.renderCount = fieldModel.renderCount - 1;
|
|
559
|
+
} else {
|
|
560
|
+
fieldModel.dispose();
|
|
561
|
+
}
|
|
562
|
+
};
|
|
563
|
+
}, [fieldModel]);
|
|
564
|
+
const renderInner = () => {
|
|
565
|
+
if (render) {
|
|
566
|
+
return render({ field, fieldState, formState });
|
|
567
|
+
}
|
|
568
|
+
if (isFunction(children)) {
|
|
569
|
+
return children({ field, fieldState, formState });
|
|
570
|
+
}
|
|
571
|
+
return React2.cloneElement(children, { ...field });
|
|
572
|
+
};
|
|
573
|
+
return /* @__PURE__ */ React2.createElement(FieldModelContext.Provider, { value: fieldModel }, renderInner());
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
// src/react/form.tsx
|
|
577
|
+
import React3, { Children, useEffect as useEffect2, useMemo as useMemo2 } from "react";
|
|
578
|
+
import { isFunction as isFunction2 } from "lodash";
|
|
579
|
+
|
|
580
|
+
// src/core/to-field-array.ts
|
|
581
|
+
function toFieldArray(model) {
|
|
582
|
+
const res = {
|
|
583
|
+
get key() {
|
|
584
|
+
return model.id;
|
|
585
|
+
},
|
|
586
|
+
get name() {
|
|
587
|
+
return model.path.toString();
|
|
588
|
+
},
|
|
589
|
+
get value() {
|
|
590
|
+
return model.value;
|
|
591
|
+
},
|
|
592
|
+
onChange: (value) => {
|
|
593
|
+
model.value = value;
|
|
594
|
+
},
|
|
595
|
+
map: (cb) => model.map((f, index) => cb(toField(f), index)),
|
|
596
|
+
append: (value) => toField(model.append(value)),
|
|
597
|
+
delete: (index) => model.delete(index),
|
|
598
|
+
swap: (from, to) => model.swap(from, to),
|
|
599
|
+
move: (from, to) => model.move(from, to)
|
|
600
|
+
};
|
|
601
|
+
Object.defineProperty(res, "_fieldModel", {
|
|
602
|
+
enumerable: false,
|
|
603
|
+
get() {
|
|
604
|
+
return model;
|
|
605
|
+
}
|
|
606
|
+
});
|
|
607
|
+
return res;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
// src/core/form-model.ts
|
|
611
|
+
import { cloneDeep, flatten as flatten2, get as get4 } from "lodash";
|
|
612
|
+
import { Emitter as Emitter3 } from "@flowgram.ai/utils";
|
|
613
|
+
import { ReactiveState as ReactiveState2 } from "@flowgram.ai/reactive";
|
|
614
|
+
|
|
615
|
+
// src/utils/validate.ts
|
|
616
|
+
function toFeedback(result, name) {
|
|
617
|
+
if (typeof result === "string") {
|
|
618
|
+
return {
|
|
619
|
+
name,
|
|
620
|
+
message: result,
|
|
621
|
+
level: "error" /* Error */
|
|
622
|
+
};
|
|
623
|
+
} else if (result?.message) {
|
|
624
|
+
return {
|
|
625
|
+
...result,
|
|
626
|
+
name
|
|
627
|
+
};
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
function feedbackToFieldErrorsOrWarnings(name, feedback) {
|
|
631
|
+
return {
|
|
632
|
+
[name]: feedback ? [feedback] : []
|
|
633
|
+
};
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
// src/constants.ts
|
|
637
|
+
var DEFAULT_FIELD_STATE = {
|
|
638
|
+
invalid: false,
|
|
639
|
+
isDirty: false,
|
|
640
|
+
isTouched: false,
|
|
641
|
+
isValidating: false
|
|
642
|
+
};
|
|
643
|
+
var DEFAULT_FORM_STATE = {
|
|
644
|
+
invalid: false,
|
|
645
|
+
isDirty: false,
|
|
646
|
+
isTouched: false,
|
|
647
|
+
isValidating: false
|
|
648
|
+
};
|
|
649
|
+
function createFormModelState(initialState) {
|
|
650
|
+
if (!initialState) {
|
|
651
|
+
return { ...DEFAULT_FORM_STATE };
|
|
652
|
+
}
|
|
653
|
+
return { ...DEFAULT_FORM_STATE, ...initialState };
|
|
654
|
+
}
|
|
655
|
+
function createFieldModelState(initialState) {
|
|
656
|
+
if (!initialState) {
|
|
657
|
+
return { ...DEFAULT_FIELD_STATE };
|
|
658
|
+
}
|
|
659
|
+
return { ...DEFAULT_FIELD_STATE, ...initialState };
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
// src/core/store.ts
|
|
663
|
+
import { get as get2 } from "lodash";
|
|
664
|
+
var Store = class {
|
|
665
|
+
get values() {
|
|
666
|
+
return this._values;
|
|
667
|
+
}
|
|
668
|
+
setInitialValues(values) {
|
|
669
|
+
this._values = values;
|
|
670
|
+
}
|
|
671
|
+
setIn(path, value) {
|
|
672
|
+
this._values = shallowSetIn(this._values || {}, path.toString(), value);
|
|
673
|
+
}
|
|
674
|
+
getIn(path) {
|
|
675
|
+
return get2(this._values, path.value);
|
|
676
|
+
}
|
|
677
|
+
dispose() {
|
|
678
|
+
}
|
|
679
|
+
};
|
|
680
|
+
|
|
681
|
+
// src/core/field-model.ts
|
|
682
|
+
import { nanoid } from "nanoid";
|
|
683
|
+
import { get as get3, groupBy, some } from "lodash";
|
|
684
|
+
import { DisposableCollection as DisposableCollection2, Emitter } from "@flowgram.ai/utils";
|
|
685
|
+
import { ReactiveState } from "@flowgram.ai/reactive";
|
|
686
|
+
var FieldModel = class {
|
|
687
|
+
constructor(path, form) {
|
|
688
|
+
this.onValueChangeEmitter = new Emitter();
|
|
689
|
+
this.onValueChange = this.onValueChangeEmitter.event;
|
|
690
|
+
this.toDispose = new DisposableCollection2();
|
|
691
|
+
this._state = new ReactiveState(
|
|
692
|
+
createFieldModelState()
|
|
693
|
+
);
|
|
694
|
+
this._renderCount = 0;
|
|
695
|
+
this._mount = false;
|
|
696
|
+
this._path = path;
|
|
697
|
+
this.form = form;
|
|
698
|
+
this.id = nanoid();
|
|
699
|
+
const changeDisposable = this.form.onFormValuesChange((payload) => {
|
|
700
|
+
const { values, prevValues } = payload;
|
|
701
|
+
if (FieldEventUtils.shouldTriggerFieldChangeEvent(payload, this.name)) {
|
|
702
|
+
this.onValueChangeEmitter.fire({
|
|
703
|
+
value: get3(values, this.name),
|
|
704
|
+
prevValue: get3(prevValues, this.name),
|
|
705
|
+
formValues: values,
|
|
706
|
+
prevFormValues: prevValues
|
|
707
|
+
});
|
|
708
|
+
if (shouldValidate("onChange" /* onChange */, this.form.validationTrigger) && FieldEventUtils.shouldTriggerFieldValidateWhenChange(payload, this.name)) {
|
|
709
|
+
this.validate();
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
});
|
|
713
|
+
this.toDispose.push(changeDisposable);
|
|
714
|
+
this.toDispose.push(this.onValueChangeEmitter);
|
|
715
|
+
this.initState();
|
|
716
|
+
}
|
|
717
|
+
get renderCount() {
|
|
718
|
+
return this._renderCount;
|
|
719
|
+
}
|
|
720
|
+
set renderCount(n) {
|
|
721
|
+
this._renderCount = n;
|
|
722
|
+
}
|
|
723
|
+
initState() {
|
|
724
|
+
const initialErrors = get3(this.form.state.errors, this.name);
|
|
725
|
+
const initialWarnings = get3(this.form.state.warnings, this.name);
|
|
726
|
+
if (initialErrors) {
|
|
727
|
+
this.state.errors = {
|
|
728
|
+
[this.name]: initialErrors
|
|
729
|
+
};
|
|
730
|
+
}
|
|
731
|
+
if (initialWarnings) {
|
|
732
|
+
this.state.warnings = {
|
|
733
|
+
[this.name]: initialWarnings
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
get path() {
|
|
738
|
+
return this._path;
|
|
739
|
+
}
|
|
740
|
+
get name() {
|
|
741
|
+
return this._path.toString();
|
|
742
|
+
}
|
|
743
|
+
set name(name) {
|
|
744
|
+
this._path = new Path(name);
|
|
745
|
+
}
|
|
746
|
+
get ref() {
|
|
747
|
+
return this._ref;
|
|
748
|
+
}
|
|
749
|
+
set ref(ref) {
|
|
750
|
+
this._ref = ref;
|
|
751
|
+
}
|
|
752
|
+
get state() {
|
|
753
|
+
return this._state.value;
|
|
754
|
+
}
|
|
755
|
+
get reactiveState() {
|
|
756
|
+
return this._state;
|
|
757
|
+
}
|
|
758
|
+
get value() {
|
|
759
|
+
return this.form.getValueIn(this.name);
|
|
760
|
+
}
|
|
761
|
+
set value(value) {
|
|
762
|
+
this.form.setValueIn(this.name, value);
|
|
763
|
+
if (!this.state.isTouched) {
|
|
764
|
+
this.state.isTouched = true;
|
|
765
|
+
this.bubbleState();
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
updateNameForLeafState(newName) {
|
|
769
|
+
const { errors, warnings } = this.state;
|
|
770
|
+
const nameInErrors = errors ? Object.keys(errors)?.[0] : void 0;
|
|
771
|
+
if (nameInErrors && errors?.[nameInErrors] && nameInErrors !== newName) {
|
|
772
|
+
this.state.errors = {
|
|
773
|
+
[newName]: errors?.[nameInErrors] ? updateFeedbacksName(errors?.[nameInErrors], newName) : errors?.[nameInErrors]
|
|
774
|
+
};
|
|
775
|
+
}
|
|
776
|
+
const nameInWarnings = warnings ? Object.keys(warnings)?.[0] : void 0;
|
|
777
|
+
if (nameInWarnings && warnings?.[nameInWarnings] && nameInWarnings !== newName) {
|
|
778
|
+
this.state.warnings = {
|
|
779
|
+
[newName]: warnings?.[nameInWarnings] ? updateFeedbacksName(warnings?.[nameInWarnings], newName) : warnings?.[nameInWarnings]
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
// recursiveUpdateName(name: FieldName) {
|
|
784
|
+
// if (this.children?.length) {
|
|
785
|
+
// this.children.forEach(c => {
|
|
786
|
+
// c.recursiveUpdateName(c.path.replaceParent(this.path, new Path(name)).toString());
|
|
787
|
+
// });
|
|
788
|
+
// } else {
|
|
789
|
+
// this.updateNameForLeafState(name);
|
|
790
|
+
// this.bubbleState();
|
|
791
|
+
// }
|
|
792
|
+
// this.name = name;
|
|
793
|
+
// }
|
|
794
|
+
/**
|
|
795
|
+
* @deprecated
|
|
796
|
+
* @param validate
|
|
797
|
+
* @param from
|
|
798
|
+
*/
|
|
799
|
+
updateValidate(validate, from) {
|
|
800
|
+
if (from === "ui") {
|
|
801
|
+
if (!this.originalValidate) {
|
|
802
|
+
this.originalValidate = validate;
|
|
803
|
+
}
|
|
804
|
+
} else {
|
|
805
|
+
this.originalValidate = validate;
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
bubbleState() {
|
|
809
|
+
const { errors, warnings } = this.state;
|
|
810
|
+
if (this.parent) {
|
|
811
|
+
this.parent.state.isTouched = some(
|
|
812
|
+
this.parent.children.map((c) => c.state.isTouched),
|
|
813
|
+
Boolean
|
|
814
|
+
);
|
|
815
|
+
this.parent.state.invalid = some(
|
|
816
|
+
this.parent.children.map((c) => c.state.invalid),
|
|
817
|
+
Boolean
|
|
818
|
+
);
|
|
819
|
+
this.parent.state.isDirty = some(
|
|
820
|
+
this.parent.children.map((c) => c.state.isDirty),
|
|
821
|
+
Boolean
|
|
822
|
+
);
|
|
823
|
+
this.parent.state.isValidating = some(
|
|
824
|
+
this.parent.children.map((c) => c.state.isValidating),
|
|
825
|
+
Boolean
|
|
826
|
+
);
|
|
827
|
+
this.parent.state.errors = errors ? mergeFeedbacks(this.parent.state.errors, errors) : clearFeedbacks(this.name, this.parent.state.errors);
|
|
828
|
+
this.parent.state.warnings = warnings ? mergeFeedbacks(this.parent.state.warnings, warnings) : clearFeedbacks(this.name, this.parent.state.warnings);
|
|
829
|
+
this.parent.bubbleState();
|
|
830
|
+
return;
|
|
831
|
+
}
|
|
832
|
+
this.form.state.isTouched = some(
|
|
833
|
+
this.form.fields.map((f) => f.state.isTouched),
|
|
834
|
+
Boolean
|
|
835
|
+
);
|
|
836
|
+
this.form.state.invalid = some(
|
|
837
|
+
this.form.fields.map((f) => f.state.invalid),
|
|
838
|
+
Boolean
|
|
839
|
+
);
|
|
840
|
+
this.form.state.isDirty = some(
|
|
841
|
+
this.form.fields.map((f) => f.state.isDirty),
|
|
842
|
+
Boolean
|
|
843
|
+
);
|
|
844
|
+
this.form.state.isValidating = some(
|
|
845
|
+
this.form.fields.map((f) => f.state.isValidating),
|
|
846
|
+
Boolean
|
|
847
|
+
);
|
|
848
|
+
this.form.state.errors = errors ? mergeFeedbacks(this.form.state.errors, errors) : clearFeedbacks(this.name, this.form.state.errors);
|
|
849
|
+
this.form.state.warnings = warnings ? mergeFeedbacks(this.form.state.warnings, warnings) : clearFeedbacks(this.name, this.form.state.warnings);
|
|
850
|
+
}
|
|
851
|
+
clearState() {
|
|
852
|
+
this.state.errors = DEFAULT_FIELD_STATE.errors;
|
|
853
|
+
this.state.warnings = DEFAULT_FIELD_STATE.warnings;
|
|
854
|
+
this.state.isTouched = DEFAULT_FIELD_STATE.isTouched;
|
|
855
|
+
this.state.isDirty = DEFAULT_FIELD_STATE.isDirty;
|
|
856
|
+
this.bubbleState();
|
|
857
|
+
}
|
|
858
|
+
get children() {
|
|
859
|
+
const res = [];
|
|
860
|
+
this.form.fieldMap.forEach((field, path) => {
|
|
861
|
+
if (this.path.isChild(path)) {
|
|
862
|
+
res.push(field);
|
|
863
|
+
}
|
|
864
|
+
});
|
|
865
|
+
return res;
|
|
866
|
+
}
|
|
867
|
+
get parent() {
|
|
868
|
+
const parentPath = this.path.parent;
|
|
869
|
+
if (!parentPath) {
|
|
870
|
+
return void 0;
|
|
871
|
+
}
|
|
872
|
+
return this.form.fieldMap.get(parentPath.toString());
|
|
873
|
+
}
|
|
874
|
+
clear() {
|
|
875
|
+
if (!this.value) {
|
|
876
|
+
return;
|
|
877
|
+
}
|
|
878
|
+
this.value = void 0;
|
|
879
|
+
}
|
|
880
|
+
async validate() {
|
|
881
|
+
await this.validateSelf();
|
|
882
|
+
}
|
|
883
|
+
async validateSelf() {
|
|
884
|
+
this.state.isValidating = true;
|
|
885
|
+
this.bubbleState();
|
|
886
|
+
const { errors, warnings } = await this._runAsyncValidate();
|
|
887
|
+
if (errors?.length) {
|
|
888
|
+
this.state.errors = groupBy(errors, "name");
|
|
889
|
+
this.state.invalid = true;
|
|
890
|
+
} else {
|
|
891
|
+
this.state.errors = { [this.name]: [] };
|
|
892
|
+
this.state.invalid = false;
|
|
893
|
+
}
|
|
894
|
+
if (warnings?.length) {
|
|
895
|
+
this.state.warnings = groupBy(warnings, "name");
|
|
896
|
+
} else {
|
|
897
|
+
this.state.warnings = { [this.name]: [] };
|
|
898
|
+
}
|
|
899
|
+
this.state.isValidating = false;
|
|
900
|
+
this.bubbleState();
|
|
901
|
+
this.form.onValidateEmitter.fire(this.form.state);
|
|
902
|
+
}
|
|
903
|
+
async _runAsyncValidate() {
|
|
904
|
+
const errors = [];
|
|
905
|
+
const warnings = [];
|
|
906
|
+
const result = await this.form.validateIn(this.name);
|
|
907
|
+
if (!result) {
|
|
908
|
+
return {};
|
|
909
|
+
} else {
|
|
910
|
+
const feedback = toFeedback(result, this.name);
|
|
911
|
+
if (!feedback) {
|
|
912
|
+
return {};
|
|
913
|
+
}
|
|
914
|
+
if (isFieldWarning(feedback)) {
|
|
915
|
+
warnings.push(feedback);
|
|
916
|
+
} else {
|
|
917
|
+
errors.push(feedback);
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
return { errors, warnings };
|
|
921
|
+
}
|
|
922
|
+
updateState(s) {
|
|
923
|
+
}
|
|
924
|
+
dispose() {
|
|
925
|
+
this.children.map((c) => c.dispose());
|
|
926
|
+
this.toDispose.dispose();
|
|
927
|
+
this.form.fieldMap.delete(this.path.toString());
|
|
928
|
+
}
|
|
929
|
+
onDispose(fn) {
|
|
930
|
+
this.toDispose.onDispose(fn);
|
|
931
|
+
}
|
|
932
|
+
};
|
|
933
|
+
|
|
934
|
+
// src/core/field-array-model.ts
|
|
935
|
+
import { Emitter as Emitter2 } from "@flowgram.ai/utils";
|
|
936
|
+
var FieldArrayModel = class extends FieldModel {
|
|
937
|
+
constructor() {
|
|
938
|
+
super(...arguments);
|
|
939
|
+
this.onAppendEmitter = new Emitter2();
|
|
940
|
+
this.onAppend = this.onAppendEmitter.event;
|
|
941
|
+
this.onDeleteEmitter = new Emitter2();
|
|
942
|
+
this.onDelete = this.onDeleteEmitter.event;
|
|
943
|
+
}
|
|
944
|
+
get children() {
|
|
945
|
+
const fields = [];
|
|
946
|
+
this.form.fieldMap.forEach((field, name) => {
|
|
947
|
+
if (this.path.isChild(name)) {
|
|
948
|
+
fields.push(field);
|
|
949
|
+
}
|
|
950
|
+
});
|
|
951
|
+
return fields.sort((f1, f2) => {
|
|
952
|
+
const p1 = f1.path.value;
|
|
953
|
+
const p2 = f2.path.value;
|
|
954
|
+
const i1 = parseInt(p1[p1.length - 1]);
|
|
955
|
+
const i2 = parseInt(p1[p2.length - 1]);
|
|
956
|
+
return i1 - i2;
|
|
957
|
+
});
|
|
958
|
+
}
|
|
959
|
+
map(cb) {
|
|
960
|
+
const fields = (this.value || []).map((v, i) => {
|
|
961
|
+
const pathString = this.path.concat(i).toString();
|
|
962
|
+
let field = this.form.getField(pathString);
|
|
963
|
+
if (!field) {
|
|
964
|
+
field = this.form.createField(pathString);
|
|
965
|
+
}
|
|
966
|
+
return field;
|
|
967
|
+
});
|
|
968
|
+
return fields.map(cb);
|
|
969
|
+
}
|
|
970
|
+
append(value) {
|
|
971
|
+
const curLength = this.value?.length || 0;
|
|
972
|
+
const newElemPath = this.path.concat(curLength).toString();
|
|
973
|
+
const newElemField = this.form.createField(newElemPath);
|
|
974
|
+
const newArrayValue = this.value ? [...this.value, value] : [value];
|
|
975
|
+
const prevFormValues = this.form.values;
|
|
976
|
+
this.form.store.setIn(new Path(this.name), newArrayValue);
|
|
977
|
+
this.form.fireOnFormValuesChange({
|
|
978
|
+
values: this.form.values,
|
|
979
|
+
prevValues: prevFormValues,
|
|
980
|
+
name: this.name,
|
|
981
|
+
options: {
|
|
982
|
+
action: "array-append",
|
|
983
|
+
indexes: [curLength]
|
|
984
|
+
}
|
|
985
|
+
});
|
|
986
|
+
this.form.fireOnFormValuesInit({
|
|
987
|
+
values: this.form.values,
|
|
988
|
+
prevValues: prevFormValues,
|
|
989
|
+
name: newElemPath
|
|
990
|
+
});
|
|
991
|
+
this.onAppendEmitter.fire({
|
|
992
|
+
value,
|
|
993
|
+
arrayValue: this.value,
|
|
994
|
+
index: this.value.length - 1
|
|
995
|
+
});
|
|
996
|
+
return newElemField;
|
|
997
|
+
}
|
|
998
|
+
/**
|
|
999
|
+
* 删除数组项,该操作会删除数组项的值并销毁数组项的Field模型
|
|
1000
|
+
* @param index
|
|
1001
|
+
*/
|
|
1002
|
+
delete(index) {
|
|
1003
|
+
this._splice(index, 1);
|
|
1004
|
+
this.onDeleteEmitter.fire({ arrayValue: this.value, index });
|
|
1005
|
+
}
|
|
1006
|
+
_splice(start, deleteCount = 1) {
|
|
1007
|
+
if (start < 0 || deleteCount < 0) {
|
|
1008
|
+
throw new Error(
|
|
1009
|
+
`[Form] Error in FieldArrayModel.splice: Invalid Params, start and deleteCount should > 0`
|
|
1010
|
+
);
|
|
1011
|
+
}
|
|
1012
|
+
if (!this.value || this.value.length === 0 || deleteCount > this.value.length) {
|
|
1013
|
+
throw new Error(
|
|
1014
|
+
`[Form] Error in FieldArrayModel.splice: delete count exceeds array length, tried to delete ${deleteCount} elements, but array length is ${this.value?.length || 0}`
|
|
1015
|
+
);
|
|
1016
|
+
}
|
|
1017
|
+
const oldFormValues = this.form.values;
|
|
1018
|
+
const tempValue = [...this.value];
|
|
1019
|
+
tempValue.splice(start, deleteCount);
|
|
1020
|
+
this.form.store.setIn(new Path(this.name), tempValue);
|
|
1021
|
+
this.form.fireOnFormValuesChange({
|
|
1022
|
+
values: this.form.values,
|
|
1023
|
+
prevValues: oldFormValues,
|
|
1024
|
+
name: this.name,
|
|
1025
|
+
options: {
|
|
1026
|
+
action: "array-splice",
|
|
1027
|
+
indexes: Array.from({ length: deleteCount }, (_, i) => i + start)
|
|
1028
|
+
}
|
|
1029
|
+
});
|
|
1030
|
+
const children = this.children;
|
|
1031
|
+
if (start + deleteCount >= children.length) {
|
|
1032
|
+
for (let i = start; i < children.length; i++) {
|
|
1033
|
+
this.form.disposeField(children[i].name);
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
const toDispose = [];
|
|
1037
|
+
const newFieldMap = new Map(this.form.fieldMap);
|
|
1038
|
+
const recursiveHandleChildField = (field, index) => {
|
|
1039
|
+
if (field.children?.length) {
|
|
1040
|
+
field.children.forEach((cField) => {
|
|
1041
|
+
recursiveHandleChildField(cField, index);
|
|
1042
|
+
});
|
|
1043
|
+
}
|
|
1044
|
+
if (index < start) {
|
|
1045
|
+
newFieldMap.set(field.name, field);
|
|
1046
|
+
} else if (index < start + deleteCount) {
|
|
1047
|
+
toDispose.push(field);
|
|
1048
|
+
} else {
|
|
1049
|
+
const originName = field.name;
|
|
1050
|
+
const targetName = field.path.replaceParent(this.path.concat(index), this.path.concat(index - deleteCount)).toString();
|
|
1051
|
+
newFieldMap.set(targetName, field);
|
|
1052
|
+
if (!field.children.length) {
|
|
1053
|
+
field.updateNameForLeafState(targetName);
|
|
1054
|
+
field.bubbleState();
|
|
1055
|
+
}
|
|
1056
|
+
field.name = targetName;
|
|
1057
|
+
if (index > children.length - deleteCount - 1) {
|
|
1058
|
+
newFieldMap.delete(originName);
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
};
|
|
1062
|
+
children.map((field, index) => {
|
|
1063
|
+
recursiveHandleChildField(field, index);
|
|
1064
|
+
});
|
|
1065
|
+
toDispose.forEach((f) => {
|
|
1066
|
+
f.dispose();
|
|
1067
|
+
});
|
|
1068
|
+
this.form.fieldMap = newFieldMap;
|
|
1069
|
+
}
|
|
1070
|
+
swap(from, to) {
|
|
1071
|
+
if (!this.value) {
|
|
1072
|
+
return;
|
|
1073
|
+
}
|
|
1074
|
+
if (from < 0 || to < 0 || from > this.value.length - 1 || to > this.value.length - 1) {
|
|
1075
|
+
throw new Error(
|
|
1076
|
+
`[Form]: FieldArrayModel.swap Error: invalid params 'form' and 'to', form=${from} to=${to}. expect the value between 0 to ${length - 1}`
|
|
1077
|
+
);
|
|
1078
|
+
}
|
|
1079
|
+
const tempValue = [...this.value];
|
|
1080
|
+
const fromValue = tempValue[from];
|
|
1081
|
+
const toValue = tempValue[to];
|
|
1082
|
+
tempValue[to] = fromValue;
|
|
1083
|
+
tempValue[from] = toValue;
|
|
1084
|
+
this.form.setValueIn(this.name, tempValue);
|
|
1085
|
+
}
|
|
1086
|
+
move(from, to) {
|
|
1087
|
+
if (!this.value) {
|
|
1088
|
+
return;
|
|
1089
|
+
}
|
|
1090
|
+
if (from < 0 || to < 0 || from > this.value.length - 1 || to > this.value.length - 1) {
|
|
1091
|
+
throw new Error(
|
|
1092
|
+
`[Form]: FieldArrayModel.move Error: invalid params 'form' and 'to', form=${from} to=${to}. expect the value between 0 to ${length - 1}`
|
|
1093
|
+
);
|
|
1094
|
+
}
|
|
1095
|
+
const tempValue = [...this.value];
|
|
1096
|
+
const fromValue = tempValue[from];
|
|
1097
|
+
tempValue.splice(from, 1);
|
|
1098
|
+
tempValue.splice(to, 0, fromValue);
|
|
1099
|
+
this.form.setValueIn(this.name, tempValue);
|
|
1100
|
+
}
|
|
1101
|
+
};
|
|
1102
|
+
|
|
1103
|
+
// src/core/form-model.ts
|
|
1104
|
+
var findMatchPaths = Glob.findMatchPaths;
|
|
1105
|
+
var FormModel = class {
|
|
1106
|
+
constructor() {
|
|
1107
|
+
this._fieldMap = /* @__PURE__ */ new Map();
|
|
1108
|
+
this.store = new Store();
|
|
1109
|
+
this._options = {};
|
|
1110
|
+
this.onFieldModelCreateEmitter = new Emitter3();
|
|
1111
|
+
this.onFieldModelCreate = this.onFieldModelCreateEmitter.event;
|
|
1112
|
+
this.onFormValuesChangeEmitter = new Emitter3();
|
|
1113
|
+
this.onFormValuesChange = this.onFormValuesChangeEmitter.event;
|
|
1114
|
+
this.onFormValuesInitEmitter = new Emitter3();
|
|
1115
|
+
this.onFormValuesInit = this.onFormValuesInitEmitter.event;
|
|
1116
|
+
this.onFormValuesUpdatedEmitter = new Emitter3();
|
|
1117
|
+
this.onFormValuesUpdated = this.onFormValuesUpdatedEmitter.event;
|
|
1118
|
+
this.onValidateEmitter = new Emitter3();
|
|
1119
|
+
this.onValidate = this.onValidateEmitter.event;
|
|
1120
|
+
this._state = new ReactiveState2(
|
|
1121
|
+
createFormModelState()
|
|
1122
|
+
);
|
|
1123
|
+
this._initialized = false;
|
|
1124
|
+
}
|
|
1125
|
+
set fieldMap(map) {
|
|
1126
|
+
this._fieldMap = map;
|
|
1127
|
+
}
|
|
1128
|
+
/**
|
|
1129
|
+
* 表单初始值,初始化设置后不可修改
|
|
1130
|
+
* @protected
|
|
1131
|
+
*/
|
|
1132
|
+
// protected _initialValues?: TValues;
|
|
1133
|
+
get fieldMap() {
|
|
1134
|
+
return this._fieldMap;
|
|
1135
|
+
}
|
|
1136
|
+
get context() {
|
|
1137
|
+
return this._options.context;
|
|
1138
|
+
}
|
|
1139
|
+
get initialValues() {
|
|
1140
|
+
return this._options.initialValues;
|
|
1141
|
+
}
|
|
1142
|
+
get values() {
|
|
1143
|
+
return cloneDeep(this.store.values) || cloneDeep(this.initialValues);
|
|
1144
|
+
}
|
|
1145
|
+
get validationTrigger() {
|
|
1146
|
+
return this._options.validateTrigger;
|
|
1147
|
+
}
|
|
1148
|
+
get state() {
|
|
1149
|
+
return this._state.value;
|
|
1150
|
+
}
|
|
1151
|
+
get reactiveState() {
|
|
1152
|
+
return this._state;
|
|
1153
|
+
}
|
|
1154
|
+
get fields() {
|
|
1155
|
+
return Array.from(this.fieldMap.values());
|
|
1156
|
+
}
|
|
1157
|
+
updateState(state) {
|
|
1158
|
+
}
|
|
1159
|
+
get initialized() {
|
|
1160
|
+
return this._initialized;
|
|
1161
|
+
}
|
|
1162
|
+
fireOnFormValuesChange(payload) {
|
|
1163
|
+
this.onFormValuesChangeEmitter.fire(payload);
|
|
1164
|
+
this.onFormValuesUpdatedEmitter.fire(payload);
|
|
1165
|
+
}
|
|
1166
|
+
fireOnFormValuesInit(payload) {
|
|
1167
|
+
this.onFormValuesInitEmitter.fire(payload);
|
|
1168
|
+
this.onFormValuesUpdatedEmitter.fire(payload);
|
|
1169
|
+
}
|
|
1170
|
+
init(options) {
|
|
1171
|
+
this._options = options;
|
|
1172
|
+
if (options.initialValues) {
|
|
1173
|
+
const prevValues = this.store.values;
|
|
1174
|
+
this.store.setInitialValues(options.initialValues);
|
|
1175
|
+
this.fireOnFormValuesInit({
|
|
1176
|
+
values: options.initialValues,
|
|
1177
|
+
prevValues,
|
|
1178
|
+
name: ""
|
|
1179
|
+
});
|
|
1180
|
+
}
|
|
1181
|
+
this._initialized = true;
|
|
1182
|
+
}
|
|
1183
|
+
createField(name, isArray2) {
|
|
1184
|
+
const path = new Path(name);
|
|
1185
|
+
const pathString = path.toString();
|
|
1186
|
+
if (this.fieldMap.get(pathString)) {
|
|
1187
|
+
return this.fieldMap.get(pathString);
|
|
1188
|
+
}
|
|
1189
|
+
const field = isArray2 ? new FieldArrayModel(path, this) : new FieldModel(path, this);
|
|
1190
|
+
this.fieldMap.set(pathString, field);
|
|
1191
|
+
field.onDispose(() => {
|
|
1192
|
+
this.fieldMap.delete(pathString);
|
|
1193
|
+
});
|
|
1194
|
+
this.onFieldModelCreateEmitter.fire(field);
|
|
1195
|
+
return field;
|
|
1196
|
+
}
|
|
1197
|
+
createFieldArray(name, value) {
|
|
1198
|
+
return this.createField(name, true);
|
|
1199
|
+
}
|
|
1200
|
+
/**
|
|
1201
|
+
* 销毁Field 模型和子模型,但不会删除field的值
|
|
1202
|
+
* @param name
|
|
1203
|
+
*/
|
|
1204
|
+
disposeField(name) {
|
|
1205
|
+
const field = this.fieldMap.get(name);
|
|
1206
|
+
if (field) {
|
|
1207
|
+
field.dispose();
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
/**
|
|
1211
|
+
* 删除field, 会删除值和 Field 模型, 以及对应的子模型
|
|
1212
|
+
* @param name
|
|
1213
|
+
*/
|
|
1214
|
+
deleteField(name) {
|
|
1215
|
+
const field = this.fieldMap.get(name);
|
|
1216
|
+
if (field) {
|
|
1217
|
+
field.clear();
|
|
1218
|
+
field.dispose();
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
getField(name) {
|
|
1222
|
+
return this.fieldMap.get(new Path(name).toString());
|
|
1223
|
+
}
|
|
1224
|
+
getValueIn(name) {
|
|
1225
|
+
return this.store.getIn(new Path(name));
|
|
1226
|
+
}
|
|
1227
|
+
setValueIn(name, value) {
|
|
1228
|
+
const prevValues = this.values;
|
|
1229
|
+
this.store.setIn(new Path(name), value);
|
|
1230
|
+
this.fireOnFormValuesChange({
|
|
1231
|
+
values: this.values,
|
|
1232
|
+
prevValues,
|
|
1233
|
+
name
|
|
1234
|
+
});
|
|
1235
|
+
}
|
|
1236
|
+
setInitValueIn(name, value) {
|
|
1237
|
+
const path = new Path(name);
|
|
1238
|
+
const prevValue = this.store.getIn(path);
|
|
1239
|
+
if (prevValue === void 0) {
|
|
1240
|
+
const prevValues = this.values;
|
|
1241
|
+
this.store.setIn(new Path(name), value);
|
|
1242
|
+
this.fireOnFormValuesInit({
|
|
1243
|
+
values: this.values,
|
|
1244
|
+
prevValues,
|
|
1245
|
+
name
|
|
1246
|
+
});
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
clearValueIn(name) {
|
|
1250
|
+
this.setValueIn(name, void 0);
|
|
1251
|
+
}
|
|
1252
|
+
async validateIn(name) {
|
|
1253
|
+
if (!this._options.validate) {
|
|
1254
|
+
return;
|
|
1255
|
+
}
|
|
1256
|
+
const validateKey = Object.keys(this._options.validate).find(
|
|
1257
|
+
(pattern) => Glob.isMatch(pattern, name)
|
|
1258
|
+
);
|
|
1259
|
+
if (validateKey) {
|
|
1260
|
+
const validate = this._options.validate[validateKey];
|
|
1261
|
+
return validate({
|
|
1262
|
+
value: this.getValueIn(name),
|
|
1263
|
+
formValues: this.values,
|
|
1264
|
+
context: this.context,
|
|
1265
|
+
name
|
|
1266
|
+
});
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
async validate() {
|
|
1270
|
+
if (!this._options.validate) {
|
|
1271
|
+
return [];
|
|
1272
|
+
}
|
|
1273
|
+
const feedbacksArrPromises = Object.keys(this._options.validate).map(async (nameRule) => {
|
|
1274
|
+
const validate = this._options.validate[nameRule];
|
|
1275
|
+
const paths = findMatchPaths(this.values, nameRule);
|
|
1276
|
+
return Promise.all(
|
|
1277
|
+
paths.map(async (path) => {
|
|
1278
|
+
const result = await validate({
|
|
1279
|
+
value: get4(this.values, path),
|
|
1280
|
+
formValues: this.values,
|
|
1281
|
+
context: this.context,
|
|
1282
|
+
name: path
|
|
1283
|
+
});
|
|
1284
|
+
const feedback = toFeedback(result, path);
|
|
1285
|
+
const field = this.getField(path);
|
|
1286
|
+
const errors = feedbackToFieldErrorsOrWarnings(path, feedback);
|
|
1287
|
+
const warnings = feedbackToFieldErrorsOrWarnings(path, feedback);
|
|
1288
|
+
if (field) {
|
|
1289
|
+
field.state.errors = errors;
|
|
1290
|
+
field.state.warnings = warnings;
|
|
1291
|
+
field.bubbleState();
|
|
1292
|
+
}
|
|
1293
|
+
this.state.errors = mergeFeedbacks(this.state.errors, errors);
|
|
1294
|
+
this.state.warnings = mergeFeedbacks(this.state.warnings, warnings);
|
|
1295
|
+
this.state.invalid = !getValidByErrors(this.state.errors);
|
|
1296
|
+
return feedback;
|
|
1297
|
+
})
|
|
1298
|
+
);
|
|
1299
|
+
});
|
|
1300
|
+
this.state.isValidating = true;
|
|
1301
|
+
const feedbacksArr = await Promise.all(feedbacksArrPromises);
|
|
1302
|
+
this.state.isValidating = false;
|
|
1303
|
+
this.onValidateEmitter.fire(this.state);
|
|
1304
|
+
return flatten2(feedbacksArr).filter(Boolean);
|
|
1305
|
+
}
|
|
1306
|
+
dispose() {
|
|
1307
|
+
this.fieldMap.forEach((f) => f.dispose());
|
|
1308
|
+
this.store.dispose();
|
|
1309
|
+
this._initialized = false;
|
|
1310
|
+
}
|
|
1311
|
+
};
|
|
1312
|
+
|
|
1313
|
+
// src/core/create-form.ts
|
|
1314
|
+
function createForm(options) {
|
|
1315
|
+
const { disableAutoInit = false, ...formOptions } = options || {};
|
|
1316
|
+
const formModel = new FormModel();
|
|
1317
|
+
if (!disableAutoInit) {
|
|
1318
|
+
formModel.init(formOptions || {});
|
|
1319
|
+
}
|
|
1320
|
+
return {
|
|
1321
|
+
form: toForm(formModel),
|
|
1322
|
+
control: {
|
|
1323
|
+
_formModel: formModel,
|
|
1324
|
+
getField: (name) => {
|
|
1325
|
+
const fieldModel = formModel.getField(name);
|
|
1326
|
+
if (fieldModel) {
|
|
1327
|
+
return fieldModel instanceof FieldArrayModel ? toFieldArray(fieldModel) : toField(fieldModel);
|
|
1328
|
+
}
|
|
1329
|
+
},
|
|
1330
|
+
init: () => formModel.init(formOptions || {})
|
|
1331
|
+
}
|
|
1332
|
+
};
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
// src/react/form.tsx
|
|
1336
|
+
function Form(props) {
|
|
1337
|
+
const { children, keepModelOnUnMount = false, control, ...restOptions } = props;
|
|
1338
|
+
const { _formModel: formModel } = useMemo2(
|
|
1339
|
+
() => control ? control : createForm(restOptions).control,
|
|
1340
|
+
[control]
|
|
1341
|
+
);
|
|
1342
|
+
useEffect2(
|
|
1343
|
+
() => () => {
|
|
1344
|
+
if (!keepModelOnUnMount) {
|
|
1345
|
+
formModel.dispose();
|
|
1346
|
+
}
|
|
1347
|
+
},
|
|
1348
|
+
[]
|
|
1349
|
+
);
|
|
1350
|
+
const form = useMemo2(() => toForm(formModel), [formModel]);
|
|
1351
|
+
return /* @__PURE__ */ React3.createElement(FormModelContext.Provider, { value: formModel }, children ? isFunction2(children) ? children({ form }) : Children.only(children) : null);
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
// src/react/use-form.ts
|
|
1355
|
+
function useForm() {
|
|
1356
|
+
const formModel = useFormModel();
|
|
1357
|
+
return toForm(formModel);
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
// src/react/use-watch.ts
|
|
1361
|
+
import { useEffect as useEffect3 } from "react";
|
|
1362
|
+
import { useRefresh as useRefresh2 } from "@flowgram.ai/utils";
|
|
1363
|
+
function useWatch(name) {
|
|
1364
|
+
const refresh = useRefresh2();
|
|
1365
|
+
const formModel = useFormModel();
|
|
1366
|
+
if (!formModel) {
|
|
1367
|
+
throw new Error("[Form] error in useWatch, formModel not found");
|
|
1368
|
+
}
|
|
1369
|
+
const value = formModel.getValueIn(name);
|
|
1370
|
+
useEffect3(() => {
|
|
1371
|
+
const disposable = formModel.onFormValuesUpdated(({ name: updatedName }) => {
|
|
1372
|
+
if (updatedName === name) {
|
|
1373
|
+
refresh();
|
|
1374
|
+
}
|
|
1375
|
+
});
|
|
1376
|
+
return () => disposable.dispose();
|
|
1377
|
+
}, [name, formModel]);
|
|
1378
|
+
return value;
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
// src/react/field-array.tsx
|
|
1382
|
+
import * as React4 from "react";
|
|
1383
|
+
import { isFunction as isFunction3 } from "lodash";
|
|
1384
|
+
import { DisposableCollection as DisposableCollection3, useRefresh as useRefresh3 } from "@flowgram.ai/utils";
|
|
1385
|
+
import { useReadonlyReactiveState as useReadonlyReactiveState2 } from "@flowgram.ai/reactive";
|
|
1386
|
+
function FieldArray({
|
|
1387
|
+
name,
|
|
1388
|
+
defaultValue,
|
|
1389
|
+
deps,
|
|
1390
|
+
render,
|
|
1391
|
+
children
|
|
1392
|
+
}) {
|
|
1393
|
+
const formModel = useFormModel();
|
|
1394
|
+
const fieldModel = React4.useMemo(
|
|
1395
|
+
() => formModel.getField(name) || formModel.createFieldArray(name),
|
|
1396
|
+
[]
|
|
1397
|
+
);
|
|
1398
|
+
const field = React4.useMemo(() => toFieldArray(fieldModel), [fieldModel]);
|
|
1399
|
+
const refresh = useRefresh3();
|
|
1400
|
+
const fieldModelState = useReadonlyReactiveState2(fieldModel.reactiveState);
|
|
1401
|
+
const formModelState = useReadonlyReactiveState2(formModel.reactiveState);
|
|
1402
|
+
const fieldState = toFieldState(fieldModelState);
|
|
1403
|
+
const formState = React4.useMemo(() => toFormState(formModelState), [formModelState]);
|
|
1404
|
+
React4.useEffect(() => {
|
|
1405
|
+
fieldModel.renderCount = fieldModel.renderCount + 1;
|
|
1406
|
+
if (!formModel.getValueIn(name) !== void 0 && defaultValue !== void 0) {
|
|
1407
|
+
formModel.setInitValueIn(name, defaultValue);
|
|
1408
|
+
refresh();
|
|
1409
|
+
}
|
|
1410
|
+
const disposableCollection = new DisposableCollection3();
|
|
1411
|
+
disposableCollection.push(
|
|
1412
|
+
fieldModel.onValueChange(() => {
|
|
1413
|
+
refresh();
|
|
1414
|
+
})
|
|
1415
|
+
);
|
|
1416
|
+
if (deps) {
|
|
1417
|
+
deps.forEach((dep) => {
|
|
1418
|
+
const disposable = formModel.getField(dep)?.onValueChange(() => {
|
|
1419
|
+
refresh();
|
|
1420
|
+
});
|
|
1421
|
+
if (disposable) {
|
|
1422
|
+
disposableCollection.push(disposable);
|
|
1423
|
+
}
|
|
1424
|
+
});
|
|
1425
|
+
}
|
|
1426
|
+
return () => {
|
|
1427
|
+
disposableCollection.dispose();
|
|
1428
|
+
if (fieldModel.renderCount > 1) {
|
|
1429
|
+
fieldModel.renderCount = fieldModel.renderCount - 1;
|
|
1430
|
+
} else {
|
|
1431
|
+
fieldModel.dispose();
|
|
1432
|
+
}
|
|
1433
|
+
};
|
|
1434
|
+
}, [fieldModel]);
|
|
1435
|
+
const renderInner = () => {
|
|
1436
|
+
if (render && isFunction3(render)) {
|
|
1437
|
+
return render({ field, fieldState, formState });
|
|
1438
|
+
}
|
|
1439
|
+
if (isFunction3(children)) {
|
|
1440
|
+
return children({ field, fieldState, formState });
|
|
1441
|
+
}
|
|
1442
|
+
return /* @__PURE__ */ React4.createElement(React4.Fragment, null, "Invalid Array render");
|
|
1443
|
+
};
|
|
1444
|
+
return /* @__PURE__ */ React4.createElement(FieldModelContext.Provider, { value: fieldModel }, renderInner());
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
// src/react/use-field.ts
|
|
1448
|
+
import { useContext as useContext2, useEffect as useEffect5 } from "react";
|
|
1449
|
+
import { useRefresh as useRefresh4 } from "@flowgram.ai/utils";
|
|
1450
|
+
function useField(name) {
|
|
1451
|
+
const currentFieldModel = useContext2(FieldModelContext);
|
|
1452
|
+
const formModel = useFormModel();
|
|
1453
|
+
const refresh = useRefresh4();
|
|
1454
|
+
const fieldModel = name ? formModel.getField(name) : currentFieldModel;
|
|
1455
|
+
useEffect5(() => {
|
|
1456
|
+
let disposable;
|
|
1457
|
+
if (fieldModel) {
|
|
1458
|
+
disposable = fieldModel.onValueChange(() => refresh());
|
|
1459
|
+
}
|
|
1460
|
+
return () => {
|
|
1461
|
+
disposable?.dispose();
|
|
1462
|
+
};
|
|
1463
|
+
}, [fieldModel]);
|
|
1464
|
+
if (!fieldModel) {
|
|
1465
|
+
return void 0;
|
|
1466
|
+
}
|
|
1467
|
+
if (fieldModel.map) {
|
|
1468
|
+
return toFieldArray(fieldModel);
|
|
1469
|
+
}
|
|
1470
|
+
return toField(fieldModel);
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1473
|
+
// src/react/use-form-state.ts
|
|
1474
|
+
import { useObserve } from "@flowgram.ai/reactive";
|
|
1475
|
+
function useFormState(control) {
|
|
1476
|
+
return useObserve(control?._formModel.reactiveState.value || {});
|
|
1477
|
+
}
|
|
1478
|
+
function useFormErrors(control) {
|
|
1479
|
+
return useObserve(control?._formModel.reactiveState.value || {})?.errors;
|
|
1480
|
+
}
|
|
1481
|
+
function useFormWarnings(control) {
|
|
1482
|
+
return useObserve(control?._formModel.reactiveState.value || {})?.warnings;
|
|
1483
|
+
}
|
|
1484
|
+
|
|
1485
|
+
// src/react/use-field-validate.ts
|
|
1486
|
+
import { useCallback, useContext as useContext3 } from "react";
|
|
1487
|
+
function useFieldValidate(name) {
|
|
1488
|
+
const currentFieldModel = useContext3(FieldModelContext);
|
|
1489
|
+
const formModel = useFormModel();
|
|
1490
|
+
return useCallback(() => {
|
|
1491
|
+
const fieldModel = name ? formModel.getField(name) : currentFieldModel;
|
|
1492
|
+
fieldModel?.validate();
|
|
1493
|
+
}, [currentFieldModel]);
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
// src/react/use-current-field.ts
|
|
1497
|
+
import { useContext as useContext4 } from "react";
|
|
1498
|
+
function useCurrentField() {
|
|
1499
|
+
const fieldModel = useContext4(FieldModelContext);
|
|
1500
|
+
if (!fieldModel) {
|
|
1501
|
+
throw new Error(
|
|
1502
|
+
`[Form] useCurrentField Error: field not found, make sure that you are using this hook in a child Component of a Field`
|
|
1503
|
+
);
|
|
1504
|
+
}
|
|
1505
|
+
return fieldModel.map ? toFieldArray(fieldModel) : toField(fieldModel);
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1508
|
+
// src/react/use-current-field-state.ts
|
|
1509
|
+
import { useContext as useContext5, useMemo as useMemo4 } from "react";
|
|
1510
|
+
import { useReadonlyReactiveState as useReadonlyReactiveState3 } from "@flowgram.ai/reactive";
|
|
1511
|
+
function useCurrentFieldState() {
|
|
1512
|
+
const fieldModel = useContext5(FieldModelContext);
|
|
1513
|
+
if (!fieldModel) {
|
|
1514
|
+
throw new Error(
|
|
1515
|
+
`[Form] useCurrentField Error: field not found, make sure that you are using this hook in a child Component of a Field`
|
|
1516
|
+
);
|
|
1517
|
+
}
|
|
1518
|
+
const fieldModelState = useReadonlyReactiveState3(fieldModel.reactiveState);
|
|
1519
|
+
return useMemo4(() => toFieldState(fieldModelState), [fieldModelState]);
|
|
1520
|
+
}
|
|
1521
|
+
export {
|
|
1522
|
+
Field,
|
|
1523
|
+
FieldArray,
|
|
1524
|
+
FieldArrayModel,
|
|
1525
|
+
FieldModel,
|
|
1526
|
+
Form,
|
|
1527
|
+
FormModel,
|
|
1528
|
+
Glob,
|
|
1529
|
+
Path,
|
|
1530
|
+
ValidateTrigger,
|
|
1531
|
+
createForm,
|
|
1532
|
+
toField,
|
|
1533
|
+
toFieldArray,
|
|
1534
|
+
toFieldState,
|
|
1535
|
+
toForm,
|
|
1536
|
+
toFormState,
|
|
1537
|
+
useCurrentField,
|
|
1538
|
+
useCurrentFieldState,
|
|
1539
|
+
useField,
|
|
1540
|
+
useFieldValidate,
|
|
1541
|
+
useForm,
|
|
1542
|
+
useFormErrors,
|
|
1543
|
+
useFormState,
|
|
1544
|
+
useFormWarnings,
|
|
1545
|
+
useWatch
|
|
1546
|
+
};
|
|
1547
|
+
//# sourceMappingURL=index.js.map
|