react-f0rm 1.3.0 → 1.5.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 (99) hide show
  1. package/README.md +98 -1140
  2. package/devtools.d.ts +1 -0
  3. package/devtools.js +1 -0
  4. package/dist/array-Bu7W8BSz.d.ts +54 -0
  5. package/dist/devtools/index.cjs.js +1 -1
  6. package/dist/devtools/index.cjs.js.map +1 -1
  7. package/dist/devtools/index.d.cts +24 -0
  8. package/dist/devtools/index.d.mts +24 -0
  9. package/dist/devtools/index.d.ts +8 -17
  10. package/dist/devtools/index.mjs +1 -1
  11. package/dist/devtools/index.mjs.map +1 -1
  12. package/dist/errors-DA4ReEd9.mjs +2 -0
  13. package/dist/errors-DA4ReEd9.mjs.map +1 -0
  14. package/dist/errors-TzyWwBfw.cjs.js +2 -0
  15. package/dist/errors-TzyWwBfw.cjs.js.map +1 -0
  16. package/dist/index.cjs.js +1 -1
  17. package/dist/index.cjs.js.map +1 -1
  18. package/dist/index.d.cts +1253 -0
  19. package/dist/index.d.mts +1253 -0
  20. package/dist/index.d.ts +570 -895
  21. package/dist/index.mjs +1 -1
  22. package/dist/index.mjs.map +1 -1
  23. package/dist/index.umd.js +1256 -535
  24. package/dist/index.umd.js.map +1 -1
  25. package/dist/index.umd.min.js +2 -2
  26. package/dist/index.umd.min.js.map +1 -1
  27. package/dist/persist.cjs.js +1 -1
  28. package/dist/persist.cjs.js.map +1 -1
  29. package/dist/persist.d.cts +28 -0
  30. package/dist/persist.d.mts +28 -0
  31. package/dist/persist.d.ts +9 -30
  32. package/dist/persist.mjs +1 -1
  33. package/dist/persist.mjs.map +1 -1
  34. package/dist/resolvers/standard-schema.cjs.js +1 -1
  35. package/dist/resolvers/standard-schema.cjs.js.map +1 -1
  36. package/dist/resolvers/standard-schema.d.cts +2 -0
  37. package/dist/resolvers/standard-schema.d.mts +2 -0
  38. package/dist/resolvers/standard-schema.d.ts +1 -67
  39. package/dist/resolvers/standard-schema.mjs +1 -1
  40. package/dist/resolvers/standard-schema.mjs.map +1 -1
  41. package/dist/resolvers/yup.cjs.js +1 -1
  42. package/dist/resolvers/yup.cjs.js.map +1 -1
  43. package/dist/resolvers/yup.d.cts +6 -0
  44. package/dist/resolvers/yup.d.mts +6 -0
  45. package/dist/resolvers/yup.d.ts +0 -1
  46. package/dist/resolvers/yup.mjs +1 -1
  47. package/dist/resolvers/yup.mjs.map +1 -1
  48. package/dist/resolvers/zod.cjs.js +1 -1
  49. package/dist/resolvers/zod.cjs.js.map +1 -1
  50. package/dist/resolvers/zod.d.cts +34 -0
  51. package/dist/resolvers/zod.d.mts +34 -0
  52. package/dist/resolvers/zod.d.ts +30 -3
  53. package/dist/resolvers/zod.mjs +1 -1
  54. package/dist/resolvers/zod.mjs.map +1 -1
  55. package/dist/server/index.cjs.js +1 -1
  56. package/dist/server/index.cjs.js.map +1 -1
  57. package/dist/server/index.d.cts +38 -0
  58. package/dist/server/index.d.mts +38 -0
  59. package/dist/server/index.d.ts +26 -65
  60. package/dist/server/index.mjs +1 -1
  61. package/dist/server/index.mjs.map +1 -1
  62. package/dist/standard-schema-BAaTmAHh.d.ts +682 -0
  63. package/dist/standardSchema-5WezjHlp.mjs +2 -0
  64. package/dist/standardSchema-5WezjHlp.mjs.map +1 -0
  65. package/dist/standardSchema-DINHlsYR.cjs.js +2 -0
  66. package/dist/standardSchema-DINHlsYR.cjs.js.map +1 -0
  67. package/dist/validate-2pX-N1O6.cjs.js +2 -0
  68. package/dist/validate-2pX-N1O6.cjs.js.map +1 -0
  69. package/dist/validate-C0HOsP9v.mjs +2 -0
  70. package/dist/validate-C0HOsP9v.mjs.map +1 -0
  71. package/dist/values-BbPnLByD.cjs.js +2 -0
  72. package/dist/values-BbPnLByD.cjs.js.map +1 -0
  73. package/dist/values-CHsmcZk4.mjs +2 -0
  74. package/dist/values-CHsmcZk4.mjs.map +1 -0
  75. package/package.json +75 -28
  76. package/persist.d.ts +1 -0
  77. package/persist.js +1 -0
  78. package/resolvers/standard-schema.d.ts +1 -0
  79. package/resolvers/standard-schema.js +1 -0
  80. package/resolvers/yup.d.ts +1 -0
  81. package/resolvers/yup.js +1 -0
  82. package/resolvers/zod.d.ts +1 -0
  83. package/resolvers/zod.js +1 -0
  84. package/server.d.ts +1 -0
  85. package/server.js +1 -0
  86. package/dist/errors-BKrUdpfI.cjs.js +0 -2
  87. package/dist/errors-BKrUdpfI.cjs.js.map +0 -1
  88. package/dist/errors-CrQBddrJ.mjs +0 -2
  89. package/dist/errors-CrQBddrJ.mjs.map +0 -1
  90. package/dist/form-CeKSBs31.d.ts +0 -486
  91. package/dist/validate-CNtuUhmk.mjs +0 -2
  92. package/dist/validate-CNtuUhmk.mjs.map +0 -1
  93. package/dist/validate-Cl4ksNFu.cjs.js +0 -2
  94. package/dist/validate-Cl4ksNFu.cjs.js.map +0 -1
  95. package/dist/validate-nksgv1pR.d.ts +0 -272
  96. package/dist/values-Cu6awQOJ.cjs.js +0 -2
  97. package/dist/values-Cu6awQOJ.cjs.js.map +0 -1
  98. package/dist/values-DRY-a32G.mjs +0 -2
  99. package/dist/values-DRY-a32G.mjs.map +0 -1
package/dist/index.umd.js CHANGED
@@ -266,12 +266,31 @@
266
266
  delete copy[prop];
267
267
  return copy;
268
268
  }
269
+ function arraySlot(container, prop) {
270
+ if (typeof prop === "number") return prop;
271
+ if (Array.isArray(container) && typeof prop === "string" && isIndex(prop)) {
272
+ return Number(prop);
273
+ }
274
+ return void 0;
275
+ }
276
+ function copyForProp(container, prop) {
277
+ if (arraySlot(container, prop) !== void 0) {
278
+ return Array.isArray(container) ? container.slice() : [];
279
+ }
280
+ return { ...container };
281
+ }
282
+ function ensureOwned(container, prop, owned) {
283
+ if (owned.has(container)) return container;
284
+ const copy = copyForProp(container, prop);
285
+ owned.add(copy);
286
+ return copy;
287
+ }
269
288
  function set(values, path, value) {
270
289
  if (!path.length) return value;
271
290
  const [prop, ...props] = path;
272
- const index = typeof prop === "number" ? prop : Array.isArray(values) && typeof prop === "string" && isIndex(prop) ? Number(prop) : void 0;
291
+ const index = arraySlot(values, prop);
273
292
  if (index !== void 0) {
274
- const arr = Array.isArray(values) ? values.slice() : [];
293
+ const arr = copyForProp(values, prop);
275
294
  arr[index] = set(arr[index], props, value);
276
295
  return arr;
277
296
  }
@@ -284,14 +303,8 @@
284
303
  let parentProp = "";
285
304
  for (let i = 0; i < path.length; i++) {
286
305
  const prop = path[i];
287
- if (!owned.has(container)) {
288
- let copy;
289
- if (typeof prop === "number" || Array.isArray(container) && typeof prop === "string" && isIndex(prop)) {
290
- copy = Array.isArray(container) ? container.slice() : [];
291
- } else {
292
- copy = { ...container };
293
- }
294
- owned.add(copy);
306
+ const copy = ensureOwned(container, prop, owned);
307
+ if (copy !== container) {
295
308
  if (i === 0) root = copy;
296
309
  else parent[parentProp] = copy;
297
310
  container = copy;
@@ -309,6 +322,18 @@
309
322
  function isPromise(value) {
310
323
  return value && typeof value.then === "function";
311
324
  }
325
+ function extractEventValue(e, options) {
326
+ const target = e?.target;
327
+ if (!target) return e;
328
+ if (target.type === "file") return target.files;
329
+ if (target.type === "checkbox") return target.checked;
330
+ if (options?.valueAsNumber) return target.valueAsNumber;
331
+ if (options?.valueAsDate) return target.valueAsDate;
332
+ return target.value;
333
+ }
334
+ function eventToValueOrDefault(eventToValue, options) {
335
+ return eventToValue ?? ((e) => extractEventValue(e, options));
336
+ }
312
337
  function isEqual(a, b) {
313
338
  if (Object.is(a, b)) return true;
314
339
  if (a instanceof Date && b instanceof Date)
@@ -355,12 +380,28 @@
355
380
  const value = normalizePath(name);
356
381
  return { value, key: JSON.stringify(value) };
357
382
  }
383
+ function segmentsFromKey(key) {
384
+ return JSON.parse(key);
385
+ }
358
386
 
387
+ function getOrCreate(map, form, create) {
388
+ if (map.has(form)) return map.get(form);
389
+ const value = create();
390
+ map.set(form, value);
391
+ return value;
392
+ }
359
393
  const valuesCaches = /* @__PURE__ */ new WeakMap();
360
- function bumpValuesVersion(form) {
361
- const cache = valuesCaches.get(form);
394
+ function bumpVersion(map, form) {
395
+ const cache = map.get(form);
362
396
  if (cache) cache.version++;
363
397
  }
398
+ function bumpValuesVersion(form) {
399
+ bumpVersion(valuesCaches, form);
400
+ }
401
+ const errorsCaches = /* @__PURE__ */ new WeakMap();
402
+ function bumpErrorsVersion(form) {
403
+ bumpVersion(errorsCaches, form);
404
+ }
364
405
  const dirtyBaselines = /* @__PURE__ */ new WeakMap();
365
406
  function getDirtyBaseline(form, key, segments) {
366
407
  const baselines = dirtyBaselines.get(form);
@@ -368,12 +409,7 @@
368
409
  return get(form.initialValues, segments);
369
410
  }
370
411
  function setDirtyBaseline(form, { key }, value) {
371
- let baselines = dirtyBaselines.get(form);
372
- if (!baselines) {
373
- baselines = /* @__PURE__ */ new Map();
374
- dirtyBaselines.set(form, baselines);
375
- }
376
- baselines.set(key, value);
412
+ getOrCreate(dirtyBaselines, form, () => /* @__PURE__ */ new Map()).set(key, value);
377
413
  }
378
414
  function pruneDirtyBaselines(form, { key }) {
379
415
  const baselines = dirtyBaselines.get(form);
@@ -391,8 +427,7 @@
391
427
  }
392
428
  const dirtyFieldsCaches = /* @__PURE__ */ new WeakMap();
393
429
  function bumpDirtyVersion(form) {
394
- const cache = dirtyFieldsCaches.get(form);
395
- if (cache) cache.version++;
430
+ bumpVersion(dirtyFieldsCaches, form);
396
431
  }
397
432
  function isSegmentsPath(name) {
398
433
  return name.some((part) => typeof part === "number");
@@ -425,11 +460,55 @@
425
460
  function getErrors({ errors }) {
426
461
  const entries = [];
427
462
  for (const [key, list] of errors) {
428
- const path = JSON.parse(key).join(".");
463
+ const path = segmentsFromKey(key).join(".");
429
464
  for (const { type, message } of list) entries.push({ path, type, message });
430
465
  }
431
466
  return entries;
432
467
  }
468
+ function computeErrorsViews(form) {
469
+ const cached = errorsCaches.get(form);
470
+ if (cached?.version === 0) return;
471
+ const result = {};
472
+ const tree = {};
473
+ for (const [key, list] of form.errors) {
474
+ const segments = segmentsFromKey(key);
475
+ result[segments.join(".")] = list;
476
+ let node = tree;
477
+ for (let i = 0; i < segments.length - 1; i++) {
478
+ const segment = segments[i];
479
+ const slot = node[segment];
480
+ const container = slot && !(Array.isArray(slot) && slot.length > 0 && isFieldError(slot[0])) ? slot : typeof segments[i + 1] === "number" ? [] : {};
481
+ node[segment] = container;
482
+ node = container;
483
+ }
484
+ node[segments[segments.length - 1]] = list;
485
+ }
486
+ if (cached) {
487
+ cached.result = result;
488
+ cached.tree = tree;
489
+ cached.version = 0;
490
+ } else {
491
+ errorsCaches.set(form, { version: 0, result, tree });
492
+ }
493
+ }
494
+ function getErrorsRecord(form) {
495
+ computeErrorsViews(form);
496
+ return errorsCaches.get(form).result;
497
+ }
498
+ function getErrorsTree(form) {
499
+ computeErrorsViews(form);
500
+ return errorsCaches.get(form).tree;
501
+ }
502
+ function fieldPathToDottedKey(name) {
503
+ return create$1(name).value.join(".");
504
+ }
505
+ function dottedKeyToFieldPath(key) {
506
+ const segments = key.split(".");
507
+ const numeric = (segment) => /^(0|[1-9]\d*)$/.test(segment);
508
+ return segments.map(
509
+ (segment, i) => i > 0 && numeric(segment) ? `[${segment}]` : `${i > 0 ? "." : ""}${segment}`
510
+ ).join("");
511
+ }
433
512
  function getFirstError({ errors }) {
434
513
  return errors.values().next().value?.[0]?.message;
435
514
  }
@@ -441,6 +520,7 @@
441
520
  const list = normalizeErrors(error);
442
521
  if (list) errors.set(path.key, list);
443
522
  else errors.delete(path.key);
523
+ bumpErrorsVersion(form);
444
524
  emit(emitter, "errors", path);
445
525
  if (options?.shouldFocus) emit(emitter, "focusError", path.key);
446
526
  }
@@ -464,11 +544,13 @@
464
544
  const { emitter, errors } = form;
465
545
  if (name === void 0) {
466
546
  errors.clear();
547
+ bumpErrorsVersion(form);
467
548
  emit(emitter, "errors");
468
549
  return;
469
550
  }
470
551
  const paths = typeof name === "string" || isSegmentsPath(name) ? [create$1(name)] : name.map((one) => create$1(one));
471
552
  for (const { key } of paths) errors.delete(key);
553
+ bumpErrorsVersion(form);
472
554
  for (const path of paths) emit(emitter, "errors", path);
473
555
  }
474
556
  function setServerErrors(form, errors, options) {
@@ -484,24 +566,110 @@
484
566
  );
485
567
  }
486
568
  }
569
+ function clearServerErrors(form) {
570
+ const affected = Array.from(form.errors).filter(
571
+ ([, list]) => list.some((error) => error.type === "server")
572
+ );
573
+ if (affected.length === 0) return;
574
+ for (const [key, list] of affected) {
575
+ const kept = list.filter((error) => error.type !== "server");
576
+ if (kept.length) form.errors.set(key, kept);
577
+ else form.errors.delete(key);
578
+ }
579
+ bumpErrorsVersion(form);
580
+ emit(form.emitter, "errors");
581
+ }
487
582
  function hasErrors({ errors }) {
488
583
  return errors.size > 0;
489
584
  }
490
585
 
586
+ function hasStandardProps(schema) {
587
+ return !!schema && typeof schema === "object" && typeof schema["~standard"]?.validate === "function";
588
+ }
589
+ function toFieldError(issue) {
590
+ return { type: "standard", message: issue?.message || "Validation failed" };
591
+ }
592
+ function schemaToFieldValidator(schema) {
593
+ return async (value) => {
594
+ const result = await schema["~standard"].validate(value);
595
+ if (!result.issues?.length) return void 0;
596
+ return result.issues.map(toFieldError);
597
+ };
598
+ }
599
+ function schemaToFormValidator(schema) {
600
+ return async (values) => {
601
+ const result = await schema["~standard"].validate(values);
602
+ const { issues } = result;
603
+ if (!issues?.length) {
604
+ return {
605
+ [VALIDATION_OUTCOME]: true,
606
+ values: "value" in result ? result.value : void 0
607
+ };
608
+ }
609
+ const errors = {};
610
+ for (const issue of issues) {
611
+ const segments = toPathSegments(issue);
612
+ if (segments.length) {
613
+ assignAtPath(errors, segments, toFieldError(issue));
614
+ } else {
615
+ const slot = errors[FORM_ERROR] ??= [];
616
+ if (Array.isArray(slot)) slot.push(toFieldError(issue));
617
+ }
618
+ }
619
+ return { [VALIDATION_OUTCOME]: true, errors: pruneEmpty(errors) || {} };
620
+ };
621
+ }
622
+ function toPathSegments(issue) {
623
+ return (issue.path || []).map(
624
+ (segment) => String(
625
+ typeof segment === "object" && segment !== null ? segment.key : segment
626
+ )
627
+ );
628
+ }
629
+ function assignAtPath(root, segments, error) {
630
+ let node = root;
631
+ for (let i = 0; i < segments.length - 1; i++) {
632
+ const segment = segments[i];
633
+ if (node[segment] === void 0) node[segment] = {};
634
+ const next = node[segment];
635
+ if (!isBranch(next)) return;
636
+ node = next;
637
+ }
638
+ const leaf = segments[segments.length - 1];
639
+ const slot = node[leaf];
640
+ if (slot === void 0) node[leaf] = [error];
641
+ else if (Array.isArray(slot)) slot.push(error);
642
+ }
643
+ function isBranch(value) {
644
+ return !!value && typeof value === "object" && !Array.isArray(value);
645
+ }
646
+ function pruneEmpty(node) {
647
+ const result = {};
648
+ for (const [key, value] of Object.entries(node)) {
649
+ if (isBranch(value)) {
650
+ const pruned = pruneEmpty(value);
651
+ if (pruned) result[key] = pruned;
652
+ } else {
653
+ result[key] = value;
654
+ }
655
+ }
656
+ return Object.keys(result).length ? result : void 0;
657
+ }
658
+
491
659
  function isFieldDirtyByPath(form, path) {
492
660
  const live = form.values.get(path.key);
493
661
  return form.values.has(path.key) && getDirtyBaseline(form, path.key, path.value) !== live;
494
662
  }
495
663
  function isDirty(form) {
496
- let dirty = false;
497
- forEachDirtyField(form, () => {
498
- dirty = true;
499
- });
500
- return dirty;
664
+ for (const [key, value] of form.values) {
665
+ const path = segmentsFromKey(key);
666
+ if (getDirtyBaseline(form, key, path) !== value) return true;
667
+ }
668
+ return false;
501
669
  }
502
670
  function forEachDirtyField(form, fn) {
503
671
  for (const [key, value] of form.values) {
504
- const path = JSON.parse(key);
672
+ const path = segmentsFromKey(key);
505
673
  if (getDirtyBaseline(form, key, path) !== value) fn(path.join("."));
506
674
  }
507
675
  }
@@ -518,11 +686,11 @@
518
686
  return aKeys.every((key) => b[key] === true);
519
687
  }
520
688
  function getDirtyFields(form) {
521
- let cache = dirtyFieldsCaches.get(form);
522
- if (!cache) {
523
- cache = { version: 0, result: computeDirtyFields(form) };
524
- dirtyFieldsCaches.set(form, cache);
525
- } else if (cache.version > 0) {
689
+ const cache = getOrCreate(dirtyFieldsCaches, form, () => ({
690
+ version: 0,
691
+ result: computeDirtyFields(form)
692
+ }));
693
+ if (cache.version > 0) {
526
694
  const result = computeDirtyFields(form);
527
695
  if (!sameDirtyKeys(cache.result, result)) cache.result = result;
528
696
  cache.version = 0;
@@ -545,21 +713,18 @@
545
713
  return touched.has(path.key);
546
714
  }
547
715
  function getTouchedFields({ touched }) {
548
- return Array.from(
549
- touched,
550
- (key) => JSON.parse(key).join(".")
551
- );
716
+ return Array.from(touched, (key) => segmentsFromKey(key).join("."));
552
717
  }
553
718
  function isTouched({ touched }) {
554
719
  return touched.size > 0;
555
720
  }
556
721
 
557
722
  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) {
723
+ const cache = getOrCreate(valuesCaches, form, () => ({
724
+ version: 0,
725
+ result: computeValues(form)
726
+ }));
727
+ if (cache.version > 0) {
563
728
  cache.result = computeValues(form);
564
729
  cache.version = 0;
565
730
  }
@@ -570,10 +735,10 @@
570
735
  const owned = /* @__PURE__ */ new Set();
571
736
  let merged = parsedValues ?? initialValues;
572
737
  for (const [key, value] of values) {
573
- merged = setOwned(merged, JSON.parse(key), value, owned);
738
+ merged = setOwned(merged, segmentsFromKey(key), value, owned);
574
739
  }
575
740
  for (const key of deleted) {
576
- merged = unset(merged, JSON.parse(key));
741
+ merged = unset(merged, segmentsFromKey(key));
577
742
  }
578
743
  return merged;
579
744
  }
@@ -647,7 +812,7 @@
647
812
  if (!hasLiveBranch(values, segments)) deleted.add(key);
648
813
  }
649
814
  if (!options?.keepTouched) touched.delete(key);
650
- if (!options?.keepError) errors.delete(key);
815
+ if (!options?.keepError && errors.delete(key)) bumpErrorsVersion(form);
651
816
  validating.delete(key);
652
817
  bumpDirtyVersion(form);
653
818
  bumpValuesVersion(form);
@@ -697,9 +862,9 @@
697
862
  function collectValueLeaves(node, segments, out) {
698
863
  if (node !== null && typeof node === "object") {
699
864
  if (Array.isArray(node)) {
700
- for (let i = 0; i < node.length; i++) {
701
- collectValueLeaves(node[i], [...segments, i], out);
702
- }
865
+ node.forEach(
866
+ (item, i) => collectValueLeaves(item, [...segments, i], out)
867
+ );
703
868
  return;
704
869
  }
705
870
  const keys = Object.keys(node);
@@ -712,18 +877,22 @@
712
877
  }
713
878
  out.push({ segments, value: node });
714
879
  }
715
- function reset(form, initialValues, options) {
716
- const keptValues = [];
880
+ function collectKeptValues(form, options) {
881
+ const kept = [];
717
882
  if (options?.keepValues) {
718
- collectValueLeaves(getValues(form), [], keptValues);
883
+ collectValueLeaves(getValues(form), [], kept);
719
884
  } else if (options?.keepDirtyValues) {
720
885
  for (const [key, value] of form.values) {
721
- const segments = JSON.parse(key);
886
+ const segments = segmentsFromKey(key);
722
887
  if (getDirtyBaseline(form, key, segments) !== value) {
723
- keptValues.push({ segments, value });
888
+ kept.push({ segments, value });
724
889
  }
725
890
  }
726
891
  }
892
+ return kept;
893
+ }
894
+ function reset(form, initialValues, options) {
895
+ const keptValues = collectKeptValues(form, options);
727
896
  form.initialValues = options?.keepDefaultValues ? form.initialValues : initialValues ?? form.initialValues;
728
897
  form.parsedValues = void 0;
729
898
  if (!options?.keepErrors) clearErrors(form);
@@ -769,6 +938,7 @@
769
938
  emit(emitter, "touched", path);
770
939
  }
771
940
  if (!options?.keepErrors && errors.delete(path.key)) {
941
+ bumpErrorsVersion(form);
772
942
  emit(emitter, "errors", path);
773
943
  }
774
944
  bumpDirtyVersion(form);
@@ -783,13 +953,17 @@
783
953
  validating.add(path.key);
784
954
  emit(emitter, "validating", path);
785
955
  }
956
+ function asErrorList(output) {
957
+ if (output === void 0) return null;
958
+ const list = Array.isArray(output) ? output : [output];
959
+ return list.length ? list : null;
960
+ }
786
961
  function registerValidatorByPath(form, path, registration) {
787
962
  let timer = null;
788
963
  let controller = null;
789
964
  let marked = false;
790
965
  let lock = null;
791
966
  let errorSource = null;
792
- const hasErrors2 = (errors) => errors !== void 0 && !(Array.isArray(errors) && errors.length === 0);
793
967
  const mark = () => {
794
968
  if (marked) return;
795
969
  marked = true;
@@ -803,44 +977,42 @@
803
977
  const runSync = () => {
804
978
  const sync = registration.sync();
805
979
  if (!sync) return false;
806
- const errors = sync(getValueByPath(form, path), { form, path });
807
- if (!hasErrors2(errors)) {
980
+ const gate = asErrorList(sync(getValueByPath(form, path), { form, path }));
981
+ if (!gate) {
808
982
  if (!registration.validate() || errorSource === "sync") {
809
983
  setErrorByPath(form, path, void 0);
810
984
  errorSource = null;
811
985
  }
812
986
  return false;
813
987
  }
814
- setErrorByPath(form, path, errors);
988
+ setErrorByPath(form, path, gate);
815
989
  errorSource = "sync";
816
990
  return true;
817
991
  };
818
992
  const collectSyncErrors = () => {
819
993
  const sync = registration.sync();
820
994
  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;
995
+ return asErrorList(sync(getValueByPath(form, path), { form, path }));
825
996
  };
826
997
  const land = (result) => {
827
998
  if (registration.asyncAlways?.()) {
828
999
  const gate = collectSyncErrors();
829
- const own = result === void 0 ? [] : Array.isArray(result) ? result : [result];
1000
+ const own = asErrorList(result) ?? [];
830
1001
  setErrorByPath(form, path, [...gate ?? [], ...own]);
831
- errorSource = hasErrors2(result) ? "validator" : gate ? "sync" : null;
1002
+ errorSource = own.length ? "validator" : gate ? "sync" : null;
832
1003
  } else {
833
1004
  setErrorByPath(form, path, result);
834
- errorSource = hasErrors2(result) ? "validator" : null;
1005
+ errorSource = asErrorList(result) ? "validator" : null;
835
1006
  }
836
1007
  };
837
- const supersede = () => {
1008
+ const cancel = () => {
838
1009
  if (timer !== null) {
839
1010
  clearTimeout(timer);
840
1011
  timer = null;
841
1012
  }
842
1013
  controller?.abort();
843
1014
  lock = {};
1015
+ unmark();
844
1016
  };
845
1017
  const runValidator = () => {
846
1018
  const fn = registration.validate();
@@ -868,13 +1040,11 @@
868
1040
  return;
869
1041
  }
870
1042
  mark();
871
- result.then(
872
- (error) => {
873
- if (lock === round) {
874
- land(error);
875
- }
1043
+ result.then((error) => {
1044
+ if (lock === round) {
1045
+ land(error);
876
1046
  }
877
- ).catch(() => {
1047
+ }).catch(() => {
878
1048
  }).finally(() => {
879
1049
  if (lock === round) {
880
1050
  unmark();
@@ -882,21 +1052,18 @@
882
1052
  }
883
1053
  });
884
1054
  };
1055
+ const gateOwnsKick = () => {
1056
+ if (!(runSync() && !registration.asyncAlways?.())) return false;
1057
+ cancel();
1058
+ return true;
1059
+ };
885
1060
  const run = () => {
886
1061
  timer = null;
887
- if (runSync() && !registration.asyncAlways?.()) {
888
- supersede();
889
- unmark();
890
- return;
891
- }
1062
+ if (gateOwnsKick()) return;
892
1063
  runValidator();
893
1064
  };
894
1065
  const kick = () => {
895
- if (runSync() && !registration.asyncAlways?.()) {
896
- supersede();
897
- unmark();
898
- return;
899
- }
1066
+ if (gateOwnsKick()) return;
900
1067
  if (!registration.validate()) return;
901
1068
  const debounce = registration.debounce();
902
1069
  if (debounce > 0) {
@@ -910,12 +1077,7 @@
910
1077
  form.validators.set(path.key, kick);
911
1078
  return () => {
912
1079
  form.validators.delete(path.key);
913
- if (timer !== null) {
914
- clearTimeout(timer);
915
- timer = null;
916
- }
917
- unmark();
918
- controller?.abort();
1080
+ cancel();
919
1081
  };
920
1082
  }
921
1083
  async function trigger(form, name, options) {
@@ -925,29 +1087,27 @@
925
1087
  () => keys2 === void 0 ? fieldsSettled(form) : keys2.every((key) => !form.validating.has(key)),
926
1088
  () => false
927
1089
  );
1090
+ const focusFirstError = (keys2) => {
1091
+ const firstKey = keys2 === void 0 ? form.errors.keys().next().value : keys2.find((key) => form.errors.has(key));
1092
+ if (firstKey !== void 0) emit(form.emitter, "focusError", firstKey);
1093
+ };
928
1094
  if (name === void 0) {
929
1095
  form.validators.forEach((validator) => validator());
930
1096
  await settle();
931
1097
  if (form.validate) await runFormValidate(form);
932
1098
  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
- }
1099
+ if (options?.shouldFocus) focusFirstError();
937
1100
  return !hasErrors(form);
938
1101
  }
939
1102
  const keys = typeof name === "string" || isSegmentsPath(name) ? [create$1(name).key] : name.map((one) => create$1(one).key);
940
1103
  keys.forEach((key) => form.validators.get(key)?.());
941
1104
  await settle(keys);
942
1105
  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
- }
1106
+ if (options?.shouldFocus) focusFirstError(keys);
947
1107
  return keys.every((key) => !form.errors.has(key));
948
1108
  }
949
1109
  function touchKeys(form, keys) {
950
- keys.forEach((key) => setTouchedByPath(form, create$1(JSON.parse(key))));
1110
+ keys.forEach((key) => setTouchedByPath(form, create$1(segmentsFromKey(key))));
951
1111
  }
952
1112
  function setFormErrors(form, result, segments = [], footprint) {
953
1113
  Object.entries(result).forEach(([key, value]) => {
@@ -956,16 +1116,9 @@
956
1116
  ...isIndex(key) ? [key] : normalizePath(key)
957
1117
  ];
958
1118
  if (typeof value === "string") {
959
- if (value) {
960
- setError(form, path, value);
961
- recordFootprint(form, path, footprint);
962
- }
963
- } else if (Array.isArray(value)) {
964
- setError(form, path, value);
965
- recordFootprint(form, path, footprint);
966
- } else if (isFieldError(value)) {
967
- setError(form, path, value);
968
- recordFootprint(form, path, footprint);
1119
+ if (value) landLeafError(form, path, value, footprint);
1120
+ } else if (Array.isArray(value) || isFieldError(value)) {
1121
+ landLeafError(form, path, value, footprint);
969
1122
  } else if (value && typeof value === "object") {
970
1123
  setFormErrors(form, value, path, footprint);
971
1124
  }
@@ -977,8 +1130,12 @@
977
1130
  const stored = form.errors.get(path.key);
978
1131
  if (stored) footprint.set(path.key, stored);
979
1132
  }
1133
+ function landLeafError(form, path, error, footprint) {
1134
+ setError(form, path, error);
1135
+ recordFootprint(form, path, footprint);
1136
+ }
980
1137
  function applyValidateResult(form, result) {
981
- const footprint = form.validateDeps ? getFormErrorFootprint(form) : void 0;
1138
+ const footprint = form.validateDeps || form.validateMode !== "onSubmit" ? getFormErrorFootprint(form) : void 0;
982
1139
  if (footprint) {
983
1140
  clearFormValidateErrors(form, footprint);
984
1141
  footprint.clear();
@@ -994,12 +1151,7 @@
994
1151
  }
995
1152
  const formErrorFootprints = /* @__PURE__ */ new WeakMap();
996
1153
  function getFormErrorFootprint(form) {
997
- let footprint = formErrorFootprints.get(form);
998
- if (!footprint) {
999
- footprint = /* @__PURE__ */ new Map();
1000
- formErrorFootprints.set(form, footprint);
1001
- }
1002
- return footprint;
1154
+ return getOrCreate(formErrorFootprints, form, () => /* @__PURE__ */ new Map());
1003
1155
  }
1004
1156
  function hasFormValidateErrors(form) {
1005
1157
  const footprint = formErrorFootprints.get(form);
@@ -1014,7 +1166,8 @@
1014
1166
  const stored = form.errors.get(key);
1015
1167
  if (stored !== written) continue;
1016
1168
  form.errors.delete(key);
1017
- emit(form.emitter, "errors", create$1(JSON.parse(key)));
1169
+ bumpErrorsVersion(form);
1170
+ emit(form.emitter, "errors", create$1(segmentsFromKey(key)));
1018
1171
  }
1019
1172
  }
1020
1173
  const FORM_VALIDATING_KEY = "__form_validate__";
@@ -1027,18 +1180,13 @@
1027
1180
  const SETTLED = /* @__PURE__ */ Symbol("form-validate-settled");
1028
1181
  const formValidateStates = /* @__PURE__ */ new WeakMap();
1029
1182
  function getFormValidateState(form) {
1030
- let state = formValidateStates.get(form);
1031
- if (!state) {
1032
- state = {
1033
- timer: null,
1034
- controller: null,
1035
- round: null,
1036
- marked: false,
1037
- waiters: []
1038
- };
1039
- formValidateStates.set(form, state);
1040
- }
1041
- return state;
1183
+ return getOrCreate(formValidateStates, form, () => ({
1184
+ timer: null,
1185
+ controller: null,
1186
+ round: null,
1187
+ marked: false,
1188
+ waiters: []
1189
+ }));
1042
1190
  }
1043
1191
  function runFormValidate(form) {
1044
1192
  const validate2 = form.validate;
@@ -1076,14 +1224,9 @@
1076
1224
  if (!validate2) return Promise.resolve();
1077
1225
  state.controller?.abort();
1078
1226
  const controller = state.controller = new AbortController();
1079
- let outcome;
1080
- try {
1081
- outcome = Promise.resolve(
1082
- validate2(getValues(form), { form, signal: controller.signal })
1083
- );
1084
- } catch (error) {
1085
- outcome = Promise.reject(error);
1086
- }
1227
+ const outcome = new Promise(
1228
+ (resolve) => resolve(validate2(getValues(form), { form, signal: controller.signal }))
1229
+ );
1087
1230
  return outcome.then(
1088
1231
  (result) => {
1089
1232
  if (state.round === round) applyValidateResult(form, result);
@@ -1109,27 +1252,29 @@
1109
1252
  else waiter.reject(outcome);
1110
1253
  }
1111
1254
  }
1255
+ function shouldKick(mode, cadence, touched, hasError, reValidateMode) {
1256
+ return mode === cadence || mode === "all" || mode === "onTouched" && touched || reValidateMode === cadence && hasError();
1257
+ }
1112
1258
  function revalidateFormOnChange(form, path, mode) {
1113
1259
  if (!form.validateDeps?.has(path.key) || !form.validate) return;
1114
- if (mode === "onChange" || mode === "all" || mode === "onTouched" && hasTouchedByPath(form, path) || form.reValidateMode === "onChange" && hasFormValidateErrors(form)) {
1260
+ if (shouldKick(
1261
+ mode,
1262
+ "onChange",
1263
+ hasTouchedByPath(form, path),
1264
+ () => hasFormValidateErrors(form),
1265
+ form.reValidateMode
1266
+ )) {
1115
1267
  runFormValidate(form).catch(() => {
1116
1268
  });
1117
1269
  }
1118
1270
  }
1119
1271
  const fieldValidateDeps = /* @__PURE__ */ new WeakMap();
1120
1272
  function registerFieldValidateDeps(form, key, depKeys) {
1121
- let deps = fieldValidateDeps.get(form);
1122
- if (!deps) {
1123
- deps = /* @__PURE__ */ new Map();
1124
- fieldValidateDeps.set(form, deps);
1125
- }
1273
+ const deps = getOrCreate(fieldValidateDeps, form, () => /* @__PURE__ */ new Map());
1126
1274
  for (const depKey of depKeys) {
1127
- let dependents = deps.get(depKey);
1128
- if (!dependents) {
1129
- dependents = /* @__PURE__ */ new Set();
1130
- deps.set(depKey, dependents);
1131
- }
1275
+ const dependents = deps.get(depKey) ?? /* @__PURE__ */ new Set();
1132
1276
  dependents.add(key);
1277
+ deps.set(depKey, dependents);
1133
1278
  }
1134
1279
  }
1135
1280
  function unregisterFieldValidateDeps(form, key, depKeys) {
@@ -1146,7 +1291,13 @@
1146
1291
  if (!dependents?.size) return;
1147
1292
  for (const dependent of dependents) {
1148
1293
  if (dependent === path.key) continue;
1149
- if (mode === "onChange" || mode === "all" || mode === "onTouched" && hasTouchedByPath(form, path) || form.reValidateMode === "onChange" && form.errors.has(dependent)) {
1294
+ if (shouldKick(
1295
+ mode,
1296
+ "onChange",
1297
+ hasTouchedByPath(form, path),
1298
+ () => form.errors.has(dependent),
1299
+ form.reValidateMode
1300
+ )) {
1150
1301
  form.validators.get(dependent)?.();
1151
1302
  }
1152
1303
  }
@@ -1188,11 +1339,7 @@
1188
1339
  }
1189
1340
  }
1190
1341
  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
- }
1342
+ const modes = getOrCreate(fieldModes, form, () => /* @__PURE__ */ new Map());
1196
1343
  const displaced = modes.has(path.key);
1197
1344
  const token = {};
1198
1345
  modes.set(path.key, { mode, token });
@@ -1203,10 +1350,38 @@
1203
1350
  const entry = modes?.get(path.key);
1204
1351
  if (modes && entry && entry.token === token) modes.delete(path.key);
1205
1352
  }
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")
1353
+ function firstMountedDescendantKey(form, ancestor) {
1354
+ const prefix = `${ancestor.key.slice(0, -1)},`;
1355
+ for (const key of fieldModes.get(form)?.keys() ?? []) {
1356
+ if (key.startsWith(prefix)) return key;
1357
+ }
1358
+ return void 0;
1359
+ }
1360
+ function fireFormValidate(form, cadence) {
1361
+ if (form.validateMode !== cadence || !form.validate) return;
1362
+ runFormValidate(form).catch(() => {
1363
+ });
1364
+ }
1365
+ function kickFieldValidator(form, path, mode, cadence, touched) {
1366
+ if (shouldKick(
1367
+ mode,
1368
+ cadence,
1369
+ touched,
1370
+ () => getFieldErrorsByPath(form, path).length > 0,
1371
+ form.reValidateMode
1372
+ ))
1208
1373
  form.validators.get(path.key)?.();
1374
+ }
1375
+ function runUserChangeGate(form, path, mode) {
1376
+ kickFieldValidator(
1377
+ form,
1378
+ path,
1379
+ mode,
1380
+ "onChange",
1381
+ hasTouchedByPath(form, path)
1382
+ );
1209
1383
  revalidateFormOnChange(form, path, mode);
1384
+ fireFormValidate(form, "onChange");
1210
1385
  revalidateDependentsOnChange(form, path, mode);
1211
1386
  }
1212
1387
  function userChangeByPath(form, path, value) {
@@ -1218,9 +1393,323 @@
1218
1393
  setTouchedByPath(form, path);
1219
1394
  const entry = fieldModes.get(form)?.get(path.key);
1220
1395
  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)?.();
1396
+ kickFieldValidator(form, path, entry.mode ?? form.mode, "onBlur", true);
1397
+ fireFormValidate(form, "onBlur");
1398
+ }
1399
+
1400
+ function removeFieldForUnmount(form, path) {
1401
+ const { key } = path;
1402
+ const snapshot = {
1403
+ present: form.values.has(key),
1404
+ value: form.values.get(key),
1405
+ touched: form.touched.has(key),
1406
+ errors: form.errors.get(key)
1407
+ };
1408
+ removeFieldByPath(form, path);
1409
+ return snapshot;
1410
+ }
1411
+ function restoreRemovedField(form, path, snapshot) {
1412
+ const { key } = path;
1413
+ if (snapshot.present) {
1414
+ setValueByPath(form, path, snapshot.value, { shouldDirty: false });
1415
+ } else {
1416
+ form.deleted.delete(key);
1417
+ bumpValuesVersion(form);
1418
+ emit(form.emitter, "change", path);
1419
+ }
1420
+ if (snapshot.touched) setTouchedByPath(form, path);
1421
+ if (snapshot.errors) setErrorByPath(form, path, snapshot.errors);
1422
+ }
1423
+
1424
+ function hasRuleConstraints(rules) {
1425
+ 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;
1426
+ }
1427
+ function defaultMessage(type, bound) {
1428
+ switch (type) {
1429
+ case "required":
1430
+ return "This field is required";
1431
+ case "min":
1432
+ return `Must be at least ${bound}`;
1433
+ case "max":
1434
+ return `Must be at most ${bound}`;
1435
+ case "minLength":
1436
+ return `Must be at least ${bound} characters`;
1437
+ case "maxLength":
1438
+ return `Must be at most ${bound} characters`;
1439
+ case "pattern":
1440
+ return "Invalid format";
1441
+ default:
1442
+ return "Invalid value";
1443
+ }
1444
+ }
1445
+ function resolveMessage(entry, bound) {
1446
+ return typeof entry === "function" ? entry(bound) : entry?.replace("{bound}", String(bound));
1447
+ }
1448
+ function numericMetric(value) {
1449
+ const n = Number(value);
1450
+ return Number.isNaN(n) ? void 0 : n;
1451
+ }
1452
+ function sizedMetric(value) {
1453
+ return typeof value === "string" || Array.isArray(value) ? value.length : void 0;
1454
+ }
1455
+ const BOUND_CHECKS = [
1456
+ ["min", numericMetric, (metric, bound) => metric < bound],
1457
+ ["max", numericMetric, (metric, bound) => metric > bound],
1458
+ ["minLength", sizedMetric, (metric, bound) => metric < bound],
1459
+ ["maxLength", sizedMetric, (metric, bound) => metric > bound]
1460
+ ];
1461
+ function rulesToValidator(rules, formMessages) {
1462
+ return (value, meta) => {
1463
+ if (rules.required) {
1464
+ if (value === "" || value === void 0 || value === null || Array.isArray(value) && value.length === 0) {
1465
+ return [
1466
+ {
1467
+ type: "required",
1468
+ message: typeof rules.required === "string" ? rules.required : resolveMessage(formMessages?.required) ?? defaultMessage("required")
1469
+ }
1470
+ ];
1471
+ }
1472
+ }
1473
+ const errors = [];
1474
+ const message = (type, bound) => rules.messages?.[type] ?? resolveMessage(formMessages?.[type], bound) ?? defaultMessage(type, bound);
1475
+ for (const [type, measure, fails] of BOUND_CHECKS) {
1476
+ const bound = rules[type];
1477
+ if (bound === void 0) continue;
1478
+ const metric = measure(value);
1479
+ if (metric !== void 0 && fails(metric, bound)) {
1480
+ errors.push({ type, message: message(type, bound) });
1481
+ }
1482
+ }
1483
+ if (rules.pattern && !rules.pattern.value.test(value)) {
1484
+ errors.push({
1485
+ type: "pattern",
1486
+ // pattern.message is type-required but JS consumers may omit it.
1487
+ message: rules.messages?.pattern ?? rules.pattern.message ?? resolveMessage(formMessages?.pattern) ?? defaultMessage("pattern")
1488
+ });
1489
+ }
1490
+ if (rules.validate !== void 0) {
1491
+ const fns = typeof rules.validate === "function" ? { validate: rules.validate } : rules.validate;
1492
+ for (const [type, fn] of Object.entries(fns)) {
1493
+ const result = fn(value, meta);
1494
+ if (result === void 0) continue;
1495
+ for (const entry of Array.isArray(result) ? result : [result]) {
1496
+ errors.push(
1497
+ typeof entry === "string" ? { type, message: entry } : { ...entry, type }
1498
+ );
1499
+ }
1500
+ }
1501
+ }
1502
+ return errors.length ? errors : void 0;
1503
+ };
1504
+ }
1505
+ function rulesToConstraintAttrs(rules) {
1506
+ const attrs = {};
1507
+ if (rules.required) attrs.required = true;
1508
+ for (const key of ["min", "max", "minLength", "maxLength"]) {
1509
+ if (rules[key] !== void 0) attrs[key] = rules[key];
1510
+ }
1511
+ if (rules.pattern) attrs.pattern = rules.pattern.value.source;
1512
+ return attrs;
1513
+ }
1514
+
1515
+ function registerField(form, name, options) {
1516
+ const path = create$1(name);
1517
+ const {
1518
+ mode,
1519
+ shouldUnregister,
1520
+ eventToValue,
1521
+ valueAsNumber,
1522
+ valueAsDate,
1523
+ rules
1524
+ } = options ?? {};
1525
+ const toValue = eventToValue ?? ((e) => {
1526
+ const target = e?.target;
1527
+ if (!target) return e;
1528
+ if (target.type === "file") return target.files;
1529
+ if (target.type === "checkbox") return target.checked;
1530
+ if (valueAsNumber) return target.valueAsNumber;
1531
+ if (valueAsDate) return target.valueAsDate;
1532
+ return target.value;
1533
+ });
1534
+ let el = null;
1535
+ let modeToken = null;
1536
+ let disposeValidator = null;
1537
+ let snapshot = null;
1538
+ let offFocus = null;
1539
+ let offBulkSync = null;
1540
+ const syncDom = () => {
1541
+ if (!el || el.type === "file") return;
1542
+ const next = getValueByPath(form, path);
1543
+ const asString = next == null ? "" : String(next);
1544
+ if (el.value !== asString) el.value = asString;
1545
+ };
1546
+ const attach = (node) => {
1547
+ if (snapshot) {
1548
+ restoreRemovedField(form, path, snapshot);
1549
+ snapshot = null;
1550
+ }
1551
+ el = node;
1552
+ if (node.type !== "file" && getValueByPath(form, path) === void 0) {
1553
+ seedValueByPath(
1554
+ form,
1555
+ path,
1556
+ node.type === "checkbox" ? node.checked : node.value
1557
+ );
1558
+ emitChangeByPath(form, path);
1559
+ }
1560
+ modeToken = registerFieldMode(form, path, mode).token;
1561
+ if (rules && hasRuleConstraints(rules)) {
1562
+ const { required, ...rest } = rules;
1563
+ const requiredGate = required !== void 0 ? rulesToValidator({ required }, form.messages) : void 0;
1564
+ disposeValidator = registerValidatorByPath(form, path, {
1565
+ validate: () => hasRuleConstraints(rest) ? rulesToValidator(rest, form.messages) : void 0,
1566
+ debounce: () => 0,
1567
+ sync: () => requiredGate
1568
+ });
1569
+ }
1570
+ offFocus = on(
1571
+ form.emitter,
1572
+ "focusError",
1573
+ (key, options2) => {
1574
+ if (key !== path.key || !el || typeof el.focus !== "function") return;
1575
+ el.focus();
1576
+ if (options2?.shouldSelect && typeof el.select === "function") {
1577
+ el.select();
1578
+ }
1579
+ }
1580
+ );
1581
+ offBulkSync = on(form.emitter, "change", (changed) => {
1582
+ if (changed) return;
1583
+ syncDom();
1584
+ });
1585
+ };
1586
+ const detach = () => {
1587
+ if (modeToken) {
1588
+ unregisterFieldMode(form, path, modeToken);
1589
+ modeToken = null;
1590
+ }
1591
+ if (disposeValidator) {
1592
+ disposeValidator();
1593
+ disposeValidator = null;
1594
+ }
1595
+ if (offFocus) {
1596
+ offFocus();
1597
+ offFocus = null;
1598
+ }
1599
+ if (offBulkSync) {
1600
+ offBulkSync();
1601
+ offBulkSync = null;
1602
+ }
1603
+ el = null;
1604
+ if ((shouldUnregister ?? form.shouldUnregister) !== false) {
1605
+ snapshot = removeFieldForUnmount(form, path);
1606
+ }
1607
+ };
1608
+ return {
1609
+ name: path.key,
1610
+ onChange: (e) => changeValueByPath(form, path, toValue(e)),
1611
+ onBlur: () => userBlur(form, path),
1612
+ ref: (node) => {
1613
+ if (node) attach(node);
1614
+ else detach();
1615
+ }
1616
+ };
1617
+ }
1618
+
1619
+ function readArray(form, path) {
1620
+ const value = getValueByPath(form, path);
1621
+ return Array.isArray(value) ? value : [];
1622
+ }
1623
+ function appendValueByPath(form, path, value) {
1624
+ const arr = readArray(form, path);
1625
+ setValueByPath(form, path, [...arr, value]);
1626
+ }
1627
+ function prependValueByPath(form, path, value) {
1628
+ const arr = readArray(form, path);
1629
+ setValueByPath(form, path, [value, ...arr]);
1630
+ }
1631
+ function insertValueByPath(form, path, index, value) {
1632
+ const arr = readArray(form, path);
1633
+ if (index < 0 || index > arr.length) return false;
1634
+ setValueByPath(form, path, [
1635
+ ...arr.slice(0, index),
1636
+ value,
1637
+ ...arr.slice(index)
1638
+ ]);
1639
+ return true;
1640
+ }
1641
+ function removeValueByPath(form, path, indices) {
1642
+ const arr = readArray(form, path);
1643
+ const drop = /* @__PURE__ */ new Set();
1644
+ for (const index of Array.isArray(indices) ? indices : [indices]) {
1645
+ if (index >= 0 && index < arr.length) drop.add(index);
1646
+ }
1647
+ if (drop.size === 0) return [];
1648
+ const dropped = [...drop].sort((a, b) => b - a);
1649
+ setValueByPath(
1650
+ form,
1651
+ path,
1652
+ arr.filter((_, i) => !drop.has(i))
1653
+ );
1654
+ return dropped;
1655
+ }
1656
+ function moveValueByPath(form, path, from, to) {
1657
+ const arr = readArray(form, path);
1658
+ if (from < 0 || from >= arr.length || to < 0 || to >= arr.length) {
1659
+ return false;
1660
+ }
1661
+ if (from === to) return false;
1662
+ const next = [...arr];
1663
+ const [item] = next.splice(from, 1);
1664
+ next.splice(to, 0, item);
1665
+ setValueByPath(form, path, next);
1666
+ return true;
1667
+ }
1668
+ function swapValuesByPath(form, path, from, to) {
1669
+ const arr = readArray(form, path);
1670
+ if (from < 0 || from >= arr.length || to < 0 || to >= arr.length) {
1671
+ return false;
1672
+ }
1673
+ if (from === to) return false;
1674
+ const next = [...arr];
1675
+ [next[from], next[to]] = [next[to], next[from]];
1676
+ setValueByPath(form, path, next);
1677
+ return true;
1678
+ }
1679
+ function replaceValuesByPath(form, path, values) {
1680
+ setValueByPath(form, path, [...values]);
1681
+ }
1682
+ function updateValueByPath(form, path, index, value) {
1683
+ const arr = readArray(form, path);
1684
+ if (index < 0 || index >= arr.length) return false;
1685
+ const next = [...arr];
1686
+ next[index] = value;
1687
+ setValueByPath(form, path, next);
1688
+ return true;
1689
+ }
1690
+ function appendValue(form, name, value) {
1691
+ appendValueByPath(form, create$1(name), value);
1692
+ }
1693
+ function prependValue(form, name, value) {
1694
+ prependValueByPath(form, create$1(name), value);
1695
+ }
1696
+ function insertValue(form, name, index, value) {
1697
+ return insertValueByPath(form, create$1(name), index, value);
1698
+ }
1699
+ function removeValue(form, name, indices) {
1700
+ return removeValueByPath(form, create$1(name), indices);
1701
+ }
1702
+ function moveValue(form, name, from, to) {
1703
+ return moveValueByPath(form, create$1(name), from, to);
1704
+ }
1705
+ function swapValues(form, name, from, to) {
1706
+ return swapValuesByPath(form, create$1(name), from, to);
1707
+ }
1708
+ function replaceValues(form, name, values) {
1709
+ replaceValuesByPath(form, create$1(name), values);
1710
+ }
1711
+ function updateValue(form, name, index, value) {
1712
+ return updateValueByPath(form, create$1(name), index, value);
1224
1713
  }
1225
1714
 
1226
1715
  function setIsSubmitting(form, value) {
@@ -1255,9 +1744,7 @@
1255
1744
  }
1256
1745
  function getNativeErrors(formEl) {
1257
1746
  const errors = [];
1258
- const { elements } = formEl;
1259
- for (let i = 0; i < elements.length; i++) {
1260
- const el = elements[i];
1747
+ for (const el of formEl.elements) {
1261
1748
  if (el.name && typeof el.checkValidity === "function" && !el.checkValidity()) {
1262
1749
  errors.push({
1263
1750
  path: nameToPath(el.name),
@@ -1274,18 +1761,21 @@
1274
1761
  onValidSubmit,
1275
1762
  onInvalidSubmit,
1276
1763
  onAction,
1277
- shouldFocusError = true
1764
+ shouldFocusError = true,
1765
+ shouldUseNativeValidation = form.shouldUseNativeValidation
1278
1766
  } = options ?? {};
1279
1767
  return async (e) => {
1280
1768
  if (e && typeof e.preventDefault === "function") {
1281
1769
  e.preventDefault();
1282
1770
  }
1283
1771
  const formEl = e?.currentTarget;
1772
+ if (form.isSubmitting) return;
1773
+ clearServerErrors(form);
1284
1774
  form.isSubmitted = true;
1285
1775
  setIsSubmitting(form, true);
1286
1776
  incrementSubmitCount(form);
1287
1777
  const values = getValues(form);
1288
- if (formEl && typeof formEl.checkValidity === "function" && formEl.checkValidity() === false) {
1778
+ if (shouldUseNativeValidation && formEl && typeof formEl.checkValidity === "function" && formEl.checkValidity() === false) {
1289
1779
  formEl.reportValidity();
1290
1780
  if (shouldFocusError && typeof formEl.querySelector === "function") {
1291
1781
  const invalid = formEl.querySelector(":invalid");
@@ -1311,7 +1801,14 @@
1311
1801
  const submitted = getValues(form);
1312
1802
  if (onSubmit) await onSubmit(submitted, e);
1313
1803
  if (onValidSubmit) await onValidSubmit(submitted, e);
1314
- if (onAction) await onAction(submitted, e);
1804
+ if (onAction) {
1805
+ const result = await onAction(submitted, e);
1806
+ if (result && typeof result === "object" && result.errors !== void 0 && typeof result.errors === "object") {
1807
+ setServerErrors(form, result.errors);
1808
+ setSubmitSuccessful(form, false);
1809
+ return;
1810
+ }
1811
+ }
1315
1812
  setSubmitSuccessful(form, true);
1316
1813
  } catch {
1317
1814
  setSubmitSuccessful(form, false);
@@ -1327,19 +1824,45 @@
1327
1824
  else emit(form.emitter, "focusError", key);
1328
1825
  }
1329
1826
 
1827
+ function seedInitialValues(form, emitter, source) {
1828
+ if (!isPromise(source)) {
1829
+ form.initialValues = source;
1830
+ return;
1831
+ }
1832
+ form.isLoading = true;
1833
+ emit(emitter, "loading");
1834
+ Promise.resolve(source).then(
1835
+ (resolved) => {
1836
+ setInitialValues(form, resolved ?? {});
1837
+ form.isLoading = false;
1838
+ emit(emitter, "loading");
1839
+ },
1840
+ (error) => {
1841
+ form.isLoading = false;
1842
+ emit(emitter, "loading");
1843
+ }
1844
+ );
1845
+ }
1330
1846
  function create(options) {
1331
1847
  const emitter = create$2();
1332
1848
  _setMaxListeners(emitter, 0);
1333
- let source = options?.initialValues ?? {};
1334
- if (typeof source === "function") source = source();
1849
+ const initialSource = options?.initialValues ?? {};
1850
+ const source = typeof initialSource === "function" ? initialSource() : initialSource;
1851
+ const validateOption = options?.validate;
1852
+ const wrappedValidate = validateOption && hasStandardProps(validateOption) ? schemaToFormValidator(
1853
+ validateOption
1854
+ ) : validateOption;
1335
1855
  const form = {
1336
1856
  emitter,
1337
1857
  ...options,
1858
+ validate: wrappedValidate,
1338
1859
  mode: options?.mode ?? "onSubmit",
1339
1860
  reValidateMode: options?.reValidateMode ?? "onChange",
1861
+ validateMode: options?.validateMode ?? "onSubmit",
1340
1862
  disabled: options?.disabled ?? false,
1341
1863
  validateOnMount: options?.validateOnMount ?? false,
1342
1864
  asyncAlways: options?.asyncAlways ?? false,
1865
+ shouldUseNativeValidation: options?.shouldUseNativeValidation ?? true,
1343
1866
  validateDeps: options?.validateDeps ? new Set(options.validateDeps.map((dep) => create$1(dep).key)) : void 0,
1344
1867
  initialValues: {},
1345
1868
  values: /* @__PURE__ */ new Map(),
@@ -1354,116 +1877,47 @@
1354
1877
  submitCount: 0,
1355
1878
  isSubmitSuccessful: void 0,
1356
1879
  isLoading: false,
1357
- status: void 0
1880
+ status: void 0,
1881
+ register: (name, registerOptions) => registerField(form, name, registerOptions)
1358
1882
  };
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
- }
1883
+ seedInitialValues(form, emitter, source);
1376
1884
  return form;
1377
1885
  }
1378
1886
 
1379
- function defaultMessage(type, bound) {
1380
- switch (type) {
1381
- case "required":
1382
- return "This field is required";
1383
- case "min":
1384
- return `Must be at least ${bound}`;
1385
- case "max":
1386
- return `Must be at most ${bound}`;
1387
- case "minLength":
1388
- return `Must be at least ${bound} characters`;
1389
- case "maxLength":
1390
- return `Must be at most ${bound} characters`;
1391
- case "pattern":
1392
- return "Invalid format";
1393
- default:
1394
- return "Invalid value";
1395
- }
1396
- }
1397
- function rulesToValidator(rules) {
1398
- return (value, meta) => {
1399
- if (rules.required) {
1400
- if (value === "" || value === void 0 || value === null || Array.isArray(value) && value.length === 0) {
1401
- return [
1402
- {
1403
- type: "required",
1404
- message: typeof rules.required === "string" ? rules.required : defaultMessage("required")
1405
- }
1406
- ];
1407
- }
1408
- }
1409
- const errors = [];
1410
- const message = (type, bound) => rules.messages?.[type] ?? defaultMessage(type, bound);
1411
- if (rules.min !== void 0) {
1412
- const n = Number(value);
1413
- if (!Number.isNaN(n) && n < rules.min) {
1414
- errors.push({ type: "min", message: message("min", rules.min) });
1415
- }
1416
- }
1417
- if (rules.max !== void 0) {
1418
- const n = Number(value);
1419
- if (!Number.isNaN(n) && n > rules.max) {
1420
- errors.push({ type: "max", message: message("max", rules.max) });
1421
- }
1422
- }
1423
- const isSized = typeof value === "string" || Array.isArray(value);
1424
- if (rules.minLength !== void 0 && isSized && value.length < rules.minLength) {
1425
- errors.push({
1426
- type: "minLength",
1427
- message: message("minLength", rules.minLength)
1428
- });
1429
- }
1430
- if (rules.maxLength !== void 0 && isSized && value.length > rules.maxLength) {
1431
- errors.push({
1432
- type: "maxLength",
1433
- message: message("maxLength", rules.maxLength)
1434
- });
1435
- }
1436
- if (rules.pattern && !rules.pattern.value.test(value)) {
1437
- errors.push({
1438
- type: "pattern",
1439
- // pattern.message is type-required but JS consumers may omit it.
1440
- message: rules.messages?.pattern ?? rules.pattern.message ?? defaultMessage("pattern")
1441
- });
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
- }
1455
- return errors.length ? errors : void 0;
1456
- };
1457
- }
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;
1887
+ function errorIdFromKey(key) {
1888
+ const id = key.replace(/["'[\],\s]+/g, "-").replace(/^-+|-+$/g, "");
1889
+ return id || "field";
1890
+ }
1891
+ function fieldErrorId(name) {
1892
+ return errorIdFromKey(create$1(name).key);
1893
+ }
1894
+
1895
+ const fieldDisabledRegistry = /* @__PURE__ */ new WeakMap();
1896
+ function registerFieldDisabled(form, path, disabled) {
1897
+ if (disabled === void 0) return null;
1898
+ const registry = getOrCreate(fieldDisabledRegistry, form, () => /* @__PURE__ */ new Map());
1899
+ const token = {};
1900
+ registry.set(path.key, { disabled, token });
1901
+ emit(form.emitter, "disabled", path);
1902
+ return { token };
1903
+ }
1904
+ function unregisterFieldDisabled(form, path, token) {
1905
+ const registry = fieldDisabledRegistry.get(form);
1906
+ const entry = registry?.get(path.key);
1907
+ if (registry && entry && entry.token === token) {
1908
+ registry.delete(path.key);
1909
+ emit(form.emitter, "disabled", path);
1910
+ }
1911
+ }
1912
+ function hasDisabledAncestor(form, path) {
1913
+ const registry = fieldDisabledRegistry.get(form);
1914
+ if (!registry?.size) return false;
1915
+ const segments = path.value;
1916
+ for (let i = 1; i < segments.length; i++) {
1917
+ const prefix = JSON.stringify(segments.slice(0, i));
1918
+ if (registry.get(prefix)?.disabled) return true;
1919
+ }
1920
+ return false;
1467
1921
  }
1468
1922
 
1469
1923
  function isDescendant(key, ancestorKey) {
@@ -1495,7 +1949,62 @@
1495
1949
  });
1496
1950
  return unsubscribes.length === 1 ? unsubscribes[0] : () => unsubscribes.forEach((unsubscribe) => unsubscribe());
1497
1951
  }
1952
+ function watch(form, event, getter, isEqual) {
1953
+ const cache = { hasValue: false };
1954
+ const consumers = /* @__PURE__ */ new Set();
1955
+ const wake = () => {
1956
+ if (isEqual && cache.hasValue) {
1957
+ const next = getter();
1958
+ if (isEqual(cache.value, next)) return;
1959
+ cache.value = next;
1960
+ } else {
1961
+ cache.value = getter();
1962
+ cache.hasValue = true;
1963
+ }
1964
+ consumers.forEach((invalidate) => invalidate());
1965
+ };
1966
+ const off = on(form.emitter, event, wake);
1967
+ return {
1968
+ getSnapshot: () => {
1969
+ if (!cache.hasValue) {
1970
+ cache.value = getter();
1971
+ cache.hasValue = true;
1972
+ }
1973
+ return cache.value;
1974
+ },
1975
+ subscribe: (invalidate) => {
1976
+ consumers.add(invalidate);
1977
+ return () => {
1978
+ consumers.delete(invalidate);
1979
+ };
1980
+ },
1981
+ dispose: () => {
1982
+ off();
1983
+ consumers.clear();
1984
+ }
1985
+ };
1986
+ }
1987
+
1988
+ function pathFromKey(key) {
1989
+ return create$1(segmentsFromKey(key));
1990
+ }
1991
+ function usePath(name) {
1992
+ const key = React.useMemo(() => create$1(normalizePath(name)).key, [name]);
1993
+ return React.useMemo(() => pathFromKey(key), [key]);
1994
+ }
1498
1995
 
1996
+ function seedIfChanged(form, seeded, source, resetOptions) {
1997
+ if (seeded.done && (seeded.source === source || isEqual(seeded.source, source))) {
1998
+ return;
1999
+ }
2000
+ seeded.done = true;
2001
+ seeded.source = source;
2002
+ if (resetOptions !== void 0) {
2003
+ reset(form, source, resetOptions);
2004
+ } else {
2005
+ setInitialValues(form, source);
2006
+ }
2007
+ }
1499
2008
  function useForm(options) {
1500
2009
  const [form] = React.useState(() => {
1501
2010
  const created = create(options);
@@ -1506,6 +2015,7 @@
1506
2015
  });
1507
2016
  const initialValues = options && options.initialValues;
1508
2017
  const values = options && options.values;
2018
+ const resetOptions = options && options.resetOptions;
1509
2019
  const seededRef = React.useRef(null);
1510
2020
  if (seededRef.current === null)
1511
2021
  seededRef.current = { done: false, source: void 0 };
@@ -1514,28 +2024,15 @@
1514
2024
  if (typeof initialValues === "function" || isPromise(initialValues)) {
1515
2025
  return;
1516
2026
  }
1517
- const seeded = seededRef.current;
1518
- if (seeded.done && (seeded.source === initialValues || isEqual(seeded.source, initialValues))) {
1519
- return;
1520
- }
1521
- seeded.done = true;
1522
- seeded.source = initialValues;
1523
- setInitialValues(form, initialValues);
2027
+ seedIfChanged(form, seededRef.current, initialValues);
1524
2028
  }, [form, initialValues]);
1525
2029
  const controlledRef = React.useRef(null);
1526
- if (controlledRef.current === null) {
2030
+ if (controlledRef.current === null)
1527
2031
  controlledRef.current = { done: false, source: void 0 };
1528
- }
1529
2032
  React.useEffect(() => {
1530
2033
  if (values === void 0) return;
1531
- const seeded = controlledRef.current;
1532
- if (seeded.done && (seeded.source === values || isEqual(seeded.source, values))) {
1533
- return;
1534
- }
1535
- seeded.done = true;
1536
- seeded.source = values;
1537
- setInitialValues(form, values);
1538
- }, [form, values]);
2034
+ seedIfChanged(form, controlledRef.current, values, resetOptions);
2035
+ }, [form, values, resetOptions]);
1539
2036
  React.useEffect(() => {
1540
2037
  if (!form.validateOnMount || !form.validate) return;
1541
2038
  const run = () => {
@@ -1603,8 +2100,7 @@
1603
2100
  const { key } = path;
1604
2101
  const scope = options?.exact === false ? "branch" : "leaf";
1605
2102
  const subscribeFactory = React.useCallback(
1606
- (invalidate) => onPathEvent(emitter, "change", path, scope, invalidate),
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
2103
+ (invalidate) => onPathEvent(emitter, "change", pathFromKey(key), scope, invalidate),
1608
2104
  [emitter, key, scope]
1609
2105
  );
1610
2106
  return useWatchCore(subscribeFactory, () => {
@@ -1615,18 +2111,26 @@
1615
2111
  return value === void 0 ? options?.defaultValue : value;
1616
2112
  });
1617
2113
  }
2114
+ function useValues(form) {
2115
+ return useWatch(form, "change", () => getValues(form));
2116
+ }
1618
2117
  function useTouched(form, name) {
1619
2118
  return useTouchedByPath(form, create$1(name));
1620
2119
  }
1621
- function useTouchedByPath(form, path) {
2120
+ function useKeyWatch(form, path, event, getter) {
1622
2121
  const { emitter } = form;
1623
2122
  const { key } = path;
1624
2123
  const subscribeFactory = React.useCallback(
1625
- (invalidate) => onKeyEvent(emitter, "touched", key, invalidate),
1626
- [emitter, key]
2124
+ (invalidate) => onKeyEvent(emitter, event, key, invalidate),
2125
+ [emitter, event, key]
1627
2126
  );
1628
- return useWatchCore(
1629
- subscribeFactory,
2127
+ return useWatchCore(subscribeFactory, getter);
2128
+ }
2129
+ function useTouchedByPath(form, path) {
2130
+ return useKeyWatch(
2131
+ form,
2132
+ path,
2133
+ "touched",
1630
2134
  hasTouchedByPath.bind(null, form, path)
1631
2135
  );
1632
2136
  }
@@ -1634,26 +2138,21 @@
1634
2138
  return useErrorByPath(form, create$1(name))?.message;
1635
2139
  }
1636
2140
  function useErrorByPath(form, path) {
1637
- const { emitter } = form;
1638
- const { key } = path;
1639
- const subscribeFactory = React.useCallback(
1640
- (invalidate) => onKeyEvent(emitter, "errors", key, invalidate),
1641
- [emitter, key]
2141
+ return useKeyWatch(
2142
+ form,
2143
+ path,
2144
+ "errors",
2145
+ getErrorByPath.bind(null, form, path)
1642
2146
  );
1643
- return useWatchCore(subscribeFactory, getErrorByPath.bind(null, form, path));
1644
2147
  }
1645
2148
  function useFieldErrors(form, name) {
1646
2149
  return useFieldErrorsByPath(form, create$1(name));
1647
2150
  }
1648
2151
  function useFieldErrorsByPath(form, path) {
1649
- const { emitter } = form;
1650
- const { key } = path;
1651
- const subscribeFactory = React.useCallback(
1652
- (invalidate) => onKeyEvent(emitter, "errors", key, invalidate),
1653
- [emitter, key]
1654
- );
1655
- return useWatchCore(
1656
- subscribeFactory,
2152
+ return useKeyWatch(
2153
+ form,
2154
+ path,
2155
+ "errors",
1657
2156
  getFieldErrorsByPath.bind(null, form, path)
1658
2157
  );
1659
2158
  }
@@ -1667,8 +2166,7 @@
1667
2166
  const { emitter } = form;
1668
2167
  const { key } = path;
1669
2168
  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
2169
+ (invalidate) => onPathEvent(emitter, "change", pathFromKey(key), "leaf", invalidate),
1672
2170
  [emitter, key]
1673
2171
  );
1674
2172
  return useWatchCore(subscribeFactory, () => isFieldDirtyByPath(form, path));
@@ -1690,14 +2188,22 @@
1690
2188
  "disabled",
1691
2189
  "loading"
1692
2190
  ];
2191
+ function subscribeFormStateEvents(emitter, invalidate) {
2192
+ const offs = FORM_STATE_EVENTS.map((event) => on(emitter, event, invalidate));
2193
+ return () => {
2194
+ for (const off of offs) off();
2195
+ };
2196
+ }
1693
2197
  function getFormState(form) {
2198
+ const anyErrors = hasErrors(form);
1694
2199
  return {
1695
2200
  isDirty: isDirty(form),
1696
2201
  dirtyFields: getDirtyFields(form),
1697
2202
  isTouched: form.touched.size > 0,
1698
2203
  touchedFields: getTouchedFields(form),
1699
- hasErrors: hasErrors(form),
1700
- isValid: !hasErrors(form),
2204
+ hasErrors: anyErrors,
2205
+ isValid: !anyErrors,
2206
+ errors: getErrorsRecord(form),
1701
2207
  isSubmitting: form.isSubmitting,
1702
2208
  isSubmitted: form.isSubmitted,
1703
2209
  isValidating: form.validating.size > 0,
@@ -1709,26 +2215,32 @@
1709
2215
  }
1710
2216
  function isSameFormState(a, b) {
1711
2217
  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;
2218
+ return a.isDirty === b.isDirty && a.dirtyFields === b.dirtyFields && a.isTouched === b.isTouched && sameTouched && a.hasErrors === b.hasErrors && a.isValid === b.isValid && a.errors === b.errors && 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
2219
  }
1714
2220
  function useFormState(form) {
1715
2221
  const getter = React.useCallback(() => getFormState(form), [form]);
1716
2222
  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
- },
2223
+ (invalidate) => subscribeFormStateEvents(form.emitter, invalidate),
1725
2224
  [form.emitter]
1726
2225
  );
1727
2226
  return useWatchCore(subscribeFactory, getter, isSameFormState);
1728
2227
  }
2228
+ function useStore(form, selector, isEqual2) {
2229
+ const subscribeFactory = React.useCallback(
2230
+ (invalidate) => subscribeFormStateEvents(form.emitter, invalidate),
2231
+ [form.emitter]
2232
+ );
2233
+ return useWatchCore(subscribeFactory, selector, isEqual2);
2234
+ }
1729
2235
  function useHasErrors(form) {
1730
2236
  return useWatch(form, "errors", hasErrors.bind(null, form));
1731
2237
  }
2238
+ function useErrors(form) {
2239
+ return useWatch(form, "errors", () => getErrorsRecord(form));
2240
+ }
2241
+ function useErrorsTree(form) {
2242
+ return useWatch(form, "errors", () => getErrorsTree(form));
2243
+ }
1732
2244
  function useIsValid(form) {
1733
2245
  return useWatch(form, "errors", () => !hasErrors(form));
1734
2246
  }
@@ -1779,11 +2291,6 @@
1779
2291
  return useFieldErrorsByPath(form, create$1(FORM_ERROR));
1780
2292
  }
1781
2293
 
1782
- function usePath(name) {
1783
- const path = React.useMemo(() => create$1(normalizePath(name)), [name]);
1784
- return React.useMemo(() => path, [path.key]);
1785
- }
1786
-
1787
2294
  function useStage(value) {
1788
2295
  const ref = React.useRef(value);
1789
2296
  ref.current = value;
@@ -1798,38 +2305,56 @@
1798
2305
  }
1799
2306
  function useUnmountRestore(teardown, restore) {
1800
2307
  const removedRef = React.useRef(false);
2308
+ const teardownRef = useStage(teardown);
2309
+ const restoreRef = useStage(restore);
1801
2310
  React.useEffect(() => {
2311
+ const teardownOnce = teardownRef.current;
2312
+ const restoreOnce = restoreRef.current;
1802
2313
  if (removedRef.current) {
1803
2314
  removedRef.current = false;
1804
- restore();
2315
+ restoreOnce();
1805
2316
  }
1806
2317
  return () => {
1807
2318
  removedRef.current = true;
1808
- teardown();
2319
+ teardownOnce();
1809
2320
  };
1810
- }, []);
2321
+ }, [removedRef, teardownRef, restoreRef]);
2322
+ }
2323
+ function useUnmountFieldRemoval(form, path, shouldUnregister) {
2324
+ const removalSnapshotRef = React.useRef(null);
2325
+ const teardownOnUnmount = useStageFn(() => {
2326
+ if ((shouldUnregister ?? form.shouldUnregister) === false) return;
2327
+ removalSnapshotRef.current = removeFieldForUnmount(form, path);
2328
+ });
2329
+ const restoreAfterStrictMode = useStageFn(() => {
2330
+ const snapshot = removalSnapshotRef.current;
2331
+ removalSnapshotRef.current = null;
2332
+ if (snapshot) restoreRemovedField(form, path, snapshot);
2333
+ });
2334
+ useUnmountRestore(teardownOnUnmount, restoreAfterStrictMode);
1811
2335
  }
1812
2336
 
2337
+ function schemaAsValidator(validate) {
2338
+ return validate && hasStandardProps(validate) ? schemaToFieldValidator(validate) : validate;
2339
+ }
1813
2340
  function useValidate(validate, path, formProp, options) {
1814
2341
  const contextForm = React.useContext(FormContext);
1815
2342
  const form = formProp || contextForm;
1816
2343
  if (!form) throw new Error("no form provided");
1817
- const validateRef = React.useRef(validate);
1818
- validateRef.current = validate;
1819
- const debounceRef = React.useRef(options?.debounce ?? 0);
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;
2344
+ const validateRef = useStage(schemaAsValidator(validate));
2345
+ const debounceRef = useStage(options?.debounce ?? 0);
2346
+ const syncRef = useStage(options?.sync);
2347
+ const asyncAlwaysRef = useStage(options?.asyncAlways ?? false);
2348
+ const validateOnMountRef = useStage(options?.validateOnMount);
1825
2349
  React.useEffect(() => {
1826
- const dispose = registerValidatorByPath(form, path, {
2350
+ const spath = pathFromKey(path.key);
2351
+ const dispose = registerValidatorByPath(form, spath, {
1827
2352
  validate: () => validateRef.current,
1828
2353
  debounce: () => debounceRef.current,
1829
2354
  sync: () => syncRef.current,
1830
2355
  asyncAlways: () => asyncAlwaysRef.current
1831
2356
  });
1832
- const validateOnMount = options?.validateOnMount ?? form.validateOnMount;
2357
+ const validateOnMount = validateOnMountRef.current ?? form.validateOnMount;
1833
2358
  if (!validateOnMount || !validateRef.current && !syncRef.current) {
1834
2359
  return dispose;
1835
2360
  }
@@ -1850,41 +2375,40 @@
1850
2375
  disposed = true;
1851
2376
  dispose();
1852
2377
  };
1853
- }, [form, path.key]);
2378
+ }, [
2379
+ form,
2380
+ path.key,
2381
+ debounceRef,
2382
+ syncRef,
2383
+ asyncAlwaysRef,
2384
+ validateRef,
2385
+ validateOnMountRef
2386
+ ]);
1854
2387
  return useStageFn(() => form.validators.get(path.key)?.());
1855
2388
  }
1856
2389
 
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
2390
  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;
2391
+ function getUncontrolledSyncEntry(form) {
2392
+ const existing = uncontrolledSyncRegistry.get(form);
2393
+ if (existing) return existing;
2394
+ const cells = /* @__PURE__ */ new Map();
2395
+ const off = on(form.emitter, "change", (changed) => {
2396
+ if (changed) return;
2397
+ for (const read of cells.values()) {
2398
+ const { el, path } = read();
2399
+ if (!el || el.type === "file") continue;
2400
+ const next = getValueByPath(form, path);
2401
+ const asString = next == null ? "" : String(next);
2402
+ if (el.value !== asString) el.value = asString;
2403
+ }
2404
+ });
2405
+ const entry = { cells, off };
2406
+ uncontrolledSyncRegistry.set(form, entry);
2407
+ return entry;
1884
2408
  }
1885
- function combineRulesAndValidate(rules, validate) {
2409
+ function combineRulesAndValidate(rules, validate, formMessages) {
1886
2410
  if (!rules || !hasRuleConstraints(rules)) return validate;
1887
- const ruleValidator = rulesToValidator(rules);
2411
+ const ruleValidator = rulesToValidator(rules, formMessages);
1888
2412
  if (!validate) return ruleValidator;
1889
2413
  return (value, meta) => {
1890
2414
  const ruleErrors = ruleValidator(value, meta);
@@ -1898,22 +2422,59 @@
1898
2422
  return isPromise(result) ? result.then(merge) : merge(result);
1899
2423
  };
1900
2424
  }
1901
- function useDelayedErrors(errors, delay) {
1902
- const [shown, setShown] = React.useState(errors);
1903
- React.useEffect(() => {
1904
- if (delay === void 0) return;
1905
- if (errors.length === 0) {
1906
- setShown(errors);
1907
- return;
1908
- }
1909
- if (shown.length > 0) {
1910
- setShown(errors);
1911
- return;
1912
- }
1913
- const timer = setTimeout(() => setShown(errors), delay);
1914
- return () => clearTimeout(timer);
1915
- }, [errors, delay, shown]);
1916
- return delay === void 0 ? errors : shown;
2425
+ const NO_DELAYED_ERRORS = [];
2426
+ function useDelayedErrors(form, path, delay) {
2427
+ const pendingRef = React.useRef(false);
2428
+ const prevRef = React.useRef(false);
2429
+ const timerRef = React.useRef(null);
2430
+ const subscribeFactory = React.useCallback(
2431
+ (invalidate) => {
2432
+ const spath = pathFromKey(path.key);
2433
+ const clearTimer = () => {
2434
+ if (timerRef.current !== null) {
2435
+ clearTimeout(timerRef.current);
2436
+ timerRef.current = null;
2437
+ }
2438
+ };
2439
+ pendingRef.current = false;
2440
+ prevRef.current = false;
2441
+ clearTimer();
2442
+ const startWindow = () => {
2443
+ clearTimer();
2444
+ pendingRef.current = true;
2445
+ timerRef.current = setTimeout(() => {
2446
+ timerRef.current = null;
2447
+ pendingRef.current = false;
2448
+ invalidate();
2449
+ }, delay);
2450
+ };
2451
+ const off = onKeyEvent(form.emitter, "errors", spath.key, () => {
2452
+ const has = getFieldErrorsByPath(form, spath).length > 0;
2453
+ const was = prevRef.current;
2454
+ prevRef.current = has;
2455
+ if (delay !== void 0) {
2456
+ if (!has) {
2457
+ if (pendingRef.current) {
2458
+ clearTimer();
2459
+ pendingRef.current = false;
2460
+ }
2461
+ } else if (!was || pendingRef.current) {
2462
+ startWindow();
2463
+ }
2464
+ }
2465
+ invalidate();
2466
+ });
2467
+ return () => {
2468
+ off();
2469
+ clearTimer();
2470
+ };
2471
+ },
2472
+ [form, path.key, delay]
2473
+ );
2474
+ return useWatchCore(
2475
+ subscribeFactory,
2476
+ () => delay === void 0 || !pendingRef.current ? getFieldErrorsByPath(form, path) : NO_DELAYED_ERRORS
2477
+ );
1917
2478
  }
1918
2479
  function useFieldValue(form, path, uncontrolled) {
1919
2480
  const snapshotRef = React.useRef({
@@ -1948,7 +2509,11 @@
1948
2509
  disabled,
1949
2510
  uncontrolled,
1950
2511
  asyncAlways,
1951
- mode: modeOption
2512
+ mode: modeOption,
2513
+ eventToValue,
2514
+ valueAsNumber,
2515
+ valueAsDate,
2516
+ type
1952
2517
  }, Context) {
1953
2518
  const contextForm = React.useContext(Context);
1954
2519
  const form = f1 || contextForm;
@@ -1966,22 +2531,32 @@
1966
2531
  emitChangeByPath(form, path);
1967
2532
  });
1968
2533
  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
- });
1975
- const liveErrors = useFieldErrorsByPath(form, path);
1976
- const errors = useDelayedErrors(liveErrors, delayError);
2534
+ const validateWrapped = schemaAsValidator(validate);
2535
+ useValidate(
2536
+ combineRulesAndValidate(restRules, validateWrapped, form.messages),
2537
+ path,
2538
+ form,
2539
+ {
2540
+ debounce: validateDebounce,
2541
+ validateOnMount,
2542
+ asyncAlways: asyncAlways ?? form.asyncAlways,
2543
+ sync: rules && rules.required !== void 0 ? rulesToValidator({ required: rules.required }, form.messages) : void 0
2544
+ }
2545
+ );
2546
+ const errors = useDelayedErrors(form, path, delayError);
1977
2547
  const errorObject = errors[0];
1978
2548
  const error = errorObject?.message;
1979
2549
  const value = useFieldValue(form, path, !!uncontrolled);
1980
2550
  const isDirty = useWatchCore(
1981
2551
  React.useCallback(
1982
2552
  (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
2553
+ } : onPathEvent(
2554
+ form.emitter,
2555
+ "change",
2556
+ pathFromKey(path.key),
2557
+ "leaf",
2558
+ invalidate
2559
+ ),
1985
2560
  [form.emitter, path.key, uncontrolled]
1986
2561
  ),
1987
2562
  () => isFieldDirtyByPath(form, path)
@@ -1993,20 +2568,46 @@
1993
2568
  ),
1994
2569
  () => form.validating.has(path.key)
1995
2570
  );
1996
- const formDisabled = useWatch(form, "disabled", () => form.disabled);
2571
+ const mergedDisabled = useWatchCore(
2572
+ React.useCallback(
2573
+ (invalidate) => onPathEvent(
2574
+ form.emitter,
2575
+ "disabled",
2576
+ pathFromKey(path.key),
2577
+ "branch",
2578
+ invalidate
2579
+ ),
2580
+ [form.emitter, path.key]
2581
+ ),
2582
+ () => form.disabled || disabled === true || disabled !== false && hasDisabledAncestor(form, path)
2583
+ );
2584
+ const disabledTokenRef = React.useRef(null);
2585
+ React.useEffect(() => {
2586
+ const spath = pathFromKey(path.key);
2587
+ const registration = registerFieldDisabled(form, spath, disabled);
2588
+ if (registration) disabledTokenRef.current = registration.token;
2589
+ return () => {
2590
+ if (disabledTokenRef.current !== null) {
2591
+ unregisterFieldDisabled(form, spath, disabledTokenRef.current);
2592
+ disabledTokenRef.current = null;
2593
+ }
2594
+ };
2595
+ }, [form, path.key, disabled]);
1997
2596
  const onChange = useStageFn((v) => userChangeByPath(form, path, v));
1998
2597
  const onBlur = useStageFn(() => userBlur(form, path));
1999
2598
  React.useEffect(() => {
2000
- const { token, displaced } = registerFieldMode(form, path, modeOption);
2001
- return () => unregisterFieldMode(form, path, token);
2599
+ const spath = pathFromKey(path.key);
2600
+ const { token, displaced } = registerFieldMode(form, spath, modeOption);
2601
+ return () => unregisterFieldMode(form, spath, token);
2002
2602
  }, [form, path.key, modeOption]);
2003
2603
  const depsKey = validateDeps?.length ? validateDeps.join("\n") : void 0;
2604
+ const validateDepsRef = useStage(validateDeps);
2004
2605
  React.useEffect(() => {
2005
2606
  if (!depsKey) return;
2006
- const depKeys = validateDeps.map((dep) => create$1(dep).key);
2607
+ const depKeys = validateDepsRef.current.map((dep) => create$1(dep).key);
2007
2608
  registerFieldValidateDeps(form, path.key, depKeys);
2008
2609
  return () => unregisterFieldValidateDeps(form, path.key, depKeys);
2009
- }, [form, path.key, depsKey]);
2610
+ }, [form, path.key, depsKey, validateDepsRef]);
2010
2611
  const elementRef = React.useRef(null);
2011
2612
  const focusRef = React.useCallback((el) => {
2012
2613
  elementRef.current = el;
@@ -2028,24 +2629,9 @@
2028
2629
  [form, path.key]
2029
2630
  );
2030
2631
  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 }));
2632
+ const spath = pathFromKey(path.key);
2633
+ const entry = getUncontrolledSyncEntry(form);
2634
+ entry.cells.set(path.key, () => ({ el: elementRef.current, path: spath }));
2049
2635
  return () => {
2050
2636
  entry.cells.delete(path.key);
2051
2637
  if (entry.cells.size === 0) {
@@ -2054,17 +2640,28 @@
2054
2640
  }
2055
2641
  };
2056
2642
  }, [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);
2643
+ useUnmountFieldRemoval(form, path, shouldUnregister);
2644
+ const extract = eventToValueOrDefault(eventToValue, {
2645
+ valueAsNumber,
2646
+ valueAsDate
2066
2647
  });
2067
- useUnmountRestore(teardownOnUnmount, restoreAfterStrictMode);
2648
+ const inputProps = {
2649
+ name: path.key,
2650
+ ref: focusRef,
2651
+ onChange: (e) => onChange(extract(e)),
2652
+ onBlur,
2653
+ disabled: mergedDisabled
2654
+ };
2655
+ if (type === "checkbox") {
2656
+ inputProps.checked = !!value;
2657
+ } else if (type !== "file") {
2658
+ if (uncontrolled) inputProps.defaultValue = value;
2659
+ else inputProps.value = value ?? "";
2660
+ }
2661
+ if (error) {
2662
+ inputProps["aria-invalid"] = true;
2663
+ inputProps["aria-describedby"] = errorIdFromKey(path.key);
2664
+ }
2068
2665
  return {
2069
2666
  form,
2070
2667
  value,
@@ -2076,8 +2673,9 @@
2076
2673
  onChange,
2077
2674
  onBlur,
2078
2675
  name: path.key,
2079
- disabled: formDisabled || !!disabled,
2080
- focusRef
2676
+ disabled: mergedDisabled,
2677
+ focusRef,
2678
+ inputProps
2081
2679
  };
2082
2680
  }
2083
2681
  function useField(options) {
@@ -2095,12 +2693,18 @@
2095
2693
  return arrayIdsRegistry.get(form)?.get(key);
2096
2694
  }
2097
2695
  function registerArrayIds(form, key, ids) {
2098
- let registry = arrayIdsRegistry.get(form);
2099
- if (!registry) {
2100
- registry = /* @__PURE__ */ new Map();
2101
- arrayIdsRegistry.set(form, registry);
2102
- }
2696
+ const registry = arrayIdsRegistry.get(form) ?? /* @__PURE__ */ new Map();
2103
2697
  registry.set(key, ids);
2698
+ arrayIdsRegistry.set(form, registry);
2699
+ }
2700
+ function scheduleArrayRowFocus(form, path, index, options) {
2701
+ const { focus } = options ?? {};
2702
+ if (focus === void 0) return;
2703
+ setTimeout(() => {
2704
+ const segments = [...path.value, index];
2705
+ const key = typeof focus === "string" ? create$1([...segments, focus]).key : firstMountedDescendantKey(form, create$1(segments));
2706
+ if (key !== void 0) emit(form.emitter, "focusError", key);
2707
+ }, 0);
2104
2708
  }
2105
2709
  function bumpReducer(count) {
2106
2710
  return count + 1;
@@ -2113,18 +2717,8 @@
2113
2717
  const { rules, shouldUnregister } = options;
2114
2718
  const path = usePath(options.name);
2115
2719
  const idsRef = React.useRef([]);
2116
- const getArray = React.useCallback(
2117
- () => getValueByPath(form, path) || [],
2118
- [form, path]
2119
- );
2120
- const setArray = React.useCallback(
2121
- (arr) => {
2122
- setValueByPath(form, path, arr);
2123
- },
2124
- [form, path]
2125
- );
2126
2720
  const computeFields = React.useCallback(() => {
2127
- const arr = getArray();
2721
+ const arr = getValueByPath(form, path) || [];
2128
2722
  while (idsRef.current.length < arr.length) {
2129
2723
  idsRef.current.push(generateId(form));
2130
2724
  }
@@ -2136,7 +2730,7 @@
2136
2730
  index,
2137
2731
  [keyName]: id
2138
2732
  }));
2139
- }, [getArray, form, keyName]);
2733
+ }, [form, path, keyName]);
2140
2734
  const [fields, syncFields] = React.useReducer(
2141
2735
  computeFields,
2142
2736
  void 0,
@@ -2148,82 +2742,65 @@
2148
2742
  );
2149
2743
  registerArrayIds(form, path.key, idsRef.current);
2150
2744
  React.useEffect(() => {
2151
- registerArrayIds(form, path.key, idsRef.current);
2745
+ const ids = idsRef.current;
2746
+ registerArrayIds(form, path.key, ids);
2152
2747
  return () => {
2153
2748
  const registry = arrayIdsRegistry.get(form);
2154
- if (registry?.get(path.key) === idsRef.current) registry.delete(path.key);
2749
+ if (registry?.get(path.key) === ids) registry.delete(path.key);
2155
2750
  };
2156
2751
  }, [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);
2752
+ useUnmountFieldRemoval(form, path, shouldUnregister);
2168
2753
  useValidate(
2169
- rules ? rulesToValidator({ ...rules, required: void 0 }) : void 0,
2754
+ rules ? rulesToValidator({ ...rules, required: void 0 }, form.messages) : void 0,
2170
2755
  path,
2171
2756
  form,
2172
2757
  {
2173
- sync: rules && rules.required !== void 0 ? rulesToValidator({ required: rules.required }) : void 0
2758
+ sync: rules?.required !== void 0 ? rulesToValidator({ required: rules.required }, form.messages) : void 0
2174
2759
  }
2175
2760
  );
2176
- const append = useStageFn((value) => {
2177
- const arr = getArray();
2178
- idsRef.current.push(generateId(form));
2179
- setArray([...arr, value]);
2180
- });
2181
- const prepend = useStageFn((value) => {
2182
- const arr = getArray();
2183
- idsRef.current.unshift(generateId(form));
2184
- setArray([value, ...arr]);
2185
- });
2186
- const insert = useStageFn((index, value) => {
2187
- const arr = getArray();
2188
- idsRef.current.splice(index, 0, generateId(form));
2189
- const newArr = [...arr.slice(0, index), value, ...arr.slice(index)];
2190
- setArray(newArr);
2191
- });
2192
- const remove = useStageFn((index) => {
2193
- const arr = getArray();
2194
- idsRef.current.splice(index, 1);
2195
- const newArr = arr.filter((_, i) => i !== index);
2196
- setArray(newArr);
2761
+ const append = useStageFn(
2762
+ (value, options2) => {
2763
+ idsRef.current.push(generateId(form));
2764
+ appendValueByPath(form, path, value);
2765
+ scheduleArrayRowFocus(form, path, idsRef.current.length - 1, options2);
2766
+ }
2767
+ );
2768
+ const prepend = useStageFn(
2769
+ (value, options2) => {
2770
+ idsRef.current.unshift(generateId(form));
2771
+ prependValueByPath(form, path, value);
2772
+ scheduleArrayRowFocus(form, path, 0, options2);
2773
+ }
2774
+ );
2775
+ const insert = useStageFn(
2776
+ (index, value, options2) => {
2777
+ if (!insertValueByPath(form, path, index, value)) return;
2778
+ idsRef.current.splice(index, 0, generateId(form));
2779
+ scheduleArrayRowFocus(form, path, index, options2);
2780
+ }
2781
+ );
2782
+ const remove = useStageFn((indices) => {
2783
+ const dropped = removeValueByPath(form, path, indices);
2784
+ for (const index of dropped) idsRef.current.splice(index, 1);
2197
2785
  });
2198
2786
  const swap = useStageFn((from, to) => {
2199
- const arr = getArray();
2787
+ if (!swapValuesByPath(form, path, from, to)) return;
2200
2788
  [idsRef.current[from], idsRef.current[to]] = [
2201
2789
  idsRef.current[to],
2202
2790
  idsRef.current[from]
2203
2791
  ];
2204
- const newArr = [...arr];
2205
- [newArr[from], newArr[to]] = [newArr[to], newArr[from]];
2206
- setArray(newArr);
2207
2792
  });
2208
2793
  const move = useStageFn((from, to) => {
2209
- const arr = getArray();
2794
+ if (!moveValueByPath(form, path, from, to)) return;
2210
2795
  const [id] = idsRef.current.splice(from, 1);
2211
2796
  idsRef.current.splice(to, 0, id);
2212
- const newArr = [...arr];
2213
- const [item] = newArr.splice(from, 1);
2214
- newArr.splice(to, 0, item);
2215
- setArray(newArr);
2216
2797
  });
2217
2798
  const replace = useStageFn((values) => {
2218
2799
  idsRef.current = values.map(() => generateId(form));
2219
- setArray([...values]);
2800
+ replaceValuesByPath(form, path, values);
2220
2801
  });
2221
2802
  const update = useStageFn((index, value) => {
2222
- const arr = getArray();
2223
- if (index < 0 || index >= arr.length) return;
2224
- const newArr = [...arr];
2225
- newArr[index] = value;
2226
- setArray(newArr);
2803
+ updateValueByPath(form, path, index, value);
2227
2804
  });
2228
2805
  return { fields, append, prepend, insert, remove, swap, move, replace, update };
2229
2806
  }
@@ -2309,7 +2886,10 @@
2309
2886
  return useFieldCore(options, Context);
2310
2887
  }
2311
2888
  function useFieldArray(options) {
2312
- return useFieldArrayCore(options, Context);
2889
+ return useFieldArrayCore(
2890
+ options,
2891
+ Context
2892
+ );
2313
2893
  }
2314
2894
  function useFieldArrayItem(options) {
2315
2895
  return useFieldArrayItemCore(options, Context);
@@ -2333,23 +2913,57 @@
2333
2913
 
2334
2914
  function useTransform(form, name, options = {}) {
2335
2915
  const path = usePath(name);
2336
- const { toDisplay, fromDisplay } = options;
2916
+ const { toDisplay, fromDisplay, asyncDebounceMs } = options;
2337
2917
  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
2918
+ (invalidate) => onPathEvent(
2919
+ form.emitter,
2920
+ "change",
2921
+ pathFromKey(path.key),
2922
+ "leaf",
2923
+ invalidate
2924
+ ),
2340
2925
  [form.emitter, path.key]
2341
2926
  );
2342
2927
  const raw = useWatchCore(subscribeFactory, () => getValueByPath(form, path));
2343
2928
  const value = toDisplay ? toDisplay(raw) : raw;
2929
+ const timerRef = React.useRef(null);
2930
+ const seqRef = React.useRef(0);
2931
+ const fromDisplayRef = useStage(fromDisplay);
2932
+ const debounceRef = useStage(asyncDebounceMs ?? 0);
2933
+ React.useEffect(
2934
+ () => () => {
2935
+ if (timerRef.current !== null) clearTimeout(timerRef.current);
2936
+ },
2937
+ []
2938
+ );
2344
2939
  const onChange = React.useCallback(
2345
2940
  (display) => {
2346
- userChangeByPath(
2347
- form,
2348
- path,
2349
- fromDisplay ? fromDisplay(display) : display
2350
- );
2941
+ const run = () => {
2942
+ const seq = ++seqRef.current;
2943
+ const transform = fromDisplayRef.current;
2944
+ const commit = (next) => userChangeByPath(form, path, next);
2945
+ if (!transform) {
2946
+ commit(display);
2947
+ return;
2948
+ }
2949
+ const result = transform(display);
2950
+ if (isPromise(result)) {
2951
+ result.then((next) => {
2952
+ if (seqRef.current === seq) commit(next);
2953
+ });
2954
+ } else if (seqRef.current === seq) {
2955
+ commit(result);
2956
+ }
2957
+ };
2958
+ if (timerRef.current !== null) clearTimeout(timerRef.current);
2959
+ timerRef.current = null;
2960
+ if (debounceRef.current > 0) {
2961
+ timerRef.current = setTimeout(run, debounceRef.current);
2962
+ } else {
2963
+ run();
2964
+ }
2351
2965
  },
2352
- [form, path, fromDisplay]
2966
+ [form, path, fromDisplayRef, debounceRef]
2353
2967
  );
2354
2968
  return { value, onChange };
2355
2969
  }
@@ -2403,6 +3017,7 @@
2403
3017
  onInvalidSubmit,
2404
3018
  action,
2405
3019
  shouldFocusError,
3020
+ shouldUseNativeValidation,
2406
3021
  ...props
2407
3022
  }) {
2408
3023
  const f2 = useForm({
@@ -2411,7 +3026,8 @@
2411
3026
  shouldUnregister,
2412
3027
  validateOnMount,
2413
3028
  disabled,
2414
- asyncAlways
3029
+ asyncAlways,
3030
+ shouldUseNativeValidation
2415
3031
  });
2416
3032
  const form = f1 || f2;
2417
3033
  React__namespace.useEffect(() => {
@@ -2422,10 +3038,12 @@
2422
3038
  onValidSubmit,
2423
3039
  onInvalidSubmit,
2424
3040
  shouldFocusError,
2425
- onAction: action ? (values2) => action(formDataFromValues(values2)) : void 0
3041
+ shouldUseNativeValidation,
3042
+ onAction: typeof action === "function" ? (values2) => action(formDataFromValues(values2)) : void 0
2426
3043
  });
2427
3044
  const { Provider } = context ?? FormContext;
2428
- return /* @__PURE__ */ React__namespace.createElement(Provider, { value: form }, /* @__PURE__ */ React__namespace.createElement("form", { ...props, noValidate: true, onSubmit: submit }));
3045
+ const nativeAction = typeof action === "string" ? action : void 0;
3046
+ return /* @__PURE__ */ React__namespace.createElement(Provider, { value: form }, /* @__PURE__ */ React__namespace.createElement("form", { ...props, action: nativeAction, noValidate: true, onSubmit: submit }));
2429
3047
  }
2430
3048
 
2431
3049
  function FormField({ children, ...options }) {
@@ -2440,18 +3058,14 @@
2440
3058
  ref.current = value;
2441
3059
  }
2442
3060
  }
2443
- function errorIdFromKey(key) {
2444
- const id = key.replace(/["'[\],\s]+/g, "-").replace(/^-+|-+$/g, "");
2445
- return id || "field";
2446
- }
2447
3061
  function ariaProps(error, fieldKey, props) {
2448
3062
  return {
2449
3063
  "aria-invalid": error ? true : props["aria-invalid"],
2450
3064
  "aria-describedby": error ? [props["aria-describedby"], errorIdFromKey(fieldKey)].filter(Boolean).join(" ") : props["aria-describedby"]
2451
3065
  };
2452
3066
  }
2453
- function fieldErrorId(name) {
2454
- return errorIdFromKey(create$1(name).key);
3067
+ function toConstraintAttrs(rules) {
3068
+ return rules ? rulesToConstraintAttrs(rules) : void 0;
2455
3069
  }
2456
3070
  const Field = React__namespace.forwardRef(
2457
3071
  ({
@@ -2479,6 +3093,10 @@
2479
3093
  }, ref) => {
2480
3094
  const innerRef = React__namespace.useRef(null);
2481
3095
  const [nativeInvalidCount, setNativeInvalidCount] = React__namespace.useState(0);
3096
+ const contextForm = React__namespace.useContext(FormContext);
3097
+ const resolvedForm = formProp ?? contextForm;
3098
+ const isFile = props.type === "file";
3099
+ const validateWrapped = validate && hasStandardProps(validate) ? schemaToFieldValidator(validate) : validate;
2482
3100
  const {
2483
3101
  value,
2484
3102
  onChange,
@@ -2486,7 +3104,8 @@
2486
3104
  error,
2487
3105
  name: fieldKey,
2488
3106
  disabled: isDisabled,
2489
- focusRef
3107
+ focusRef,
3108
+ validating
2490
3109
  } = useField({
2491
3110
  name,
2492
3111
  form: formProp,
@@ -2499,19 +3118,20 @@
2499
3118
  disabled,
2500
3119
  asyncAlways,
2501
3120
  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",
3121
+ // File inputs can't be value-controlled — force the uncontrolled path.
3122
+ uncontrolled: uncontrolled || isFile,
2505
3123
  validate: (...params) => {
2506
- const el = innerRef.current;
2507
- if (el && typeof el.checkValidity === "function") {
2508
- el.setCustomValidity("");
2509
- if (el.checkValidity() === false) {
2510
- setNativeInvalidCount((count) => count + 1);
2511
- return void 0;
3124
+ if (resolvedForm?.shouldUseNativeValidation !== false) {
3125
+ const el = innerRef.current;
3126
+ if (el && typeof el.checkValidity === "function") {
3127
+ el.setCustomValidity("");
3128
+ if (el.checkValidity() === false) {
3129
+ setNativeInvalidCount((count) => count + 1);
3130
+ return void 0;
3131
+ }
2512
3132
  }
2513
3133
  }
2514
- if (validate) return validate(...params);
3134
+ if (validateWrapped) return validateWrapped(...params);
2515
3135
  }
2516
3136
  });
2517
3137
  const mergedRef = React__namespace.useCallback(
@@ -2522,7 +3142,6 @@
2522
3142
  },
2523
3143
  [ref, focusRef]
2524
3144
  );
2525
- const Component = as || "input";
2526
3145
  React__namespace.useEffect(() => {
2527
3146
  const el = innerRef.current;
2528
3147
  if (!el || typeof el.setCustomValidity !== "function") return;
@@ -2536,11 +3155,14 @@
2536
3155
  React__namespace.useEffect(() => {
2537
3156
  if (nativeInvalidCount > 0) innerRef.current?.reportValidity();
2538
3157
  }, [nativeInvalidCount]);
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);
3158
+ const Component = as || "input";
3159
+ const toValue = eventToValueOrDefault(eventToValue, {
3160
+ valueAsNumber,
3161
+ valueAsDate
3162
+ });
2541
3163
  const valueProps = valueToProps ? valueToProps(value) : isFile ? {} : uncontrolled ? { defaultValue: value } : { value };
2542
3164
  const errorId = errorIdFromKey(fieldKey);
2543
- const constraintAttrs = rules ? rulesToConstraintAttrs(rules) : void 0;
3165
+ const constraintAttrs = toConstraintAttrs(rules);
2544
3166
  return /* @__PURE__ */ React__namespace.createElement(React__namespace.Fragment, null, /* @__PURE__ */ React__namespace.createElement(
2545
3167
  Component,
2546
3168
  {
@@ -2552,6 +3174,7 @@
2552
3174
  ...valueProps,
2553
3175
  ...ariaProps(error, fieldKey, props),
2554
3176
  disabled: isDisabled,
3177
+ "aria-busy": validating || void 0,
2555
3178
  onChange: (e) => onChange(toValue(e)),
2556
3179
  ref: mergedRef
2557
3180
  }
@@ -2580,7 +3203,8 @@
2580
3203
  onBlur,
2581
3204
  error,
2582
3205
  name: fieldKey,
2583
- disabled: isDisabled
3206
+ disabled: isDisabled,
3207
+ validating
2584
3208
  } = useField({
2585
3209
  name,
2586
3210
  form,
@@ -2595,7 +3219,7 @@
2595
3219
  disabled,
2596
3220
  mode
2597
3221
  });
2598
- const constraintAttrs = rules ? rulesToConstraintAttrs(rules) : void 0;
3222
+ const constraintAttrs = toConstraintAttrs(rules);
2599
3223
  return /* @__PURE__ */ React__namespace.createElement(
2600
3224
  "input",
2601
3225
  {
@@ -2607,6 +3231,7 @@
2607
3231
  checked: !!value,
2608
3232
  ...ariaProps(error, fieldKey, props),
2609
3233
  disabled: isDisabled,
3234
+ "aria-busy": validating || void 0,
2610
3235
  onChange: (e) => onChange(e.target.checked),
2611
3236
  ref
2612
3237
  }
@@ -2641,7 +3266,8 @@
2641
3266
  onBlur,
2642
3267
  error,
2643
3268
  name: fieldKey,
2644
- disabled: isDisabled
3269
+ disabled: isDisabled,
3270
+ validating
2645
3271
  } = useField({
2646
3272
  name,
2647
3273
  form,
@@ -2656,7 +3282,7 @@
2656
3282
  disabled,
2657
3283
  mode
2658
3284
  });
2659
- const constraintAttrs = rules ? rulesToConstraintAttrs(rules) : void 0;
3285
+ const constraintAttrs = toConstraintAttrs(rules);
2660
3286
  return /* @__PURE__ */ React__namespace.createElement(
2661
3287
  "select",
2662
3288
  {
@@ -2668,6 +3294,7 @@
2668
3294
  value: toSelectValue(multiple, value),
2669
3295
  ...ariaProps(error, fieldKey, props),
2670
3296
  disabled: isDisabled,
3297
+ "aria-busy": validating || void 0,
2671
3298
  onChange: (e) => onChange(
2672
3299
  multiple ? Array.from(e.target.selectedOptions, (option) => option.value) : e.target.value
2673
3300
  ),
@@ -2678,9 +3305,74 @@
2678
3305
  }
2679
3306
  );
2680
3307
 
3308
+ function ErrorSummary({
3309
+ form: formProp,
3310
+ context,
3311
+ heading
3312
+ }) {
3313
+ const contextForm = React__namespace.useContext(context ?? FormContext);
3314
+ const form = formProp ?? contextForm;
3315
+ if (!form) throw new Error("no form provided");
3316
+ const containerRef = React__namespace.useRef(null);
3317
+ const wasSubmittingRef = React__namespace.useRef(false);
3318
+ const headingId = React__namespace.useId();
3319
+ const errors = useErrors(form);
3320
+ const subscribeFactory = React__namespace.useCallback(
3321
+ (invalidate) => {
3322
+ const check = () => {
3323
+ const wasSubmitting = wasSubmittingRef.current;
3324
+ wasSubmittingRef.current = form.isSubmitting;
3325
+ if (wasSubmitting && !form.isSubmitting && hasErrors(form)) {
3326
+ containerRef.current?.focus();
3327
+ }
3328
+ invalidate();
3329
+ };
3330
+ const offErrors = on(form.emitter, "errors", check);
3331
+ const offSubmitting = on(form.emitter, "submitting", check);
3332
+ return () => {
3333
+ offErrors();
3334
+ offSubmitting();
3335
+ };
3336
+ },
3337
+ [form]
3338
+ );
3339
+ useWatchCore(subscribeFactory, () => null);
3340
+ const entries = Object.entries(errors);
3341
+ if (entries.length === 0) return null;
3342
+ return /* @__PURE__ */ React__namespace.createElement(
3343
+ "div",
3344
+ {
3345
+ role: "alert",
3346
+ tabIndex: -1,
3347
+ ref: containerRef,
3348
+ "aria-labelledby": headingId
3349
+ },
3350
+ /* @__PURE__ */ React__namespace.createElement("h2", { id: headingId }, heading ?? "There is a problem"),
3351
+ /* @__PURE__ */ React__namespace.createElement("ul", null, entries.map(([dottedKey, list]) => {
3352
+ const message = list[0]?.message;
3353
+ if (dottedKey === FORM_ERROR) {
3354
+ return /* @__PURE__ */ React__namespace.createElement("li", { key: dottedKey }, /* @__PURE__ */ React__namespace.createElement("p", null, message));
3355
+ }
3356
+ const path = dottedKeyToFieldPath(dottedKey);
3357
+ return /* @__PURE__ */ React__namespace.createElement("li", { key: dottedKey }, /* @__PURE__ */ React__namespace.createElement(
3358
+ "a",
3359
+ {
3360
+ href: `#${fieldErrorId(path)}`,
3361
+ onClick: (e) => {
3362
+ e.preventDefault();
3363
+ setFocus(form, path);
3364
+ }
3365
+ },
3366
+ message
3367
+ ));
3368
+ }))
3369
+ );
3370
+ }
3371
+
2681
3372
  exports.Checkbox = Checkbox;
2682
3373
  exports.CheckboxGroupContext = CheckboxGroupContext;
2683
3374
  exports.CheckboxGroupProvider = CheckboxGroupProvider;
3375
+ exports.ErrorSummary = ErrorSummary;
2684
3376
  exports.FORM_ERROR = FORM_ERROR;
2685
3377
  exports.Field = Field;
2686
3378
  exports.Form = Form;
@@ -2689,18 +3381,26 @@
2689
3381
  exports.FormProvider = FormProvider;
2690
3382
  exports.Select = Select;
2691
3383
  exports.VALIDATION_OUTCOME = VALIDATION_OUTCOME;
3384
+ exports.appendValue = appendValue;
3385
+ exports.appendValueByPath = appendValueByPath;
2692
3386
  exports.changeValue = changeValue;
2693
3387
  exports.changeValueByPath = changeValueByPath;
2694
3388
  exports.clearErrors = clearErrors;
3389
+ exports.clearServerErrors = clearServerErrors;
2695
3390
  exports.createForm = create;
2696
3391
  exports.createFormContext = createFormContext;
3392
+ exports.dottedKeyToFieldPath = dottedKeyToFieldPath;
2697
3393
  exports.emitChangeByPath = emitChangeByPath;
2698
3394
  exports.ensureValidate = ensureValidate;
2699
3395
  exports.fieldErrorId = fieldErrorId;
3396
+ exports.fieldPathToDottedKey = fieldPathToDottedKey;
3397
+ exports.firstMountedDescendantKey = firstMountedDescendantKey;
2700
3398
  exports.getDirtyFields = getDirtyFields;
2701
3399
  exports.getError = getError;
2702
3400
  exports.getErrorByPath = getErrorByPath;
2703
3401
  exports.getErrors = getErrors;
3402
+ exports.getErrorsRecord = getErrorsRecord;
3403
+ exports.getErrorsTree = getErrorsTree;
2704
3404
  exports.getFieldErrors = getFieldErrors;
2705
3405
  exports.getFieldErrorsByPath = getFieldErrorsByPath;
2706
3406
  exports.getFieldState = getFieldState;
@@ -2714,14 +3414,25 @@
2714
3414
  exports.hasTouched = hasTouched;
2715
3415
  exports.hasTouchedByPath = hasTouchedByPath;
2716
3416
  exports.incrementSubmitCount = incrementSubmitCount;
3417
+ exports.insertValue = insertValue;
3418
+ exports.insertValueByPath = insertValueByPath;
2717
3419
  exports.isDirty = isDirty;
2718
3420
  exports.isFieldDirtyByPath = isFieldDirtyByPath;
2719
3421
  exports.isTouched = isTouched;
3422
+ exports.moveValue = moveValue;
3423
+ exports.moveValueByPath = moveValueByPath;
3424
+ exports.prependValue = prependValue;
3425
+ exports.prependValueByPath = prependValueByPath;
3426
+ exports.registerField = registerField;
2720
3427
  exports.registerFieldMode = registerFieldMode;
2721
3428
  exports.registerFieldValidateDeps = registerFieldValidateDeps;
2722
3429
  exports.registerValidatorByPath = registerValidatorByPath;
2723
3430
  exports.removeField = removeField;
2724
3431
  exports.removeFieldByPath = removeFieldByPath;
3432
+ exports.removeValue = removeValue;
3433
+ exports.removeValueByPath = removeValueByPath;
3434
+ exports.replaceValues = replaceValues;
3435
+ exports.replaceValuesByPath = replaceValuesByPath;
2725
3436
  exports.reset = reset;
2726
3437
  exports.resetField = resetField;
2727
3438
  exports.revalidateDependentsOnChange = revalidateDependentsOnChange;
@@ -2742,16 +3453,23 @@
2742
3453
  exports.setValidatingByPath = setValidatingByPath;
2743
3454
  exports.setValue = setValue;
2744
3455
  exports.setValueByPath = setValueByPath;
3456
+ exports.shouldKick = shouldKick;
2745
3457
  exports.subscribe = subscribe;
3458
+ exports.swapValues = swapValues;
3459
+ exports.swapValuesByPath = swapValuesByPath;
2746
3460
  exports.trigger = trigger;
2747
3461
  exports.unregisterFieldMode = unregisterFieldMode;
2748
3462
  exports.unregisterFieldValidateDeps = unregisterFieldValidateDeps;
2749
3463
  exports.unsetValidatingByPath = unsetValidatingByPath;
3464
+ exports.updateValue = updateValue;
3465
+ exports.updateValueByPath = updateValueByPath;
2750
3466
  exports.useCanSubmit = useCanSubmit;
2751
3467
  exports.useCheckboxGroupContext = useCheckboxGroupContext;
2752
3468
  exports.useDirtyFields = useDirtyFields;
2753
3469
  exports.useError = useError;
2754
3470
  exports.useErrorByPath = useErrorByPath;
3471
+ exports.useErrors = useErrors;
3472
+ exports.useErrorsTree = useErrorsTree;
2755
3473
  exports.useField = useField;
2756
3474
  exports.useFieldArray = useFieldArray;
2757
3475
  exports.useFieldArrayItem = useFieldArrayItem;
@@ -2772,6 +3490,7 @@
2772
3490
  exports.useIsValid = useIsValid;
2773
3491
  exports.useIsValidating = useIsValidating;
2774
3492
  exports.useStatus = useStatus;
3493
+ exports.useStore = useStore;
2775
3494
  exports.useSubmitCount = useSubmitCount;
2776
3495
  exports.useTouched = useTouched;
2777
3496
  exports.useTouchedByPath = useTouchedByPath;
@@ -2779,11 +3498,13 @@
2779
3498
  exports.useTransform = useTransform;
2780
3499
  exports.useValue = useValue;
2781
3500
  exports.useValueByPath = useValueByPath;
3501
+ exports.useValues = useValues;
2782
3502
  exports.useWatch = useWatch;
2783
3503
  exports.useWatchCore = useWatchCore;
2784
3504
  exports.userBlur = userBlur;
2785
3505
  exports.userChangeByPath = userChangeByPath;
2786
3506
  exports.validate = validate;
3507
+ exports.watch = watch;
2787
3508
 
2788
3509
  }));
2789
3510
  //# sourceMappingURL=index.umd.js.map