react-f0rm 1.1.1 → 1.3.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.
Files changed (61) hide show
  1. package/README.md +242 -39
  2. package/dist/devtools/index.cjs.js +1 -1
  3. package/dist/devtools/index.cjs.js.map +1 -1
  4. package/dist/devtools/index.d.ts +2 -2
  5. package/dist/devtools/index.mjs +1 -1
  6. package/dist/devtools/index.mjs.map +1 -1
  7. package/dist/errors-BKrUdpfI.cjs.js +2 -0
  8. package/dist/errors-BKrUdpfI.cjs.js.map +1 -0
  9. package/dist/errors-CrQBddrJ.mjs +2 -0
  10. package/dist/errors-CrQBddrJ.mjs.map +1 -0
  11. package/dist/form-CeKSBs31.d.ts +486 -0
  12. package/dist/index.cjs.js +1 -1
  13. package/dist/index.cjs.js.map +1 -1
  14. package/dist/index.d.ts +1097 -118
  15. package/dist/index.mjs +1 -1
  16. package/dist/index.mjs.map +1 -1
  17. package/dist/index.umd.js +1082 -544
  18. package/dist/index.umd.js.map +1 -1
  19. package/dist/index.umd.min.js +2 -2
  20. package/dist/index.umd.min.js.map +1 -1
  21. package/dist/persist.cjs.js +2 -0
  22. package/dist/persist.cjs.js.map +1 -0
  23. package/dist/persist.d.ts +49 -0
  24. package/dist/persist.mjs +2 -0
  25. package/dist/persist.mjs.map +1 -0
  26. package/dist/resolvers/standard-schema.cjs.js +1 -1
  27. package/dist/resolvers/standard-schema.cjs.js.map +1 -1
  28. package/dist/resolvers/standard-schema.d.ts +7 -5
  29. package/dist/resolvers/standard-schema.mjs +1 -1
  30. package/dist/resolvers/standard-schema.mjs.map +1 -1
  31. package/dist/resolvers/yup.cjs.js +1 -1
  32. package/dist/resolvers/yup.cjs.js.map +1 -1
  33. package/dist/resolvers/yup.d.ts +1 -1
  34. package/dist/resolvers/yup.mjs +1 -1
  35. package/dist/resolvers/yup.mjs.map +1 -1
  36. package/dist/resolvers/zod.cjs.js +1 -1
  37. package/dist/resolvers/zod.cjs.js.map +1 -1
  38. package/dist/resolvers/zod.d.ts +1 -1
  39. package/dist/resolvers/zod.mjs +1 -1
  40. package/dist/resolvers/zod.mjs.map +1 -1
  41. package/dist/server/index.cjs.js +2 -0
  42. package/dist/server/index.cjs.js.map +1 -0
  43. package/dist/server/index.d.ts +77 -0
  44. package/dist/server/index.mjs +2 -0
  45. package/dist/server/index.mjs.map +1 -0
  46. package/dist/validate-CNtuUhmk.mjs +2 -0
  47. package/dist/validate-CNtuUhmk.mjs.map +1 -0
  48. package/dist/validate-Cl4ksNFu.cjs.js +2 -0
  49. package/dist/validate-Cl4ksNFu.cjs.js.map +1 -0
  50. package/dist/validate-nksgv1pR.d.ts +272 -0
  51. package/dist/values-Cu6awQOJ.cjs.js +2 -0
  52. package/dist/values-Cu6awQOJ.cjs.js.map +1 -0
  53. package/dist/values-DRY-a32G.mjs +2 -0
  54. package/dist/values-DRY-a32G.mjs.map +1 -0
  55. package/package.json +87 -29
  56. package/dist/form-2_tBkEXU.mjs +0 -2
  57. package/dist/form-2_tBkEXU.mjs.map +0 -1
  58. package/dist/form-BiDaJLjD.d.ts +0 -826
  59. package/dist/form-BwLNQ6WB.cjs.js +0 -2
  60. package/dist/form-BwLNQ6WB.cjs.js.map +0 -1
  61. package/dist/validate-2XUilILy.d.ts +0 -22
package/dist/index.umd.js CHANGED
@@ -23,6 +23,67 @@
23
23
 
24
24
  var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
25
25
 
26
+ function _arrayLikeToArray(r, a) {
27
+ (null == a || a > r.length) && (a = r.length);
28
+ for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
29
+ return n;
30
+ }
31
+ function _createForOfIteratorHelper(r, e) {
32
+ var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
33
+ if (!t) {
34
+ if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e) {
35
+ t && (r = t);
36
+ var n = 0,
37
+ F = function () {};
38
+ return {
39
+ s: F,
40
+ n: function () {
41
+ return n >= r.length ? {
42
+ done: true
43
+ } : {
44
+ done: false,
45
+ value: r[n++]
46
+ };
47
+ },
48
+ e: function (r) {
49
+ throw r;
50
+ },
51
+ f: F
52
+ };
53
+ }
54
+ throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
55
+ }
56
+ var o,
57
+ a = true,
58
+ u = false;
59
+ return {
60
+ s: function () {
61
+ t = t.call(r);
62
+ },
63
+ n: function () {
64
+ var r = t.next();
65
+ return a = r.done, r;
66
+ },
67
+ e: function (r) {
68
+ u = true, o = r;
69
+ },
70
+ f: function () {
71
+ try {
72
+ a || null == t.return || t.return();
73
+ } finally {
74
+ if (u) throw o;
75
+ }
76
+ }
77
+ };
78
+ }
79
+ function _unsupportedIterableToArray(r, a) {
80
+ if (r) {
81
+ if ("string" == typeof r) return _arrayLikeToArray(r, a);
82
+ var t = {}.toString.call(r).slice(8, -1);
83
+ return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
84
+ }
85
+ }
86
+
26
87
  function getSet(ee, key) {
27
88
  var set = ee.get(key);
28
89
  if (set) return set;
@@ -30,20 +91,85 @@
30
91
  ee.set(key, newSet);
31
92
  return newSet;
32
93
  }
94
+
95
+ // DEV-only listener-leak warning. Checked via process.env.NODE_ENV because the
96
+ // build pipeline has no compile-time constant injection; the typeof guard
97
+ // keeps direct browser usage of the UMD build safe. In production the whole
98
+ // machinery is skipped and `on` only pays one boolean test.
99
+ var DEV = typeof process !== 'undefined' && process.env && process.env.NODE_ENV !== 'production';
100
+ var DEFAULT_MAX_LISTENERS = 10;
101
+ var maxListenersMap = new WeakMap();
102
+ var warnedKeysMap = new WeakMap();
103
+ function _setMaxListeners(ee, n) {
104
+ maxListenersMap.set(ee, n);
105
+ }
106
+ function checkMaxListeners(ee, key, size) {
107
+ var max = maxListenersMap.get(ee);
108
+ if (max === undefined) max = DEFAULT_MAX_LISTENERS;
109
+ if (max <= 0 || size <= max) return;
110
+ var warnedKeys = warnedKeysMap.get(ee);
111
+ if (!warnedKeys) {
112
+ warnedKeys = new Set();
113
+ warnedKeysMap.set(ee, warnedKeys);
114
+ }
115
+ if (warnedKeys.has(key)) return;
116
+ warnedKeys.add(key);
117
+ // eslint-disable-next-line no-console
118
+ console.warn("Possible event-emitter memory leak: ".concat(size, " \"").concat(String(key), "\" listeners added. ") + "Use setMaxListeners(ee, n) to raise the limit, or 0 to disable this warning.");
119
+ }
120
+ var errorEvent = Symbol('error');
33
121
  function create$2() {
34
122
  return new Map();
35
123
  }
124
+
125
+ // A throwing handler must not stop its peers: errors are collected while the
126
+ // remaining handlers still run, then reported through emitError (the
127
+ // errorEvent channel). If no error handler is subscribed either, the first
128
+ // collected error is rethrown to the emit caller instead of being swallowed.
129
+ // Iteration follows Set semantics: a listener added while this emit runs is
130
+ // still visited by that same emit, and a listener removed before it is
131
+ // visited is skipped. Removing a whole key (off/removeAllListeners) does not
132
+ // affect an emit already in flight.
36
133
  function emit(ee, key) {
37
134
  for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
38
135
  args[_key - 2] = arguments[_key];
39
136
  }
40
- (ee.get(key) || []).forEach(function (h) {
41
- return h.apply(void 0, args);
137
+ var set = ee.get(key);
138
+ if (!set || !set.size) return;
139
+ var errors;
140
+ set.forEach(function (h) {
141
+ try {
142
+ h.apply(void 0, args);
143
+ } catch (err) {
144
+ if (errors) errors.push(err);else errors = [err];
145
+ }
146
+ });
147
+ if (errors) {
148
+ var _iterator = _createForOfIteratorHelper(errors),
149
+ _step;
150
+ try {
151
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
152
+ var err = _step.value;
153
+ emitError(ee, err);
154
+ }
155
+ } catch (err) {
156
+ _iterator.e(err);
157
+ } finally {
158
+ _iterator.f();
159
+ }
160
+ }
161
+ }
162
+ function emitError(ee, err) {
163
+ var handlerSet = ee.get(errorEvent);
164
+ if (!handlerSet || !handlerSet.size) throw err;
165
+ handlerSet.forEach(function (h) {
166
+ return h(err);
42
167
  });
43
168
  }
44
169
  function on(ee, key, handler) {
45
170
  var set = getSet(ee, key);
46
171
  set.add(handler);
172
+ if (DEV) checkMaxListeners(ee, key, set.size);
47
173
  return function () {
48
174
  return set.delete(handler);
49
175
  };
@@ -230,110 +356,59 @@
230
356
  return { value, key: JSON.stringify(value) };
231
357
  }
232
358
 
233
- const VALIDATION_OUTCOME = /* @__PURE__ */ Symbol("validation-outcome");
234
- function create(options) {
235
- const emitter = create$2();
236
- return {
237
- emitter,
238
- ...options,
239
- mode: options?.mode ?? "onSubmit",
240
- reValidateMode: options?.reValidateMode ?? "onChange",
241
- disabled: options?.disabled ?? false,
242
- validateDeps: options?.validateDeps ? new Set(options.validateDeps.map((dep) => create$1(dep).key)) : void 0,
243
- initialValues: options?.initialValues ?? {},
244
- values: /* @__PURE__ */ new Map(),
245
- deleted: /* @__PURE__ */ new Set(),
246
- errors: /* @__PURE__ */ new Map(),
247
- touched: /* @__PURE__ */ new Set(),
248
- validators: /* @__PURE__ */ new Map(),
249
- changeHandlers: /* @__PURE__ */ new Map(),
250
- validating: /* @__PURE__ */ new Set(),
251
- parsedValues: void 0,
252
- isSubmitting: false,
253
- submitCount: 0,
254
- isSubmitSuccessful: void 0
255
- };
256
- }
257
359
  const valuesCaches = /* @__PURE__ */ new WeakMap();
258
360
  function bumpValuesVersion(form) {
259
361
  const cache = valuesCaches.get(form);
260
362
  if (cache) cache.version++;
261
363
  }
262
- function getValues(form) {
263
- let cache = valuesCaches.get(form);
264
- if (!cache) {
265
- cache = { version: 0, result: computeValues(form) };
266
- valuesCaches.set(form, cache);
267
- } else if (cache.version > 0) {
268
- cache.result = computeValues(form);
269
- cache.version = 0;
270
- }
271
- return cache.result;
364
+ const dirtyBaselines = /* @__PURE__ */ new WeakMap();
365
+ function getDirtyBaseline(form, key, segments) {
366
+ const baselines = dirtyBaselines.get(form);
367
+ if (baselines?.has(key)) return baselines.get(key);
368
+ return get(form.initialValues, segments);
272
369
  }
273
- function computeValues(form) {
274
- const { initialValues, parsedValues, values, deleted } = form;
275
- const owned = /* @__PURE__ */ new Set();
276
- let merged = parsedValues ?? initialValues;
277
- for (const [key, value] of values) {
278
- merged = setOwned(merged, JSON.parse(key), value, owned);
279
- }
280
- for (const key of deleted) {
281
- merged = unset(merged, JSON.parse(key));
370
+ function setDirtyBaseline(form, { key }, value) {
371
+ let baselines = dirtyBaselines.get(form);
372
+ if (!baselines) {
373
+ baselines = /* @__PURE__ */ new Map();
374
+ dirtyBaselines.set(form, baselines);
282
375
  }
283
- return merged;
284
- }
285
- function getValue(form, name) {
286
- return getValueByPath(form, create$1(name));
376
+ baselines.set(key, value);
287
377
  }
288
- function getValueByPath({ initialValues, parsedValues, values, deleted }, path) {
289
- const { key, value: segments } = path;
290
- if (values.has(key)) return values.get(key);
291
- if (deleted.has(key)) return void 0;
292
- for (let i = segments.length - 1; i > 0; i--) {
293
- const ancestorKey = JSON.stringify(segments.slice(0, i));
294
- if (values.has(ancestorKey)) {
295
- return get(values.get(ancestorKey), segments.slice(i));
296
- }
378
+ function pruneDirtyBaselines(form, { key }) {
379
+ const baselines = dirtyBaselines.get(form);
380
+ if (!baselines?.size) return;
381
+ const stem = `${key.slice(0, -1)},`;
382
+ for (const baselineKey of baselines.keys()) {
383
+ if (baselineKey.startsWith(stem)) baselines.delete(baselineKey);
297
384
  }
298
- return get(parsedValues ?? initialValues, segments);
299
- }
300
- function setValue(form, name, value, options) {
301
- setValueByPath(form, create$1(name), value, options);
302
385
  }
303
- function setValueByPath(form, path, value, options) {
304
- const { emitter, values, deleted } = form;
305
- values.set(path.key, value);
306
- pruneDescendantKeys(values, path);
307
- reviveBranch(deleted, path);
308
- pruneDirtyBaselines(form, path);
309
- if (options?.shouldDirty === false) setDirtyBaseline(form, path, value);
310
- bumpDirtyVersion(form);
311
- bumpValuesVersion(form);
312
- if (options?.shouldTouch) setTouchedByPath(form, path);
313
- if (options?.shouldValidate) form.validators.get(path.key)?.();
314
- emit(emitter, "change", path);
386
+ function clearDirtyBaselines(form, key) {
387
+ const baselines = dirtyBaselines.get(form);
388
+ if (!baselines) return;
389
+ if (key === void 0) baselines.clear();
390
+ else baselines.delete(key);
315
391
  }
316
- function seedValueByPath(form, path, value) {
317
- const { values, deleted } = form;
318
- values.set(path.key, value);
319
- pruneDescendantKeys(values, path);
320
- reviveBranch(deleted, path);
321
- pruneDirtyBaselines(form, path);
322
- bumpDirtyVersion(form);
323
- bumpValuesVersion(form);
392
+ const dirtyFieldsCaches = /* @__PURE__ */ new WeakMap();
393
+ function bumpDirtyVersion(form) {
394
+ const cache = dirtyFieldsCaches.get(form);
395
+ if (cache) cache.version++;
324
396
  }
325
- function emitChangeByPath({ emitter }, path) {
326
- emit(emitter, "change", path);
397
+ function isSegmentsPath(name) {
398
+ return name.some((part) => typeof part === "number");
327
399
  }
328
- function changeValue(form, name, value, options) {
329
- changeValueByPath(form, create$1(name), value, options);
400
+ function isFieldError(value) {
401
+ return !!value && typeof value === "object" && typeof value.type === "string" && typeof value.message === "string";
330
402
  }
331
- function changeValueByPath(form, path, value, options) {
332
- if (options?.shouldDirty === false) setDirtyBaseline(form, path, value);
333
- const change = form.changeHandlers.get(path.key);
334
- if (change) change(value);
335
- else setValueByPath(form, path, value, options);
403
+ function setParsedValues(form, values) {
404
+ if (values === void 0 || values === form.parsedValues) return;
405
+ form.parsedValues = values;
406
+ bumpValuesVersion(form);
407
+ emit(form.emitter, "change");
336
408
  }
409
+
410
+ const FORM_ERROR = "_form";
411
+ const VALIDATION_OUTCOME = /* @__PURE__ */ Symbol("validation-outcome");
337
412
  function getError(form, name) {
338
413
  return getErrorByPath(form, create$1(name));
339
414
  }
@@ -358,37 +433,16 @@
358
433
  function getFirstError({ errors }) {
359
434
  return errors.values().next().value?.[0]?.message;
360
435
  }
361
- function getFieldState(form, name) {
362
- const path = create$1(name);
363
- const { values, touched, validating } = form;
364
- const live = values.get(path.key);
365
- return {
366
- value: getValueByPath(form, path),
367
- error: getErrorByPath(form, path),
368
- errors: getFieldErrorsByPath(form, path),
369
- // Same rule as getDirtyFields, committed baselines included: the field
370
- // is dirty while its live value differs from its effective baseline.
371
- isDirty: values.has(path.key) && getDirtyBaseline(form, path.key, path.value) !== live,
372
- isTouched: touched.has(path.key),
373
- isValidating: validating.has(path.key)
374
- };
375
- }
376
- function unsetValidatingByPath({ emitter, validating }, path) {
377
- validating.delete(path.key);
378
- emit(emitter, "validating", path);
379
- }
380
- function setValidatingByPath({ emitter, validating }, path) {
381
- validating.add(path.key);
382
- emit(emitter, "validating", path);
436
+ function setError(form, name, error, options) {
437
+ setErrorByPath(form, create$1(name), error, options);
383
438
  }
384
- function setError(form, name, error) {
385
- setErrorByPath(form, create$1(name), error);
386
- }
387
- function setErrorByPath({ emitter, errors }, path, error) {
439
+ function setErrorByPath(form, path, error, options) {
440
+ const { emitter, errors } = form;
388
441
  const list = normalizeErrors(error);
389
442
  if (list) errors.set(path.key, list);
390
443
  else errors.delete(path.key);
391
444
  emit(emitter, "errors", path);
445
+ if (options?.shouldFocus) emit(emitter, "focusError", path.key);
392
446
  }
393
447
  function normalizeErrors(error) {
394
448
  if (typeof error === "string") {
@@ -430,19 +484,13 @@
430
484
  );
431
485
  }
432
486
  }
433
- function setTouched(form, name) {
434
- setTouchedByPath(form, create$1(name));
435
- }
436
- function setTouchedByPath({ emitter, touched }, path) {
437
- if (touched.has(path.key)) return;
438
- touched.add(path.key);
439
- emit(emitter, "touched", path);
440
- }
441
- function hasTouched(form, name) {
442
- return hasTouchedByPath(form, create$1(name));
487
+ function hasErrors({ errors }) {
488
+ return errors.size > 0;
443
489
  }
444
- function hasTouchedByPath({ touched }, path) {
445
- return touched.has(path.key);
490
+
491
+ function isFieldDirtyByPath(form, path) {
492
+ const live = form.values.get(path.key);
493
+ return form.values.has(path.key) && getDirtyBaseline(form, path.key, path.value) !== live;
446
494
  }
447
495
  function isDirty(form) {
448
496
  let dirty = false;
@@ -457,39 +505,6 @@
457
505
  if (getDirtyBaseline(form, key, path) !== value) fn(path.join("."));
458
506
  }
459
507
  }
460
- const dirtyBaselines = /* @__PURE__ */ new WeakMap();
461
- function getDirtyBaseline(form, key, segments) {
462
- const baselines = dirtyBaselines.get(form);
463
- if (baselines?.has(key)) return baselines.get(key);
464
- return get(form.initialValues, segments);
465
- }
466
- function setDirtyBaseline(form, { key }, value) {
467
- let baselines = dirtyBaselines.get(form);
468
- if (!baselines) {
469
- baselines = /* @__PURE__ */ new Map();
470
- dirtyBaselines.set(form, baselines);
471
- }
472
- baselines.set(key, value);
473
- }
474
- function pruneDirtyBaselines(form, { key }) {
475
- const baselines = dirtyBaselines.get(form);
476
- if (!baselines?.size) return;
477
- const stem = `${key.slice(0, -1)},`;
478
- for (const baselineKey of baselines.keys()) {
479
- if (baselineKey.startsWith(stem)) baselines.delete(baselineKey);
480
- }
481
- }
482
- function clearDirtyBaselines(form, key) {
483
- const baselines = dirtyBaselines.get(form);
484
- if (!baselines) return;
485
- if (key === void 0) baselines.clear();
486
- else baselines.delete(key);
487
- }
488
- const dirtyFieldsCaches = /* @__PURE__ */ new WeakMap();
489
- function bumpDirtyVersion(form) {
490
- const cache = dirtyFieldsCaches.get(form);
491
- if (cache) cache.version++;
492
- }
493
508
  function computeDirtyFields(form) {
494
509
  const dirtyFields = {};
495
510
  forEachDirtyField(form, (key) => {
@@ -514,6 +529,21 @@
514
529
  }
515
530
  return cache.result;
516
531
  }
532
+
533
+ function setTouched(form, name) {
534
+ setTouchedByPath(form, create$1(name));
535
+ }
536
+ function setTouchedByPath({ emitter, touched }, path) {
537
+ if (touched.has(path.key)) return;
538
+ touched.add(path.key);
539
+ emit(emitter, "touched", path);
540
+ }
541
+ function hasTouched(form, name) {
542
+ return hasTouchedByPath(form, create$1(name));
543
+ }
544
+ function hasTouchedByPath({ touched }, path) {
545
+ return touched.has(path.key);
546
+ }
517
547
  function getTouchedFields({ touched }) {
518
548
  return Array.from(
519
549
  touched,
@@ -523,18 +553,102 @@
523
553
  function isTouched({ touched }) {
524
554
  return touched.size > 0;
525
555
  }
526
- function removeField(form, name) {
527
- removeFieldByPath(form, create$1(name));
556
+
557
+ function getValues(form) {
558
+ let cache = valuesCaches.get(form);
559
+ if (!cache) {
560
+ cache = { version: 0, result: computeValues(form) };
561
+ valuesCaches.set(form, cache);
562
+ } else if (cache.version > 0) {
563
+ cache.result = computeValues(form);
564
+ cache.version = 0;
565
+ }
566
+ return cache.result;
567
+ }
568
+ function computeValues(form) {
569
+ const { initialValues, parsedValues, values, deleted } = form;
570
+ const owned = /* @__PURE__ */ new Set();
571
+ let merged = parsedValues ?? initialValues;
572
+ for (const [key, value] of values) {
573
+ merged = setOwned(merged, JSON.parse(key), value, owned);
574
+ }
575
+ for (const key of deleted) {
576
+ merged = unset(merged, JSON.parse(key));
577
+ }
578
+ return merged;
579
+ }
580
+ function getValue(form, name) {
581
+ return getValueByPath(form, create$1(name));
582
+ }
583
+ function getValueByPath({ initialValues, parsedValues, values, deleted }, path) {
584
+ const { key, value: segments } = path;
585
+ if (values.has(key)) return values.get(key);
586
+ if (deleted.has(key)) return void 0;
587
+ for (let i = segments.length - 1; i > 0; i--) {
588
+ const ancestorKey = JSON.stringify(segments.slice(0, i));
589
+ if (values.has(ancestorKey)) {
590
+ return get(values.get(ancestorKey), segments.slice(i));
591
+ }
592
+ }
593
+ return get(parsedValues ?? initialValues, segments);
594
+ }
595
+ function setValue(form, name, value, options) {
596
+ setValueByPath(form, create$1(name), value, options);
597
+ }
598
+ function setValueByPath(form, path, value, options) {
599
+ const { emitter, values, deleted } = form;
600
+ const next = typeof value === "function" ? value(getValueByPath(form, path)) : value;
601
+ values.set(path.key, next);
602
+ pruneDescendantKeys(values, path);
603
+ reviveBranch(deleted, path);
604
+ pruneDirtyBaselines(form, path);
605
+ if (options?.shouldDirty === false) setDirtyBaseline(form, path, next);
606
+ bumpDirtyVersion(form);
607
+ bumpValuesVersion(form);
608
+ if (options?.shouldTouch) setTouchedByPath(form, path);
609
+ if (options?.shouldValidate) form.validators.get(path.key)?.();
610
+ emit(emitter, "change", path);
611
+ }
612
+ function seedValueByPath(form, path, value) {
613
+ const { values, deleted } = form;
614
+ values.set(path.key, value);
615
+ pruneDescendantKeys(values, path);
616
+ reviveBranch(deleted, path);
617
+ pruneDirtyBaselines(form, path);
618
+ bumpDirtyVersion(form);
619
+ bumpValuesVersion(form);
620
+ }
621
+ function emitChangeByPath({ emitter }, path) {
622
+ emit(emitter, "change", path);
623
+ }
624
+ function getFieldState(form, name) {
625
+ const path = create$1(name);
626
+ const { touched, validating } = form;
627
+ return {
628
+ value: getValueByPath(form, path),
629
+ error: getErrorByPath(form, path),
630
+ errors: getFieldErrorsByPath(form, path),
631
+ // The shared per-field rule (committed baselines included): the field
632
+ // is dirty while its live value differs from its effective baseline.
633
+ isDirty: isFieldDirtyByPath(form, path),
634
+ isTouched: touched.has(path.key),
635
+ isValidating: validating.has(path.key)
636
+ };
637
+ }
638
+ function removeField(form, name, options) {
639
+ removeFieldByPath(form, create$1(name), options);
528
640
  }
529
- function removeFieldByPath(form, path) {
641
+ function removeFieldByPath(form, path, options) {
530
642
  const { key, value: segments } = path;
531
643
  const { emitter, values, touched, errors, validating, deleted } = form;
532
- values.delete(key);
533
- touched.delete(key);
534
- errors.delete(key);
644
+ if (!options?.keepValue && !options?.keepDirty) {
645
+ values.delete(key);
646
+ clearDirtyBaselines(form, key);
647
+ if (!hasLiveBranch(values, segments)) deleted.add(key);
648
+ }
649
+ if (!options?.keepTouched) touched.delete(key);
650
+ if (!options?.keepError) errors.delete(key);
535
651
  validating.delete(key);
536
- clearDirtyBaselines(form, key);
537
- if (!hasLiveBranch(values, segments)) deleted.add(key);
538
652
  bumpDirtyVersion(form);
539
653
  bumpValuesVersion(form);
540
654
  emit(emitter, "change", path);
@@ -580,17 +694,37 @@
580
694
  bumpValuesVersion(form);
581
695
  emit(form.emitter, "change");
582
696
  }
697
+ function collectValueLeaves(node, segments, out) {
698
+ if (node !== null && typeof node === "object") {
699
+ if (Array.isArray(node)) {
700
+ for (let i = 0; i < node.length; i++) {
701
+ collectValueLeaves(node[i], [...segments, i], out);
702
+ }
703
+ return;
704
+ }
705
+ const keys = Object.keys(node);
706
+ if (keys.length > 0) {
707
+ for (const k of keys) {
708
+ collectValueLeaves(node[k], [...segments, k], out);
709
+ }
710
+ return;
711
+ }
712
+ }
713
+ out.push({ segments, value: node });
714
+ }
583
715
  function reset(form, initialValues, options) {
584
- const dirtyValues = [];
585
- if (options?.keepDirtyValues) {
716
+ const keptValues = [];
717
+ if (options?.keepValues) {
718
+ collectValueLeaves(getValues(form), [], keptValues);
719
+ } else if (options?.keepDirtyValues) {
586
720
  for (const [key, value] of form.values) {
587
721
  const segments = JSON.parse(key);
588
722
  if (getDirtyBaseline(form, key, segments) !== value) {
589
- dirtyValues.push({ segments, value });
723
+ keptValues.push({ segments, value });
590
724
  }
591
725
  }
592
726
  }
593
- form.initialValues = initialValues;
727
+ form.initialValues = options?.keepDefaultValues ? form.initialValues : initialValues ?? form.initialValues;
594
728
  form.parsedValues = void 0;
595
729
  if (!options?.keepErrors) clearErrors(form);
596
730
  const { emitter, touched, values, deleted, validating } = form;
@@ -601,10 +735,11 @@
601
735
  validating.clear();
602
736
  if (!options?.keepIsSubmitting) form.isSubmitting = false;
603
737
  if (!options?.keepSubmitCount) form.submitCount = 0;
604
- if (!options?.keepIsSubmitted) form.isSubmitSuccessful = void 0;
738
+ if (!options?.keepIsSubmitted) form.isSubmitted = false;
739
+ if (!options?.keepIsSubmitSuccessful) form.isSubmitSuccessful = void 0;
605
740
  bumpDirtyVersion(form);
606
741
  bumpValuesVersion(form);
607
- for (const { segments, value } of dirtyValues) {
742
+ for (const { segments, value } of keptValues) {
608
743
  setValueByPath(form, create$1(segments), value);
609
744
  }
610
745
  emit(emitter, "change");
@@ -639,10 +774,151 @@
639
774
  bumpDirtyVersion(form);
640
775
  bumpValuesVersion(form);
641
776
  }
642
- function hasErrors({ errors }) {
643
- return errors.size > 0;
777
+
778
+ function unsetValidatingByPath({ emitter, validating }, path) {
779
+ validating.delete(path.key);
780
+ emit(emitter, "validating", path);
781
+ }
782
+ function setValidatingByPath({ emitter, validating }, path) {
783
+ validating.add(path.key);
784
+ emit(emitter, "validating", path);
785
+ }
786
+ function registerValidatorByPath(form, path, registration) {
787
+ let timer = null;
788
+ let controller = null;
789
+ let marked = false;
790
+ let lock = null;
791
+ let errorSource = null;
792
+ const hasErrors2 = (errors) => errors !== void 0 && !(Array.isArray(errors) && errors.length === 0);
793
+ const mark = () => {
794
+ if (marked) return;
795
+ marked = true;
796
+ setValidatingByPath(form, path);
797
+ };
798
+ const unmark = () => {
799
+ if (!marked) return;
800
+ marked = false;
801
+ unsetValidatingByPath(form, path);
802
+ };
803
+ const runSync = () => {
804
+ const sync = registration.sync();
805
+ if (!sync) return false;
806
+ const errors = sync(getValueByPath(form, path), { form, path });
807
+ if (!hasErrors2(errors)) {
808
+ if (!registration.validate() || errorSource === "sync") {
809
+ setErrorByPath(form, path, void 0);
810
+ errorSource = null;
811
+ }
812
+ return false;
813
+ }
814
+ setErrorByPath(form, path, errors);
815
+ errorSource = "sync";
816
+ return true;
817
+ };
818
+ const collectSyncErrors = () => {
819
+ const sync = registration.sync();
820
+ if (!sync) return null;
821
+ const errors = sync(getValueByPath(form, path), { form, path });
822
+ if (errors === void 0) return null;
823
+ const list = Array.isArray(errors) ? errors : [errors];
824
+ return list.length ? list : null;
825
+ };
826
+ const land = (result) => {
827
+ if (registration.asyncAlways?.()) {
828
+ const gate = collectSyncErrors();
829
+ const own = result === void 0 ? [] : Array.isArray(result) ? result : [result];
830
+ setErrorByPath(form, path, [...gate ?? [], ...own]);
831
+ errorSource = hasErrors2(result) ? "validator" : gate ? "sync" : null;
832
+ } else {
833
+ setErrorByPath(form, path, result);
834
+ errorSource = hasErrors2(result) ? "validator" : null;
835
+ }
836
+ };
837
+ const supersede = () => {
838
+ if (timer !== null) {
839
+ clearTimeout(timer);
840
+ timer = null;
841
+ }
842
+ controller?.abort();
843
+ lock = {};
844
+ };
845
+ const runValidator = () => {
846
+ const fn = registration.validate();
847
+ if (!fn) {
848
+ unmark();
849
+ return;
850
+ }
851
+ controller?.abort();
852
+ controller = new AbortController();
853
+ const round = lock = {};
854
+ let result;
855
+ try {
856
+ result = fn(getValueByPath(form, path), {
857
+ form,
858
+ path,
859
+ signal: controller.signal
860
+ });
861
+ } catch (e) {
862
+ unmark();
863
+ throw e;
864
+ }
865
+ if (!isPromise(result)) {
866
+ land(result);
867
+ unmark();
868
+ return;
869
+ }
870
+ mark();
871
+ result.then(
872
+ (error) => {
873
+ if (lock === round) {
874
+ land(error);
875
+ }
876
+ }
877
+ ).catch(() => {
878
+ }).finally(() => {
879
+ if (lock === round) {
880
+ unmark();
881
+ lock = null;
882
+ }
883
+ });
884
+ };
885
+ const run = () => {
886
+ timer = null;
887
+ if (runSync() && !registration.asyncAlways?.()) {
888
+ supersede();
889
+ unmark();
890
+ return;
891
+ }
892
+ runValidator();
893
+ };
894
+ const kick = () => {
895
+ if (runSync() && !registration.asyncAlways?.()) {
896
+ supersede();
897
+ unmark();
898
+ return;
899
+ }
900
+ if (!registration.validate()) return;
901
+ const debounce = registration.debounce();
902
+ if (debounce > 0) {
903
+ if (timer !== null) clearTimeout(timer);
904
+ else mark();
905
+ timer = setTimeout(run, debounce);
906
+ return;
907
+ }
908
+ runValidator();
909
+ };
910
+ form.validators.set(path.key, kick);
911
+ return () => {
912
+ form.validators.delete(path.key);
913
+ if (timer !== null) {
914
+ clearTimeout(timer);
915
+ timer = null;
916
+ }
917
+ unmark();
918
+ controller?.abort();
919
+ };
644
920
  }
645
- async function trigger(form, name) {
921
+ async function trigger(form, name, options) {
646
922
  const settle = (keys2) => waitUntil(
647
923
  form.emitter,
648
924
  "validating",
@@ -653,18 +929,25 @@
653
929
  form.validators.forEach((validator) => validator());
654
930
  await settle();
655
931
  if (form.validate) await runFormValidate(form);
932
+ if (options?.shouldTouch) touchKeys(form, [...form.validators.keys()]);
933
+ if (options?.shouldFocus) {
934
+ const firstKey = form.errors.keys().next().value;
935
+ if (firstKey !== void 0) emit(form.emitter, "focusError", firstKey);
936
+ }
656
937
  return !hasErrors(form);
657
938
  }
658
939
  const keys = typeof name === "string" || isSegmentsPath(name) ? [create$1(name).key] : name.map((one) => create$1(one).key);
659
940
  keys.forEach((key) => form.validators.get(key)?.());
660
941
  await settle(keys);
942
+ if (options?.shouldTouch) touchKeys(form, keys);
943
+ if (options?.shouldFocus) {
944
+ const firstKey = keys.find((key) => form.errors.has(key));
945
+ if (firstKey !== void 0) emit(form.emitter, "focusError", firstKey);
946
+ }
661
947
  return keys.every((key) => !form.errors.has(key));
662
948
  }
663
- function isSegmentsPath(name) {
664
- return name.some((part) => typeof part === "number");
665
- }
666
- function isFieldError(value) {
667
- return !!value && typeof value === "object" && typeof value.type === "string" && typeof value.message === "string";
949
+ function touchKeys(form, keys) {
950
+ keys.forEach((key) => setTouchedByPath(form, create$1(JSON.parse(key))));
668
951
  }
669
952
  function setFormErrors(form, result, segments = [], footprint) {
670
953
  Object.entries(result).forEach(([key, value]) => {
@@ -694,12 +977,6 @@
694
977
  const stored = form.errors.get(path.key);
695
978
  if (stored) footprint.set(path.key, stored);
696
979
  }
697
- function setParsedValues(form, values) {
698
- if (values === void 0 || values === form.parsedValues) return;
699
- form.parsedValues = values;
700
- bumpValuesVersion(form);
701
- emit(form.emitter, "change");
702
- }
703
980
  function applyValidateResult(form, result) {
704
981
  const footprint = form.validateDeps ? getFormErrorFootprint(form) : void 0;
705
982
  if (footprint) {
@@ -897,6 +1174,55 @@
897
1174
  async function validate(form) {
898
1175
  return ensureValidate(form).catch((e) => e.message);
899
1176
  }
1177
+
1178
+ const fieldModes = /* @__PURE__ */ new WeakMap();
1179
+ function changeValue(form, name, value, options) {
1180
+ changeValueByPath(form, create$1(name), value, options);
1181
+ }
1182
+ function changeValueByPath(form, path, value, options) {
1183
+ if (options?.shouldDirty === false) setDirtyBaseline(form, path, value);
1184
+ if (fieldModes.get(form)?.get(path.key)) {
1185
+ userChangeByPath(form, path, value);
1186
+ } else {
1187
+ setValueByPath(form, path, value, options);
1188
+ }
1189
+ }
1190
+ function registerFieldMode(form, path, mode) {
1191
+ let modes = fieldModes.get(form);
1192
+ if (!modes) {
1193
+ modes = /* @__PURE__ */ new Map();
1194
+ fieldModes.set(form, modes);
1195
+ }
1196
+ const displaced = modes.has(path.key);
1197
+ const token = {};
1198
+ modes.set(path.key, { mode, token });
1199
+ return { token, displaced };
1200
+ }
1201
+ function unregisterFieldMode(form, path, token) {
1202
+ const modes = fieldModes.get(form);
1203
+ const entry = modes?.get(path.key);
1204
+ if (modes && entry && entry.token === token) modes.delete(path.key);
1205
+ }
1206
+ function runUserChangeGate(form, path, mode) {
1207
+ if (mode === "onChange" || mode === "all" || mode === "onTouched" && hasTouchedByPath(form, path) || getFieldErrorsByPath(form, path).length > 0 && form.reValidateMode === "onChange")
1208
+ form.validators.get(path.key)?.();
1209
+ revalidateFormOnChange(form, path, mode);
1210
+ revalidateDependentsOnChange(form, path, mode);
1211
+ }
1212
+ function userChangeByPath(form, path, value) {
1213
+ setValueByPath(form, path, value);
1214
+ const entry = fieldModes.get(form)?.get(path.key);
1215
+ if (entry) runUserChangeGate(form, path, entry.mode ?? form.mode);
1216
+ }
1217
+ function userBlur(form, path) {
1218
+ setTouchedByPath(form, path);
1219
+ const entry = fieldModes.get(form)?.get(path.key);
1220
+ if (!entry) return;
1221
+ const mode = entry.mode ?? form.mode;
1222
+ if (mode === "onBlur" || mode === "onTouched" || mode === "all" || getFieldErrorsByPath(form, path).length > 0 && form.reValidateMode === "onBlur")
1223
+ form.validators.get(path.key)?.();
1224
+ }
1225
+
900
1226
  function setIsSubmitting(form, value) {
901
1227
  form.isSubmitting = value;
902
1228
  emit(form.emitter, "submitting");
@@ -913,6 +1239,10 @@
913
1239
  form.disabled = value;
914
1240
  emit(form.emitter, "disabled");
915
1241
  }
1242
+ function setStatus(form, value) {
1243
+ form.status = value;
1244
+ emit(form.emitter, "status");
1245
+ }
916
1246
  function nameToPath(name) {
917
1247
  if (name.startsWith("[")) {
918
1248
  try {
@@ -943,6 +1273,7 @@
943
1273
  onSubmit,
944
1274
  onValidSubmit,
945
1275
  onInvalidSubmit,
1276
+ onAction,
946
1277
  shouldFocusError = true
947
1278
  } = options ?? {};
948
1279
  return async (e) => {
@@ -950,6 +1281,7 @@
950
1281
  e.preventDefault();
951
1282
  }
952
1283
  const formEl = e?.currentTarget;
1284
+ form.isSubmitted = true;
953
1285
  setIsSubmitting(form, true);
954
1286
  incrementSubmitCount(form);
955
1287
  const values = getValues(form);
@@ -979,6 +1311,7 @@
979
1311
  const submitted = getValues(form);
980
1312
  if (onSubmit) await onSubmit(submitted, e);
981
1313
  if (onValidSubmit) await onValidSubmit(submitted, e);
1314
+ if (onAction) await onAction(submitted, e);
982
1315
  setSubmitSuccessful(form, true);
983
1316
  } catch {
984
1317
  setSubmitSuccessful(form, false);
@@ -987,12 +1320,62 @@
987
1320
  }
988
1321
  };
989
1322
  }
1323
+
990
1324
  function setFocus(form, name, options) {
991
1325
  const { key } = create$1(name);
992
1326
  if (options) emit(form.emitter, "focusError", key, options);
993
1327
  else emit(form.emitter, "focusError", key);
994
1328
  }
995
1329
 
1330
+ function create(options) {
1331
+ const emitter = create$2();
1332
+ _setMaxListeners(emitter, 0);
1333
+ let source = options?.initialValues ?? {};
1334
+ if (typeof source === "function") source = source();
1335
+ const form = {
1336
+ emitter,
1337
+ ...options,
1338
+ mode: options?.mode ?? "onSubmit",
1339
+ reValidateMode: options?.reValidateMode ?? "onChange",
1340
+ disabled: options?.disabled ?? false,
1341
+ validateOnMount: options?.validateOnMount ?? false,
1342
+ asyncAlways: options?.asyncAlways ?? false,
1343
+ validateDeps: options?.validateDeps ? new Set(options.validateDeps.map((dep) => create$1(dep).key)) : void 0,
1344
+ initialValues: {},
1345
+ values: /* @__PURE__ */ new Map(),
1346
+ deleted: /* @__PURE__ */ new Set(),
1347
+ errors: /* @__PURE__ */ new Map(),
1348
+ touched: /* @__PURE__ */ new Set(),
1349
+ validators: /* @__PURE__ */ new Map(),
1350
+ validating: /* @__PURE__ */ new Set(),
1351
+ parsedValues: void 0,
1352
+ isSubmitting: false,
1353
+ isSubmitted: false,
1354
+ submitCount: 0,
1355
+ isSubmitSuccessful: void 0,
1356
+ isLoading: false,
1357
+ status: void 0
1358
+ };
1359
+ if (isPromise(source)) {
1360
+ form.isLoading = true;
1361
+ emit(emitter, "loading");
1362
+ Promise.resolve(source).then(
1363
+ (resolved) => {
1364
+ setInitialValues(form, resolved ?? {});
1365
+ form.isLoading = false;
1366
+ emit(emitter, "loading");
1367
+ },
1368
+ (error) => {
1369
+ form.isLoading = false;
1370
+ emit(emitter, "loading");
1371
+ }
1372
+ );
1373
+ } else {
1374
+ form.initialValues = source;
1375
+ }
1376
+ return form;
1377
+ }
1378
+
996
1379
  function defaultMessage(type, bound) {
997
1380
  switch (type) {
998
1381
  case "required":
@@ -1012,9 +1395,9 @@
1012
1395
  }
1013
1396
  }
1014
1397
  function rulesToValidator(rules) {
1015
- return (value) => {
1398
+ return (value, meta) => {
1016
1399
  if (rules.required) {
1017
- if (value === "" || value === void 0 || value === null) {
1400
+ if (value === "" || value === void 0 || value === null || Array.isArray(value) && value.length === 0) {
1018
1401
  return [
1019
1402
  {
1020
1403
  type: "required",
@@ -1037,13 +1420,14 @@
1037
1420
  errors.push({ type: "max", message: message("max", rules.max) });
1038
1421
  }
1039
1422
  }
1040
- if (rules.minLength !== void 0 && typeof value === "string" && value.length < rules.minLength) {
1423
+ const isSized = typeof value === "string" || Array.isArray(value);
1424
+ if (rules.minLength !== void 0 && isSized && value.length < rules.minLength) {
1041
1425
  errors.push({
1042
1426
  type: "minLength",
1043
1427
  message: message("minLength", rules.minLength)
1044
1428
  });
1045
1429
  }
1046
- if (rules.maxLength !== void 0 && typeof value === "string" && value.length > rules.maxLength) {
1430
+ if (rules.maxLength !== void 0 && isSized && value.length > rules.maxLength) {
1047
1431
  errors.push({
1048
1432
  type: "maxLength",
1049
1433
  message: message("maxLength", rules.maxLength)
@@ -1056,207 +1440,32 @@
1056
1440
  message: rules.messages?.pattern ?? rules.pattern.message ?? defaultMessage("pattern")
1057
1441
  });
1058
1442
  }
1443
+ if (rules.validate !== void 0) {
1444
+ const fns = typeof rules.validate === "function" ? { validate: rules.validate } : rules.validate;
1445
+ for (const [type, fn] of Object.entries(fns)) {
1446
+ const result = fn(value, meta);
1447
+ if (result === void 0) continue;
1448
+ for (const entry of Array.isArray(result) ? result : [result]) {
1449
+ errors.push(
1450
+ typeof entry === "string" ? { type, message: entry } : { ...entry, type }
1451
+ );
1452
+ }
1453
+ }
1454
+ }
1059
1455
  return errors.length ? errors : void 0;
1060
1456
  };
1061
1457
  }
1062
-
1063
- var shim = {exports: {}};
1064
-
1065
- var useSyncExternalStoreShim_production = {};
1066
-
1067
- /**
1068
- * @license React
1069
- * use-sync-external-store-shim.production.js
1070
- *
1071
- * Copyright (c) Meta Platforms, Inc. and affiliates.
1072
- *
1073
- * This source code is licensed under the MIT license found in the
1074
- * LICENSE file in the root directory of this source tree.
1075
- */
1076
-
1077
- var hasRequiredUseSyncExternalStoreShim_production;
1078
-
1079
- function requireUseSyncExternalStoreShim_production () {
1080
- if (hasRequiredUseSyncExternalStoreShim_production) return useSyncExternalStoreShim_production;
1081
- hasRequiredUseSyncExternalStoreShim_production = 1;
1082
- var React$1 = React;
1083
- function is(x, y) {
1084
- return (x === y && (0 !== x || 1 / x === 1 / y)) || (x !== x && y !== y);
1085
- }
1086
- var objectIs = "function" === typeof Object.is ? Object.is : is,
1087
- useState = React$1.useState,
1088
- useEffect = React$1.useEffect,
1089
- useLayoutEffect = React$1.useLayoutEffect,
1090
- useDebugValue = React$1.useDebugValue;
1091
- function useSyncExternalStore$2(subscribe, getSnapshot) {
1092
- var value = getSnapshot(),
1093
- _useState = useState({ inst: { value: value, getSnapshot: getSnapshot } }),
1094
- inst = _useState[0].inst,
1095
- forceUpdate = _useState[1];
1096
- useLayoutEffect(
1097
- function () {
1098
- inst.value = value;
1099
- inst.getSnapshot = getSnapshot;
1100
- checkIfSnapshotChanged(inst) && forceUpdate({ inst: inst });
1101
- },
1102
- [subscribe, value, getSnapshot]
1103
- );
1104
- useEffect(
1105
- function () {
1106
- checkIfSnapshotChanged(inst) && forceUpdate({ inst: inst });
1107
- return subscribe(function () {
1108
- checkIfSnapshotChanged(inst) && forceUpdate({ inst: inst });
1109
- });
1110
- },
1111
- [subscribe]
1112
- );
1113
- useDebugValue(value);
1114
- return value;
1115
- }
1116
- function checkIfSnapshotChanged(inst) {
1117
- var latestGetSnapshot = inst.getSnapshot;
1118
- inst = inst.value;
1119
- try {
1120
- var nextValue = latestGetSnapshot();
1121
- return !objectIs(inst, nextValue);
1122
- } catch (error) {
1123
- return true;
1124
- }
1125
- }
1126
- function useSyncExternalStore$1(subscribe, getSnapshot) {
1127
- return getSnapshot();
1128
- }
1129
- var shim =
1130
- "undefined" === typeof window ||
1131
- "undefined" === typeof window.document ||
1132
- "undefined" === typeof window.document.createElement
1133
- ? useSyncExternalStore$1
1134
- : useSyncExternalStore$2;
1135
- useSyncExternalStoreShim_production.useSyncExternalStore =
1136
- void 0 !== React$1.useSyncExternalStore ? React$1.useSyncExternalStore : shim;
1137
- return useSyncExternalStoreShim_production;
1138
- }
1139
-
1140
- var useSyncExternalStoreShim_development = {};
1141
-
1142
- /**
1143
- * @license React
1144
- * use-sync-external-store-shim.development.js
1145
- *
1146
- * Copyright (c) Meta Platforms, Inc. and affiliates.
1147
- *
1148
- * This source code is licensed under the MIT license found in the
1149
- * LICENSE file in the root directory of this source tree.
1150
- */
1151
-
1152
- var hasRequiredUseSyncExternalStoreShim_development;
1153
-
1154
- function requireUseSyncExternalStoreShim_development () {
1155
- if (hasRequiredUseSyncExternalStoreShim_development) return useSyncExternalStoreShim_development;
1156
- hasRequiredUseSyncExternalStoreShim_development = 1;
1157
- "production" !== process.env.NODE_ENV &&
1158
- (function () {
1159
- function is(x, y) {
1160
- return (x === y && (0 !== x || 1 / x === 1 / y)) || (x !== x && y !== y);
1161
- }
1162
- function useSyncExternalStore$2(subscribe, getSnapshot) {
1163
- didWarnOld18Alpha ||
1164
- void 0 === React$1.startTransition ||
1165
- ((didWarnOld18Alpha = true),
1166
- console.error(
1167
- "You are using an outdated, pre-release alpha of React 18 that does not support useSyncExternalStore. The use-sync-external-store shim will not work correctly. Upgrade to a newer pre-release."
1168
- ));
1169
- var value = getSnapshot();
1170
- if (!didWarnUncachedGetSnapshot) {
1171
- var cachedValue = getSnapshot();
1172
- objectIs(value, cachedValue) ||
1173
- (console.error(
1174
- "The result of getSnapshot should be cached to avoid an infinite loop"
1175
- ),
1176
- (didWarnUncachedGetSnapshot = true));
1177
- }
1178
- cachedValue = useState({
1179
- inst: { value: value, getSnapshot: getSnapshot }
1180
- });
1181
- var inst = cachedValue[0].inst,
1182
- forceUpdate = cachedValue[1];
1183
- useLayoutEffect(
1184
- function () {
1185
- inst.value = value;
1186
- inst.getSnapshot = getSnapshot;
1187
- checkIfSnapshotChanged(inst) && forceUpdate({ inst: inst });
1188
- },
1189
- [subscribe, value, getSnapshot]
1190
- );
1191
- useEffect(
1192
- function () {
1193
- checkIfSnapshotChanged(inst) && forceUpdate({ inst: inst });
1194
- return subscribe(function () {
1195
- checkIfSnapshotChanged(inst) && forceUpdate({ inst: inst });
1196
- });
1197
- },
1198
- [subscribe]
1199
- );
1200
- useDebugValue(value);
1201
- return value;
1202
- }
1203
- function checkIfSnapshotChanged(inst) {
1204
- var latestGetSnapshot = inst.getSnapshot;
1205
- inst = inst.value;
1206
- try {
1207
- var nextValue = latestGetSnapshot();
1208
- return !objectIs(inst, nextValue);
1209
- } catch (error) {
1210
- return true;
1211
- }
1212
- }
1213
- function useSyncExternalStore$1(subscribe, getSnapshot) {
1214
- return getSnapshot();
1215
- }
1216
- "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
1217
- "function" ===
1218
- typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart &&
1219
- __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
1220
- var React$1 = React,
1221
- objectIs = "function" === typeof Object.is ? Object.is : is,
1222
- useState = React$1.useState,
1223
- useEffect = React$1.useEffect,
1224
- useLayoutEffect = React$1.useLayoutEffect,
1225
- useDebugValue = React$1.useDebugValue,
1226
- didWarnOld18Alpha = false,
1227
- didWarnUncachedGetSnapshot = false,
1228
- shim =
1229
- "undefined" === typeof window ||
1230
- "undefined" === typeof window.document ||
1231
- "undefined" === typeof window.document.createElement
1232
- ? useSyncExternalStore$1
1233
- : useSyncExternalStore$2;
1234
- useSyncExternalStoreShim_development.useSyncExternalStore =
1235
- void 0 !== React$1.useSyncExternalStore ? React$1.useSyncExternalStore : shim;
1236
- "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
1237
- "function" ===
1238
- typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&
1239
- __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error());
1240
- })();
1241
- return useSyncExternalStoreShim_development;
1242
- }
1243
-
1244
- var hasRequiredShim;
1245
-
1246
- function requireShim () {
1247
- if (hasRequiredShim) return shim.exports;
1248
- hasRequiredShim = 1;
1249
-
1250
- if (process.env.NODE_ENV === 'production') {
1251
- shim.exports = requireUseSyncExternalStoreShim_production();
1252
- } else {
1253
- shim.exports = requireUseSyncExternalStoreShim_development();
1254
- }
1255
- return shim.exports;
1458
+ function rulesToConstraintAttrs(rules) {
1459
+ const attrs = {};
1460
+ if (rules.required) attrs.required = true;
1461
+ if (rules.min !== void 0) attrs.min = rules.min;
1462
+ if (rules.max !== void 0) attrs.max = rules.max;
1463
+ if (rules.minLength !== void 0) attrs.minLength = rules.minLength;
1464
+ if (rules.maxLength !== void 0) attrs.maxLength = rules.maxLength;
1465
+ if (rules.pattern) attrs.pattern = rules.pattern.value.source;
1466
+ return attrs;
1256
1467
  }
1257
1468
 
1258
- var shimExports = requireShim();
1259
-
1260
1469
  function isDescendant(key, ancestorKey) {
1261
1470
  return key.startsWith(`${ancestorKey.slice(0, -1)},`);
1262
1471
  }
@@ -1302,6 +1511,9 @@
1302
1511
  seededRef.current = { done: false, source: void 0 };
1303
1512
  React.useEffect(() => {
1304
1513
  if (initialValues === void 0) return;
1514
+ if (typeof initialValues === "function" || isPromise(initialValues)) {
1515
+ return;
1516
+ }
1305
1517
  const seeded = seededRef.current;
1306
1518
  if (seeded.done && (seeded.source === initialValues || isEqual(seeded.source, initialValues))) {
1307
1519
  return;
@@ -1324,14 +1536,29 @@
1324
1536
  seeded.source = values;
1325
1537
  setInitialValues(form, values);
1326
1538
  }, [form, values]);
1539
+ React.useEffect(() => {
1540
+ if (!form.validateOnMount || !form.validate) return;
1541
+ const run = () => {
1542
+ void runFormValidate(form).catch(() => void 0);
1543
+ };
1544
+ if (!form.isLoading) {
1545
+ run();
1546
+ return;
1547
+ }
1548
+ return on(form.emitter, "loading", () => {
1549
+ run();
1550
+ });
1551
+ }, [form]);
1327
1552
  return form;
1328
1553
  }
1329
- function useWatchCore(subscribeFactory, getter) {
1554
+ function useWatchCore(subscribeFactory, getter, isEqual2) {
1330
1555
  const cacheRef = React.useRef(null);
1331
1556
  if (cacheRef.current === null) cacheRef.current = { hasValue: false };
1332
1557
  const cache = cacheRef.current;
1333
1558
  const getterRef = React.useRef(getter);
1334
1559
  getterRef.current = getter;
1560
+ const isEqualRef = React.useRef(isEqual2);
1561
+ isEqualRef.current = isEqual2;
1335
1562
  const getSnapshot = React.useCallback(() => {
1336
1563
  if (!cache.hasValue) {
1337
1564
  cache.value = getterRef.current();
@@ -1343,6 +1570,14 @@
1343
1570
  (notify) => {
1344
1571
  cache.hasValue = false;
1345
1572
  const invalidate = () => {
1573
+ const compare = isEqualRef.current;
1574
+ if (compare && cache.hasValue) {
1575
+ const next = getterRef.current();
1576
+ if (compare(cache.value, next)) return;
1577
+ cache.value = next;
1578
+ notify();
1579
+ return;
1580
+ }
1346
1581
  cache.hasValue = false;
1347
1582
  notify();
1348
1583
  };
@@ -1350,27 +1585,35 @@
1350
1585
  },
1351
1586
  [subscribeFactory, cache]
1352
1587
  );
1353
- return shimExports.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
1588
+ return React.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
1354
1589
  }
1355
- function useWatch(emitter, event, getter) {
1590
+ function useWatch(formOrEmitter, event, getter, isEqual2) {
1591
+ const emitter = "emitter" in formOrEmitter ? formOrEmitter.emitter : formOrEmitter;
1356
1592
  const subscribeFactory = React.useCallback(
1357
1593
  (invalidate) => on(emitter, event, invalidate),
1358
1594
  [emitter, event]
1359
1595
  );
1360
- return useWatchCore(subscribeFactory, getter);
1596
+ return useWatchCore(subscribeFactory, getter, isEqual2);
1361
1597
  }
1362
- function useValue(form, name) {
1363
- return useValueByPath(form, create$1(name));
1598
+ function useValue(form, name, options) {
1599
+ return useValueByPath(form, create$1(name), options);
1364
1600
  }
1365
- function useValueByPath(form, path) {
1601
+ function useValueByPath(form, path, options) {
1366
1602
  const { emitter } = form;
1367
1603
  const { key } = path;
1604
+ const scope = options?.exact === false ? "branch" : "leaf";
1368
1605
  const subscribeFactory = React.useCallback(
1369
- (invalidate) => onPathEvent(emitter, "change", path, "leaf", invalidate),
1606
+ (invalidate) => onPathEvent(emitter, "change", path, scope, invalidate),
1370
1607
  // eslint-disable-next-line react-hooks/exhaustive-deps -- deps are `key` on purpose: useValue creates a fresh Path per render, so the object must stay out of the deps while the key string pins the subscription
1371
- [emitter, key]
1608
+ [emitter, key, scope]
1372
1609
  );
1373
- return useWatchCore(subscribeFactory, getValueByPath.bind(null, form, path));
1610
+ return useWatchCore(subscribeFactory, () => {
1611
+ if (options?.exact === false) {
1612
+ return get(getValues(form), path.value);
1613
+ }
1614
+ const value = getValueByPath(form, path);
1615
+ return value === void 0 ? options?.defaultValue : value;
1616
+ });
1374
1617
  }
1375
1618
  function useTouched(form, name) {
1376
1619
  return useTouchedByPath(form, create$1(name));
@@ -1415,19 +1658,88 @@
1415
1658
  );
1416
1659
  }
1417
1660
  function useIsDirty(form) {
1418
- return useWatch(form.emitter, "change", isDirty.bind(null, form));
1661
+ return useWatch(form, "change", isDirty.bind(null, form));
1662
+ }
1663
+ function useIsFieldDirty(form, name) {
1664
+ return useIsFieldDirtyByPath(form, create$1(name));
1665
+ }
1666
+ function useIsFieldDirtyByPath(form, path) {
1667
+ const { emitter } = form;
1668
+ const { key } = path;
1669
+ const subscribeFactory = React.useCallback(
1670
+ (invalidate) => onPathEvent(emitter, "change", path, "leaf", invalidate),
1671
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- same key-pinning convention as useValueByPath
1672
+ [emitter, key]
1673
+ );
1674
+ return useWatchCore(subscribeFactory, () => isFieldDirtyByPath(form, path));
1419
1675
  }
1420
1676
  function useDirtyFields(form) {
1421
- return useWatch(form.emitter, "change", getDirtyFields.bind(null, form));
1677
+ return useWatch(form, "change", getDirtyFields.bind(null, form));
1422
1678
  }
1423
1679
  function useTouchedFields(form) {
1424
- return useWatch(form.emitter, "touched", getTouchedFields.bind(null, form));
1680
+ return useWatch(form, "touched", getTouchedFields.bind(null, form));
1681
+ }
1682
+ const FORM_STATE_EVENTS = [
1683
+ "change",
1684
+ "errors",
1685
+ "touched",
1686
+ "validating",
1687
+ "submitting",
1688
+ "submitCount",
1689
+ "submitSuccessful",
1690
+ "disabled",
1691
+ "loading"
1692
+ ];
1693
+ function getFormState(form) {
1694
+ return {
1695
+ isDirty: isDirty(form),
1696
+ dirtyFields: getDirtyFields(form),
1697
+ isTouched: form.touched.size > 0,
1698
+ touchedFields: getTouchedFields(form),
1699
+ hasErrors: hasErrors(form),
1700
+ isValid: !hasErrors(form),
1701
+ isSubmitting: form.isSubmitting,
1702
+ isSubmitted: form.isSubmitted,
1703
+ isValidating: form.validating.size > 0,
1704
+ isSubmitSuccessful: form.isSubmitSuccessful,
1705
+ submitCount: form.submitCount,
1706
+ isLoading: form.isLoading,
1707
+ disabled: form.disabled
1708
+ };
1709
+ }
1710
+ function isSameFormState(a, b) {
1711
+ const sameTouched = a.touchedFields.length === b.touchedFields.length && a.touchedFields.every((path, i) => path === b.touchedFields[i]);
1712
+ return a.isDirty === b.isDirty && a.dirtyFields === b.dirtyFields && a.isTouched === b.isTouched && sameTouched && a.hasErrors === b.hasErrors && a.isValid === b.isValid && a.isSubmitting === b.isSubmitting && a.isSubmitted === b.isSubmitted && a.isValidating === b.isValidating && a.isSubmitSuccessful === b.isSubmitSuccessful && a.submitCount === b.submitCount && a.isLoading === b.isLoading && a.disabled === b.disabled;
1713
+ }
1714
+ function useFormState(form) {
1715
+ const getter = React.useCallback(() => getFormState(form), [form]);
1716
+ const subscribeFactory = React.useCallback(
1717
+ (invalidate) => {
1718
+ const offs = FORM_STATE_EVENTS.map(
1719
+ (event) => on(form.emitter, event, invalidate)
1720
+ );
1721
+ return () => {
1722
+ for (const off of offs) off();
1723
+ };
1724
+ },
1725
+ [form.emitter]
1726
+ );
1727
+ return useWatchCore(subscribeFactory, getter, isSameFormState);
1425
1728
  }
1426
1729
  function useHasErrors(form) {
1427
- return useWatch(form.emitter, "errors", hasErrors.bind(null, form));
1730
+ return useWatch(form, "errors", hasErrors.bind(null, form));
1731
+ }
1732
+ function useIsValid(form) {
1733
+ return useWatch(form, "errors", () => !hasErrors(form));
1428
1734
  }
1429
1735
  function useIsSubmitting(form) {
1430
- return useWatch(form.emitter, "submitting", () => form.isSubmitting);
1736
+ return useWatch(form, "submitting", () => form.isSubmitting);
1737
+ }
1738
+ function useIsLoading(form) {
1739
+ return useWatch(form, "loading", () => form.isLoading);
1740
+ }
1741
+ function useStatus(form) {
1742
+ return useWatch(form, "status", () => form.status);
1431
1743
  }
1432
1744
  function useCanSubmit(form) {
1433
1745
  const { emitter } = form;
@@ -1448,7 +1760,23 @@
1448
1760
  );
1449
1761
  }
1450
1762
  function useSubmitCount(form) {
1451
- return useWatch(form.emitter, "submitCount", () => form.submitCount);
1763
+ return useWatch(form, "submitCount", () => form.submitCount);
1764
+ }
1765
+ function useIsValidating(form) {
1766
+ return useWatch(form, "validating", () => form.validating.size > 0);
1767
+ }
1768
+ function useIsSubmitSuccessful(form) {
1769
+ return useWatch(
1770
+ form.emitter,
1771
+ "submitSuccessful",
1772
+ () => !!form.isSubmitSuccessful
1773
+ );
1774
+ }
1775
+ function useFormError(form) {
1776
+ return useErrorByPath(form, create$1(FORM_ERROR))?.message;
1777
+ }
1778
+ function useFormErrors(form) {
1779
+ return useFieldErrorsByPath(form, create$1(FORM_ERROR));
1452
1780
  }
1453
1781
 
1454
1782
  function usePath(name) {
@@ -1468,97 +1796,94 @@
1468
1796
  [ref]
1469
1797
  );
1470
1798
  }
1799
+ function useUnmountRestore(teardown, restore) {
1800
+ const removedRef = React.useRef(false);
1801
+ React.useEffect(() => {
1802
+ if (removedRef.current) {
1803
+ removedRef.current = false;
1804
+ restore();
1805
+ }
1806
+ return () => {
1807
+ removedRef.current = true;
1808
+ teardown();
1809
+ };
1810
+ }, []);
1811
+ }
1471
1812
 
1472
1813
  function useValidate(validate, path, formProp, options) {
1473
1814
  const contextForm = React.useContext(FormContext);
1474
1815
  const form = formProp || contextForm;
1475
1816
  if (!form) throw new Error("no form provided");
1476
- const lockRef = React.useRef(null);
1477
1817
  const validateRef = React.useRef(validate);
1478
1818
  validateRef.current = validate;
1479
1819
  const debounceRef = React.useRef(options?.debounce ?? 0);
1480
1820
  debounceRef.current = options?.debounce ?? 0;
1821
+ const syncRef = React.useRef(options?.sync);
1822
+ syncRef.current = options?.sync;
1823
+ const asyncAlwaysRef = React.useRef(options?.asyncAlways ?? false);
1824
+ asyncAlwaysRef.current = options?.asyncAlways ?? false;
1481
1825
  React.useEffect(() => {
1482
- let timer = null;
1483
- let controller = null;
1484
- let marked = false;
1485
- const mark = () => {
1486
- if (marked) return;
1487
- marked = true;
1488
- setValidatingByPath(form, path);
1489
- };
1490
- const unmark = () => {
1491
- if (!marked) return;
1492
- marked = false;
1493
- unsetValidatingByPath(form, path);
1826
+ const dispose = registerValidatorByPath(form, path, {
1827
+ validate: () => validateRef.current,
1828
+ debounce: () => debounceRef.current,
1829
+ sync: () => syncRef.current,
1830
+ asyncAlways: () => asyncAlwaysRef.current
1831
+ });
1832
+ const validateOnMount = options?.validateOnMount ?? form.validateOnMount;
1833
+ if (!validateOnMount || !validateRef.current && !syncRef.current) {
1834
+ return dispose;
1835
+ }
1836
+ let disposed = false;
1837
+ const kick = () => {
1838
+ if (disposed) return;
1839
+ form.validators.get(path.key)?.();
1494
1840
  };
1495
- const run = () => {
1496
- timer = null;
1497
- const fn = validateRef.current;
1498
- if (!fn) {
1499
- unmark();
1500
- return;
1501
- }
1502
- controller?.abort();
1503
- controller = new AbortController();
1504
- const lock = lockRef.current = {};
1505
- let result;
1506
- try {
1507
- result = fn(getValueByPath(form, path), {
1508
- form,
1509
- path,
1510
- signal: controller.signal
1511
- });
1512
- } catch (e) {
1513
- unmark();
1514
- throw e;
1515
- }
1516
- if (!isPromise(result)) {
1517
- setErrorByPath(form, path, result);
1518
- unmark();
1519
- return;
1520
- }
1521
- mark();
1522
- result.then(
1523
- (error) => {
1524
- if (lock === lockRef.current) {
1525
- setErrorByPath(form, path, error);
1526
- }
1527
- }
1528
- ).catch(() => {
1529
- }).finally(() => {
1530
- if (lock === lockRef.current) {
1531
- unmark();
1532
- lockRef.current = null;
1533
- }
1841
+ if (!form.isLoading) {
1842
+ kick();
1843
+ } else {
1844
+ const off = on(form.emitter, "loading", () => {
1845
+ off();
1846
+ kick();
1534
1847
  });
1535
- };
1536
- const validator = () => {
1537
- const debounce = debounceRef.current;
1538
- if (debounce > 0) {
1539
- if (timer !== null) clearTimeout(timer);
1540
- else mark();
1541
- timer = setTimeout(run, debounce);
1542
- return;
1543
- }
1544
- run();
1545
- };
1546
- form.validators.set(path.key, validator);
1848
+ }
1547
1849
  return () => {
1548
- form.validators.delete(path.key);
1549
- if (timer !== null) {
1550
- clearTimeout(timer);
1551
- timer = null;
1552
- }
1553
- unmark();
1554
- controller?.abort();
1850
+ disposed = true;
1851
+ dispose();
1555
1852
  };
1556
1853
  }, [form, path.key]);
1557
1854
  return useStageFn(() => form.validators.get(path.key)?.());
1558
1855
  }
1559
1856
 
1857
+ function removeFieldForUnmount(form, path) {
1858
+ const { key } = path;
1859
+ const snapshot = {
1860
+ present: form.values.has(key),
1861
+ value: form.values.get(key),
1862
+ touched: form.touched.has(key),
1863
+ errors: form.errors.get(key)
1864
+ };
1865
+ removeFieldByPath(form, path);
1866
+ return snapshot;
1867
+ }
1868
+ function restoreRemovedField(form, path, snapshot) {
1869
+ const { key } = path;
1870
+ if (snapshot.present) {
1871
+ setValueByPath(form, path, snapshot.value, { shouldDirty: false });
1872
+ } else {
1873
+ form.deleted.delete(key);
1874
+ bumpValuesVersion(form);
1875
+ emit(form.emitter, "change", path);
1876
+ }
1877
+ if (snapshot.touched) setTouchedByPath(form, path);
1878
+ if (snapshot.errors) setErrorByPath(form, path, snapshot.errors);
1879
+ }
1880
+
1881
+ const uncontrolledSyncRegistry = /* @__PURE__ */ new WeakMap();
1882
+ function hasRuleConstraints(rules) {
1883
+ return rules.required !== void 0 || rules.min !== void 0 || rules.max !== void 0 || rules.minLength !== void 0 || rules.maxLength !== void 0 || rules.pattern !== void 0 || rules.validate !== void 0;
1884
+ }
1560
1885
  function combineRulesAndValidate(rules, validate) {
1561
- if (!rules) return validate;
1886
+ if (!rules || !hasRuleConstraints(rules)) return validate;
1562
1887
  const ruleValidator = rulesToValidator(rules);
1563
1888
  if (!validate) return ruleValidator;
1564
1889
  return (value, meta) => {
@@ -1590,6 +1915,25 @@
1590
1915
  }, [errors, delay, shown]);
1591
1916
  return delay === void 0 ? errors : shown;
1592
1917
  }
1918
+ function useFieldValue(form, path, uncontrolled) {
1919
+ const snapshotRef = React.useRef({
1920
+ has: false,
1921
+ value: void 0
1922
+ });
1923
+ const getter = React.useCallback(() => {
1924
+ if (!uncontrolled) return getValueByPath(form, path);
1925
+ if (!snapshotRef.current.has) {
1926
+ snapshotRef.current = { has: true, value: getValueByPath(form, path) };
1927
+ }
1928
+ return snapshotRef.current.value;
1929
+ }, [uncontrolled, form, path]);
1930
+ const subscribeFactory = React.useCallback(
1931
+ (invalidate) => uncontrolled ? () => {
1932
+ } : onPathEvent(form.emitter, "change", path, "leaf", invalidate),
1933
+ [uncontrolled, form.emitter, path]
1934
+ );
1935
+ return useWatchCore(subscribeFactory, getter);
1936
+ }
1593
1937
  function useFieldCore({
1594
1938
  form: f1,
1595
1939
  name,
@@ -1599,8 +1943,11 @@
1599
1943
  rules,
1600
1944
  validateDebounce,
1601
1945
  validateDeps,
1946
+ validateOnMount,
1602
1947
  delayError,
1603
1948
  disabled,
1949
+ uncontrolled,
1950
+ asyncAlways,
1604
1951
  mode: modeOption
1605
1952
  }, Context) {
1606
1953
  const contextForm = React.useContext(Context);
@@ -1618,35 +1965,41 @@
1618
1965
  seededRef.current = false;
1619
1966
  emitChangeByPath(form, path);
1620
1967
  });
1621
- const validator = useValidate(
1622
- combineRulesAndValidate(rules, validate),
1623
- path,
1624
- form,
1625
- {
1626
- debounce: validateDebounce
1627
- }
1628
- );
1968
+ const restRules = rules ? { ...rules, required: void 0 } : void 0;
1969
+ useValidate(combineRulesAndValidate(restRules, validate), path, form, {
1970
+ debounce: validateDebounce,
1971
+ validateOnMount,
1972
+ asyncAlways: asyncAlways ?? form.asyncAlways,
1973
+ sync: rules && rules.required !== void 0 ? rulesToValidator({ required: rules.required }) : void 0
1974
+ });
1629
1975
  const liveErrors = useFieldErrorsByPath(form, path);
1630
1976
  const errors = useDelayedErrors(liveErrors, delayError);
1631
1977
  const errorObject = errors[0];
1632
1978
  const error = errorObject?.message;
1633
- const value = useValueByPath(form, path);
1634
- const formDisabled = useWatch(form.emitter, "disabled", () => form.disabled);
1635
- const mode = modeOption ?? form.mode;
1636
- const onChange = useStageFn((v) => {
1637
- setValueByPath(form, path, v);
1638
- if (mode === "onChange" || mode === "all" || mode === "onTouched" && hasTouchedByPath(form, path) || liveErrors.length > 0 && form.reValidateMode === "onChange")
1639
- validator();
1640
- revalidateFormOnChange(form, path, mode);
1641
- revalidateDependentsOnChange(form, path, mode);
1642
- });
1979
+ const value = useFieldValue(form, path, !!uncontrolled);
1980
+ const isDirty = useWatchCore(
1981
+ React.useCallback(
1982
+ (invalidate) => uncontrolled ? () => {
1983
+ } : onPathEvent(form.emitter, "change", path, "leaf", invalidate),
1984
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- usePath memoizes the Path per key, so key pins the subscription like every path-scoped hook
1985
+ [form.emitter, path.key, uncontrolled]
1986
+ ),
1987
+ () => isFieldDirtyByPath(form, path)
1988
+ );
1989
+ const validating = useWatchCore(
1990
+ React.useCallback(
1991
+ (invalidate) => onKeyEvent(form.emitter, "validating", path.key, invalidate),
1992
+ [form.emitter, path.key]
1993
+ ),
1994
+ () => form.validating.has(path.key)
1995
+ );
1996
+ const formDisabled = useWatch(form, "disabled", () => form.disabled);
1997
+ const onChange = useStageFn((v) => userChangeByPath(form, path, v));
1998
+ const onBlur = useStageFn(() => userBlur(form, path));
1643
1999
  React.useEffect(() => {
1644
- form.changeHandlers.set(path.key, onChange);
1645
- return () => {
1646
- if (form.changeHandlers.get(path.key) === onChange)
1647
- form.changeHandlers.delete(path.key);
1648
- };
1649
- }, [form, path.key, onChange]);
2000
+ const { token, displaced } = registerFieldMode(form, path, modeOption);
2001
+ return () => unregisterFieldMode(form, path, token);
2002
+ }, [form, path.key, modeOption]);
1650
2003
  const depsKey = validateDeps?.length ? validateDeps.join("\n") : void 0;
1651
2004
  React.useEffect(() => {
1652
2005
  if (!depsKey) return;
@@ -1654,29 +2007,77 @@
1654
2007
  registerFieldValidateDeps(form, path.key, depKeys);
1655
2008
  return () => unregisterFieldValidateDeps(form, path.key, depKeys);
1656
2009
  }, [form, path.key, depsKey]);
1657
- const onBlur = useStageFn(() => {
1658
- setTouchedByPath(form, path);
1659
- if (mode === "onBlur" || mode === "onTouched" || mode === "all" || liveErrors.length > 0 && form.reValidateMode === "onBlur")
1660
- validator();
1661
- });
2010
+ const elementRef = React.useRef(null);
2011
+ const focusRef = React.useCallback((el) => {
2012
+ elementRef.current = el;
2013
+ }, []);
1662
2014
  React.useEffect(
1663
- () => () => {
1664
- if (shouldUnregister !== false) {
1665
- removeFieldByPath(form, path);
2015
+ () => on(
2016
+ form.emitter,
2017
+ "focusError",
2018
+ (key, options) => {
2019
+ if (key !== path.key) return;
2020
+ const el = elementRef.current;
2021
+ if (!el || typeof el.focus !== "function") return;
2022
+ el.focus();
2023
+ if (options?.shouldSelect && typeof el.select === "function") {
2024
+ el.select();
2025
+ }
1666
2026
  }
1667
- },
1668
- [path, form, shouldUnregister]
2027
+ ),
2028
+ [form, path.key]
1669
2029
  );
2030
+ React.useEffect(() => {
2031
+ if (!uncontrolled) return;
2032
+ let entry = uncontrolledSyncRegistry.get(form);
2033
+ if (!entry) {
2034
+ const cells = /* @__PURE__ */ new Map();
2035
+ const off = on(form.emitter, "change", (changed) => {
2036
+ if (changed) return;
2037
+ for (const read of cells.values()) {
2038
+ const { el, path: path2 } = read();
2039
+ if (!el || el.type === "file") continue;
2040
+ const next = getValueByPath(form, path2);
2041
+ const asString = next == null ? "" : String(next);
2042
+ if (el.value !== asString) el.value = asString;
2043
+ }
2044
+ });
2045
+ entry = { cells, off };
2046
+ uncontrolledSyncRegistry.set(form, entry);
2047
+ }
2048
+ entry.cells.set(path.key, () => ({ el: elementRef.current, path }));
2049
+ return () => {
2050
+ entry.cells.delete(path.key);
2051
+ if (entry.cells.size === 0) {
2052
+ entry.off();
2053
+ uncontrolledSyncRegistry.delete(form);
2054
+ }
2055
+ };
2056
+ }, [form, path.key, uncontrolled]);
2057
+ const removalSnapshotRef = React.useRef(null);
2058
+ const teardownOnUnmount = useStageFn(() => {
2059
+ if ((shouldUnregister ?? form.shouldUnregister) === false) return;
2060
+ removalSnapshotRef.current = removeFieldForUnmount(form, path);
2061
+ });
2062
+ const restoreAfterStrictMode = useStageFn(() => {
2063
+ const snapshot = removalSnapshotRef.current;
2064
+ removalSnapshotRef.current = null;
2065
+ if (snapshot) restoreRemovedField(form, path, snapshot);
2066
+ });
2067
+ useUnmountRestore(teardownOnUnmount, restoreAfterStrictMode);
1670
2068
  return {
1671
2069
  form,
1672
2070
  value,
1673
2071
  error,
1674
2072
  errorObject,
1675
2073
  errors,
2074
+ isDirty,
2075
+ validating,
1676
2076
  onChange,
1677
2077
  onBlur,
1678
2078
  name: path.key,
1679
- disabled: formDisabled || !!disabled
2079
+ disabled: formDisabled || !!disabled,
2080
+ focusRef
1680
2081
  };
1681
2082
  }
1682
2083
  function useField(options) {
@@ -1708,6 +2109,8 @@
1708
2109
  const contextForm = React.useContext(Context);
1709
2110
  const form = options.form || contextForm;
1710
2111
  if (!form) throw new Error("no form provided");
2112
+ const keyName = options.keyName ?? "id";
2113
+ const { rules, shouldUnregister } = options;
1711
2114
  const path = usePath(options.name);
1712
2115
  const idsRef = React.useRef([]);
1713
2116
  const getArray = React.useCallback(
@@ -1728,8 +2131,12 @@
1728
2131
  while (idsRef.current.length > arr.length) {
1729
2132
  idsRef.current.pop();
1730
2133
  }
1731
- return idsRef.current.map((id, index) => ({ id, index }));
1732
- }, [getArray, form]);
2134
+ return idsRef.current.map((id, index) => ({
2135
+ id,
2136
+ index,
2137
+ [keyName]: id
2138
+ }));
2139
+ }, [getArray, form, keyName]);
1733
2140
  const [fields, syncFields] = React.useReducer(
1734
2141
  computeFields,
1735
2142
  void 0,
@@ -1747,6 +2154,25 @@
1747
2154
  if (registry?.get(path.key) === idsRef.current) registry.delete(path.key);
1748
2155
  };
1749
2156
  }, [form, path.key]);
2157
+ const removalSnapshotRef = React.useRef(null);
2158
+ const teardownOnUnmount = useStageFn(() => {
2159
+ if ((shouldUnregister ?? form.shouldUnregister) === false) return;
2160
+ removalSnapshotRef.current = removeFieldForUnmount(form, path);
2161
+ });
2162
+ const restoreAfterStrictMode = useStageFn(() => {
2163
+ const snapshot = removalSnapshotRef.current;
2164
+ removalSnapshotRef.current = null;
2165
+ if (snapshot) restoreRemovedField(form, path, snapshot);
2166
+ });
2167
+ useUnmountRestore(teardownOnUnmount, restoreAfterStrictMode);
2168
+ useValidate(
2169
+ rules ? rulesToValidator({ ...rules, required: void 0 }) : void 0,
2170
+ path,
2171
+ form,
2172
+ {
2173
+ sync: rules && rules.required !== void 0 ? rulesToValidator({ required: rules.required }) : void 0
2174
+ }
2175
+ );
1750
2176
  const append = useStageFn((value) => {
1751
2177
  const arr = getArray();
1752
2178
  idsRef.current.push(generateId(form));
@@ -1905,29 +2331,108 @@
1905
2331
  return group;
1906
2332
  }
1907
2333
 
2334
+ function useTransform(form, name, options = {}) {
2335
+ const path = usePath(name);
2336
+ const { toDisplay, fromDisplay } = options;
2337
+ const subscribeFactory = React.useCallback(
2338
+ (invalidate) => onPathEvent(form.emitter, "change", path, "leaf", invalidate),
2339
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- usePath memoizes the Path per key, so key pins the subscription like every path-scoped hook
2340
+ [form.emitter, path.key]
2341
+ );
2342
+ const raw = useWatchCore(subscribeFactory, () => getValueByPath(form, path));
2343
+ const value = toDisplay ? toDisplay(raw) : raw;
2344
+ const onChange = React.useCallback(
2345
+ (display) => {
2346
+ userChangeByPath(
2347
+ form,
2348
+ path,
2349
+ fromDisplay ? fromDisplay(display) : display
2350
+ );
2351
+ },
2352
+ [form, path, fromDisplay]
2353
+ );
2354
+ return { value, onChange };
2355
+ }
2356
+
2357
+ function appendFormDataValue(fd, key, value) {
2358
+ if (value == null) return;
2359
+ if (Array.isArray(value)) {
2360
+ for (const item of value) appendFormDataValue(fd, key, item);
2361
+ return;
2362
+ }
2363
+ if (typeof FileList !== "undefined" && value instanceof FileList) {
2364
+ for (let i = 0; i < value.length; i++) fd.append(key, value.item(i));
2365
+ return;
2366
+ }
2367
+ if (typeof File !== "undefined" && value instanceof File) {
2368
+ fd.append(key, value, value.name);
2369
+ return;
2370
+ }
2371
+ if (typeof Blob !== "undefined" && value instanceof Blob) {
2372
+ fd.append(key, value);
2373
+ return;
2374
+ }
2375
+ if (value instanceof Date) {
2376
+ fd.append(key, value.toISOString());
2377
+ return;
2378
+ }
2379
+ fd.append(
2380
+ key,
2381
+ typeof value === "object" ? JSON.stringify(value) : String(value)
2382
+ );
2383
+ }
2384
+ function formDataFromValues(values) {
2385
+ const fd = new FormData();
2386
+ for (const key of Object.keys(values)) {
2387
+ appendFormDataValue(fd, key, values[key]);
2388
+ }
2389
+ return fd;
2390
+ }
2391
+
1908
2392
  function Form({
1909
2393
  form: f1,
1910
2394
  context,
1911
2395
  initialValues,
1912
2396
  values,
2397
+ shouldUnregister,
2398
+ validateOnMount,
2399
+ disabled,
2400
+ asyncAlways,
1913
2401
  onSubmit,
1914
2402
  onValidSubmit,
1915
2403
  onInvalidSubmit,
2404
+ action,
1916
2405
  shouldFocusError,
1917
2406
  ...props
1918
2407
  }) {
1919
- const f2 = useForm({ initialValues, values });
2408
+ const f2 = useForm({
2409
+ initialValues,
2410
+ values,
2411
+ shouldUnregister,
2412
+ validateOnMount,
2413
+ disabled,
2414
+ asyncAlways
2415
+ });
1920
2416
  const form = f1 || f2;
2417
+ React__namespace.useEffect(() => {
2418
+ if (disabled !== void 0) setDisabled(form, disabled);
2419
+ }, [form, disabled]);
1921
2420
  const submit = handleSubmit(form, {
1922
2421
  onSubmit,
1923
2422
  onValidSubmit,
1924
2423
  onInvalidSubmit,
1925
- shouldFocusError
2424
+ shouldFocusError,
2425
+ onAction: action ? (values2) => action(formDataFromValues(values2)) : void 0
1926
2426
  });
1927
2427
  const { Provider } = context ?? FormContext;
1928
2428
  return /* @__PURE__ */ React__namespace.createElement(Provider, { value: form }, /* @__PURE__ */ React__namespace.createElement("form", { ...props, noValidate: true, onSubmit: submit }));
1929
2429
  }
1930
2430
 
2431
+ function FormField({ children, ...options }) {
2432
+ const field = useField(options);
2433
+ return children(field);
2434
+ }
2435
+
1931
2436
  function setRef(ref, value) {
1932
2437
  if (typeof ref === "function") {
1933
2438
  ref(value);
@@ -1962,28 +2467,26 @@
1962
2467
  shouldUnregister,
1963
2468
  rules,
1964
2469
  validateDebounce,
2470
+ validateOnMount,
2471
+ valueAsNumber,
2472
+ valueAsDate,
2473
+ asyncAlways,
1965
2474
  disabled,
1966
2475
  delayError,
1967
2476
  mode,
2477
+ uncontrolled,
1968
2478
  ...props
1969
2479
  }, ref) => {
1970
2480
  const innerRef = React__namespace.useRef(null);
1971
2481
  const [nativeInvalidCount, setNativeInvalidCount] = React__namespace.useState(0);
1972
- const mergedRef = React__namespace.useCallback(
1973
- (node) => {
1974
- innerRef.current = node;
1975
- setRef(ref, node);
1976
- },
1977
- [ref]
1978
- );
1979
2482
  const {
1980
2483
  value,
1981
2484
  onChange,
1982
2485
  onBlur,
1983
2486
  error,
1984
- form,
1985
2487
  name: fieldKey,
1986
- disabled: isDisabled
2488
+ disabled: isDisabled,
2489
+ focusRef
1987
2490
  } = useField({
1988
2491
  name,
1989
2492
  form: formProp,
@@ -1991,9 +2494,14 @@
1991
2494
  shouldUnregister,
1992
2495
  rules,
1993
2496
  validateDebounce,
2497
+ validateOnMount,
1994
2498
  delayError,
1995
2499
  disabled,
2500
+ asyncAlways,
1996
2501
  mode,
2502
+ // File inputs cannot be value-controlled at all — force the
2503
+ // uncontrolled path so no `value` prop ever reaches the element.
2504
+ uncontrolled: uncontrolled || props.type === "file",
1997
2505
  validate: (...params) => {
1998
2506
  const el = innerRef.current;
1999
2507
  if (el && typeof el.checkValidity === "function") {
@@ -2006,6 +2514,14 @@
2006
2514
  if (validate) return validate(...params);
2007
2515
  }
2008
2516
  });
2517
+ const mergedRef = React__namespace.useCallback(
2518
+ (node) => {
2519
+ innerRef.current = node;
2520
+ focusRef(node);
2521
+ setRef(ref, node);
2522
+ },
2523
+ [ref, focusRef]
2524
+ );
2009
2525
  const Component = as || "input";
2010
2526
  React__namespace.useEffect(() => {
2011
2527
  const el = innerRef.current;
@@ -2020,32 +2536,20 @@
2020
2536
  React__namespace.useEffect(() => {
2021
2537
  if (nativeInvalidCount > 0) innerRef.current?.reportValidity();
2022
2538
  }, [nativeInvalidCount]);
2023
- React__namespace.useEffect(
2024
- () => on(
2025
- form.emitter,
2026
- "focusError",
2027
- (key, options) => {
2028
- if (key !== fieldKey) return;
2029
- const el = innerRef.current;
2030
- if (!el || typeof el.focus !== "function") return;
2031
- el.focus();
2032
- if (options?.shouldSelect && typeof el.select === "function") {
2033
- el.select();
2034
- }
2035
- }
2036
- ),
2037
- [form, fieldKey]
2038
- );
2039
- const toValue = eventToValue ?? ((e) => e.target.value);
2539
+ const isFile = props.type === "file";
2540
+ const toValue = eventToValue ?? (isFile ? (e) => e.target.files : valueAsNumber ? (e) => e.target.valueAsNumber : valueAsDate ? (e) => e.target.valueAsDate : (e) => e.target.value);
2541
+ const valueProps = valueToProps ? valueToProps(value) : isFile ? {} : uncontrolled ? { defaultValue: value } : { value };
2040
2542
  const errorId = errorIdFromKey(fieldKey);
2543
+ const constraintAttrs = rules ? rulesToConstraintAttrs(rules) : void 0;
2041
2544
  return /* @__PURE__ */ React__namespace.createElement(React__namespace.Fragment, null, /* @__PURE__ */ React__namespace.createElement(
2042
2545
  Component,
2043
2546
  {
2547
+ ...constraintAttrs,
2044
2548
  ...props,
2045
2549
  name: fieldKey,
2046
2550
  onBlur,
2047
2551
  ...asProps,
2048
- ...valueToProps ? valueToProps(value) : { value },
2552
+ ...valueProps,
2049
2553
  ...ariaProps(error, fieldKey, props),
2050
2554
  disabled: isDisabled,
2051
2555
  onChange: (e) => onChange(toValue(e)),
@@ -2063,6 +2567,8 @@
2063
2567
  validate,
2064
2568
  rules,
2065
2569
  validateDebounce,
2570
+ validateOnMount,
2571
+ asyncAlways,
2066
2572
  disabled,
2067
2573
  delayError,
2068
2574
  mode,
@@ -2083,13 +2589,17 @@
2083
2589
  validate,
2084
2590
  rules,
2085
2591
  validateDebounce,
2592
+ validateOnMount,
2593
+ asyncAlways,
2086
2594
  delayError,
2087
2595
  disabled,
2088
2596
  mode
2089
2597
  });
2598
+ const constraintAttrs = rules ? rulesToConstraintAttrs(rules) : void 0;
2090
2599
  return /* @__PURE__ */ React__namespace.createElement(
2091
2600
  "input",
2092
2601
  {
2602
+ ...constraintAttrs,
2093
2603
  ...props,
2094
2604
  name: fieldKey,
2095
2605
  onBlur,
@@ -2118,6 +2628,8 @@
2118
2628
  validate,
2119
2629
  rules,
2120
2630
  validateDebounce,
2631
+ validateOnMount,
2632
+ asyncAlways,
2121
2633
  disabled,
2122
2634
  delayError,
2123
2635
  mode,
@@ -2138,13 +2650,17 @@
2138
2650
  validate,
2139
2651
  rules,
2140
2652
  validateDebounce,
2653
+ validateOnMount,
2654
+ asyncAlways,
2141
2655
  delayError,
2142
2656
  disabled,
2143
2657
  mode
2144
2658
  });
2659
+ const constraintAttrs = rules ? rulesToConstraintAttrs(rules) : void 0;
2145
2660
  return /* @__PURE__ */ React__namespace.createElement(
2146
2661
  "select",
2147
2662
  {
2663
+ ...constraintAttrs,
2148
2664
  ...props,
2149
2665
  name: fieldKey,
2150
2666
  onBlur,
@@ -2165,9 +2681,11 @@
2165
2681
  exports.Checkbox = Checkbox;
2166
2682
  exports.CheckboxGroupContext = CheckboxGroupContext;
2167
2683
  exports.CheckboxGroupProvider = CheckboxGroupProvider;
2684
+ exports.FORM_ERROR = FORM_ERROR;
2168
2685
  exports.Field = Field;
2169
2686
  exports.Form = Form;
2170
2687
  exports.FormContext = FormContext;
2688
+ exports.FormField = FormField;
2171
2689
  exports.FormProvider = FormProvider;
2172
2690
  exports.Select = Select;
2173
2691
  exports.VALIDATION_OUTCOME = VALIDATION_OUTCOME;
@@ -2197,14 +2715,18 @@
2197
2715
  exports.hasTouchedByPath = hasTouchedByPath;
2198
2716
  exports.incrementSubmitCount = incrementSubmitCount;
2199
2717
  exports.isDirty = isDirty;
2718
+ exports.isFieldDirtyByPath = isFieldDirtyByPath;
2200
2719
  exports.isTouched = isTouched;
2720
+ exports.registerFieldMode = registerFieldMode;
2201
2721
  exports.registerFieldValidateDeps = registerFieldValidateDeps;
2722
+ exports.registerValidatorByPath = registerValidatorByPath;
2202
2723
  exports.removeField = removeField;
2203
2724
  exports.removeFieldByPath = removeFieldByPath;
2204
2725
  exports.reset = reset;
2205
2726
  exports.resetField = resetField;
2206
2727
  exports.revalidateDependentsOnChange = revalidateDependentsOnChange;
2207
2728
  exports.revalidateFormOnChange = revalidateFormOnChange;
2729
+ exports.runFormValidate = runFormValidate;
2208
2730
  exports.seedValueByPath = seedValueByPath;
2209
2731
  exports.setDisabled = setDisabled;
2210
2732
  exports.setError = setError;
@@ -2213,6 +2735,7 @@
2213
2735
  exports.setInitialValues = setInitialValues;
2214
2736
  exports.setIsSubmitting = setIsSubmitting;
2215
2737
  exports.setServerErrors = setServerErrors;
2738
+ exports.setStatus = setStatus;
2216
2739
  exports.setSubmitSuccessful = setSubmitSuccessful;
2217
2740
  exports.setTouched = setTouched;
2218
2741
  exports.setTouchedByPath = setTouchedByPath;
@@ -2221,6 +2744,7 @@
2221
2744
  exports.setValueByPath = setValueByPath;
2222
2745
  exports.subscribe = subscribe;
2223
2746
  exports.trigger = trigger;
2747
+ exports.unregisterFieldMode = unregisterFieldMode;
2224
2748
  exports.unregisterFieldValidateDeps = unregisterFieldValidateDeps;
2225
2749
  exports.unsetValidatingByPath = unsetValidatingByPath;
2226
2750
  exports.useCanSubmit = useCanSubmit;
@@ -2235,16 +2759,30 @@
2235
2759
  exports.useFieldErrorsByPath = useFieldErrorsByPath;
2236
2760
  exports.useForm = useForm;
2237
2761
  exports.useFormContext = useFormContext;
2762
+ exports.useFormError = useFormError;
2763
+ exports.useFormErrors = useFormErrors;
2764
+ exports.useFormState = useFormState;
2238
2765
  exports.useHasErrors = useHasErrors;
2239
2766
  exports.useIsDirty = useIsDirty;
2767
+ exports.useIsFieldDirty = useIsFieldDirty;
2768
+ exports.useIsFieldDirtyByPath = useIsFieldDirtyByPath;
2769
+ exports.useIsLoading = useIsLoading;
2770
+ exports.useIsSubmitSuccessful = useIsSubmitSuccessful;
2240
2771
  exports.useIsSubmitting = useIsSubmitting;
2772
+ exports.useIsValid = useIsValid;
2773
+ exports.useIsValidating = useIsValidating;
2774
+ exports.useStatus = useStatus;
2241
2775
  exports.useSubmitCount = useSubmitCount;
2242
2776
  exports.useTouched = useTouched;
2243
2777
  exports.useTouchedByPath = useTouchedByPath;
2244
2778
  exports.useTouchedFields = useTouchedFields;
2779
+ exports.useTransform = useTransform;
2245
2780
  exports.useValue = useValue;
2246
2781
  exports.useValueByPath = useValueByPath;
2247
2782
  exports.useWatch = useWatch;
2783
+ exports.useWatchCore = useWatchCore;
2784
+ exports.userBlur = userBlur;
2785
+ exports.userChangeByPath = userChangeByPath;
2248
2786
  exports.validate = validate;
2249
2787
 
2250
2788
  }));