@depup/react-hook-form 7.72.0-depup.0 → 7.83.0-depup.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 (298) hide show
  1. package/README.md +2 -2
  2. package/changes.json +1 -1
  3. package/dist/constants.d.ts +1 -1
  4. package/dist/constants.d.ts.map +1 -1
  5. package/dist/fieldArray.d.ts +36 -0
  6. package/dist/fieldArray.d.ts.map +1 -0
  7. package/dist/form.d.ts.map +1 -1
  8. package/dist/index.cjs.js +1 -1
  9. package/dist/index.cjs.js.map +1 -1
  10. package/dist/index.d.ts +1 -0
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.esm.mjs +2455 -2019
  13. package/dist/index.esm.mjs.map +1 -1
  14. package/dist/index.umd.js +1 -1
  15. package/dist/index.umd.js.map +1 -1
  16. package/dist/logic/createFormControl.d.ts +13 -0
  17. package/dist/logic/createFormControl.d.ts.map +1 -1
  18. package/dist/logic/getDirtyFields.d.ts +3 -2
  19. package/dist/logic/getDirtyFields.d.ts.map +1 -1
  20. package/dist/logic/getEventValue.d.ts.map +1 -1
  21. package/dist/logic/getNodeParentName.d.ts.map +1 -1
  22. package/dist/logic/getProxyFormState.d.ts.map +1 -1
  23. package/dist/logic/getResolverOptions.d.ts +2 -2
  24. package/dist/logic/getValueAndMessage.d.ts +1 -4
  25. package/dist/logic/getValueAndMessage.d.ts.map +1 -1
  26. package/dist/logic/hasPromiseValidation.d.ts.map +1 -1
  27. package/dist/logic/hasValidation.d.ts +1 -1
  28. package/dist/logic/index.d.ts +2 -3
  29. package/dist/logic/index.d.ts.map +1 -1
  30. package/dist/logic/isNameInFieldArray.d.ts.map +1 -1
  31. package/dist/logic/isWatched.d.ts.map +1 -1
  32. package/dist/logic/shouldRenderFormState.d.ts.map +1 -1
  33. package/dist/logic/skipValidation.d.ts +1 -4
  34. package/dist/logic/skipValidation.d.ts.map +1 -1
  35. package/dist/logic/updateFieldArrayRootError.d.ts.map +1 -1
  36. package/dist/logic/validateField.d.ts.map +1 -1
  37. package/dist/react-server.esm.mjs +491 -179
  38. package/dist/react-server.esm.mjs.map +1 -1
  39. package/dist/types/errors.d.ts +2 -2
  40. package/dist/types/errors.d.ts.map +1 -1
  41. package/dist/types/fieldArray.d.ts +25 -1
  42. package/dist/types/fieldArray.d.ts.map +1 -1
  43. package/dist/types/form.d.ts +81 -56
  44. package/dist/types/form.d.ts.map +1 -1
  45. package/dist/types/path/common.d.ts +6 -0
  46. package/dist/types/path/common.d.ts.map +1 -1
  47. package/dist/types/path/eager.d.ts +15 -11
  48. package/dist/types/path/eager.d.ts.map +1 -1
  49. package/dist/types/utils.d.ts +4 -4
  50. package/dist/types/utils.d.ts.map +1 -1
  51. package/dist/types/validator.d.ts +1 -1
  52. package/dist/types/validator.d.ts.map +1 -1
  53. package/dist/types/watch.d.ts +1 -1
  54. package/dist/types/watch.d.ts.map +1 -1
  55. package/dist/useController.d.ts.map +1 -1
  56. package/dist/useFieldArray.d.ts.map +1 -1
  57. package/dist/useForm.d.ts.map +1 -1
  58. package/dist/useFormContext.d.ts +1 -1
  59. package/dist/useFormContext.d.ts.map +1 -1
  60. package/dist/useFormState.d.ts +2 -2
  61. package/dist/useFormState.d.ts.map +1 -1
  62. package/dist/useIsomorphicLayoutEffect.d.ts.map +1 -1
  63. package/dist/useWatch.d.ts +14 -14
  64. package/dist/utils/deepEqual.d.ts +1 -1
  65. package/dist/utils/deepEqual.d.ts.map +1 -1
  66. package/dist/utils/flatten.d.ts.map +1 -1
  67. package/dist/utils/get.d.ts.map +1 -1
  68. package/dist/utils/index.d.ts +2 -3
  69. package/dist/utils/index.d.ts.map +1 -1
  70. package/dist/utils/isKey.d.ts.map +1 -1
  71. package/dist/utils/set.d.ts.map +1 -1
  72. package/dist/utils/stringToPath.d.ts.map +1 -1
  73. package/dist/utils/unset.d.ts.map +1 -1
  74. package/dist/watch.d.ts +1 -1
  75. package/dist/watch.d.ts.map +1 -1
  76. package/package.json +34 -31
  77. package/dist/__tests__/controller.server.test.d.ts +0 -2
  78. package/dist/__tests__/controller.server.test.d.ts.map +0 -1
  79. package/dist/__tests__/controller.test.d.ts +0 -2
  80. package/dist/__tests__/controller.test.d.ts.map +0 -1
  81. package/dist/__tests__/form.test.d.ts +0 -2
  82. package/dist/__tests__/form.test.d.ts.map +0 -1
  83. package/dist/__tests__/formStateSubscribe.server.test.d.ts +0 -2
  84. package/dist/__tests__/formStateSubscribe.server.test.d.ts.map +0 -1
  85. package/dist/__tests__/formStateSubscribe.test.d.ts +0 -2
  86. package/dist/__tests__/formStateSubscribe.test.d.ts.map +0 -1
  87. package/dist/__tests__/isPlainObject.test.d.ts +0 -2
  88. package/dist/__tests__/isPlainObject.test.d.ts.map +0 -1
  89. package/dist/__tests__/logic/appendErrors.test.d.ts +0 -2
  90. package/dist/__tests__/logic/appendErrors.test.d.ts.map +0 -1
  91. package/dist/__tests__/logic/createFormControl.test.d.ts +0 -2
  92. package/dist/__tests__/logic/createFormControl.test.d.ts.map +0 -1
  93. package/dist/__tests__/logic/generateId.test.d.ts +0 -2
  94. package/dist/__tests__/logic/generateId.test.d.ts.map +0 -1
  95. package/dist/__tests__/logic/getCheckboxValue.test.d.ts +0 -2
  96. package/dist/__tests__/logic/getCheckboxValue.test.d.ts.map +0 -1
  97. package/dist/__tests__/logic/getDirtyFields.test.d.ts +0 -2
  98. package/dist/__tests__/logic/getDirtyFields.test.d.ts.map +0 -1
  99. package/dist/__tests__/logic/getEventValue.test.d.ts +0 -2
  100. package/dist/__tests__/logic/getEventValue.test.d.ts.map +0 -1
  101. package/dist/__tests__/logic/getFieldValue.test.d.ts +0 -2
  102. package/dist/__tests__/logic/getFieldValue.test.d.ts.map +0 -1
  103. package/dist/__tests__/logic/getFieldValueAs.test.d.ts +0 -2
  104. package/dist/__tests__/logic/getFieldValueAs.test.d.ts.map +0 -1
  105. package/dist/__tests__/logic/getFocusFieldName.test.d.ts +0 -2
  106. package/dist/__tests__/logic/getFocusFieldName.test.d.ts.map +0 -1
  107. package/dist/__tests__/logic/getNodeParentName.test.d.ts +0 -2
  108. package/dist/__tests__/logic/getNodeParentName.test.d.ts.map +0 -1
  109. package/dist/__tests__/logic/getRadioValue.test.d.ts +0 -2
  110. package/dist/__tests__/logic/getRadioValue.test.d.ts.map +0 -1
  111. package/dist/__tests__/logic/getResolverOptions.test.d.ts +0 -2
  112. package/dist/__tests__/logic/getResolverOptions.test.d.ts.map +0 -1
  113. package/dist/__tests__/logic/getRuleValue.test.d.ts +0 -2
  114. package/dist/__tests__/logic/getRuleValue.test.d.ts.map +0 -1
  115. package/dist/__tests__/logic/getValidateError.test.d.ts +0 -2
  116. package/dist/__tests__/logic/getValidateError.test.d.ts.map +0 -1
  117. package/dist/__tests__/logic/getValidationModes.test.d.ts +0 -2
  118. package/dist/__tests__/logic/getValidationModes.test.d.ts.map +0 -1
  119. package/dist/__tests__/logic/getValueAndMessage.test.d.ts +0 -2
  120. package/dist/__tests__/logic/getValueAndMessage.test.d.ts.map +0 -1
  121. package/dist/__tests__/logic/hasPromiseValidation.test.d.ts +0 -2
  122. package/dist/__tests__/logic/hasPromiseValidation.test.d.ts.map +0 -1
  123. package/dist/__tests__/logic/hasValidation.test.d.ts +0 -2
  124. package/dist/__tests__/logic/hasValidation.test.d.ts.map +0 -1
  125. package/dist/__tests__/logic/isNameInFieldArray.test.d.ts +0 -2
  126. package/dist/__tests__/logic/isNameInFieldArray.test.d.ts.map +0 -1
  127. package/dist/__tests__/logic/isWatched.test.d.ts +0 -2
  128. package/dist/__tests__/logic/isWatched.test.d.ts.map +0 -1
  129. package/dist/__tests__/logic/iterateFieldsByAction.test.d.ts +0 -2
  130. package/dist/__tests__/logic/iterateFieldsByAction.test.d.ts.map +0 -1
  131. package/dist/__tests__/logic/schemaErrorLookup.test.d.ts +0 -2
  132. package/dist/__tests__/logic/schemaErrorLookup.test.d.ts.map +0 -1
  133. package/dist/__tests__/logic/shouldRenderFormState.test.d.ts +0 -2
  134. package/dist/__tests__/logic/shouldRenderFormState.test.d.ts.map +0 -1
  135. package/dist/__tests__/logic/shouldSubscribeByName.test.d.ts +0 -2
  136. package/dist/__tests__/logic/shouldSubscribeByName.test.d.ts.map +0 -1
  137. package/dist/__tests__/logic/skipValidation.test.d.ts +0 -2
  138. package/dist/__tests__/logic/skipValidation.test.d.ts.map +0 -1
  139. package/dist/__tests__/logic/unsetEmptyArray.test.d.ts +0 -2
  140. package/dist/__tests__/logic/unsetEmptyArray.test.d.ts.map +0 -1
  141. package/dist/__tests__/logic/validateField.test.d.ts +0 -2
  142. package/dist/__tests__/logic/validateField.test.d.ts.map +0 -1
  143. package/dist/__tests__/type.test.d.ts +0 -2
  144. package/dist/__tests__/type.test.d.ts.map +0 -1
  145. package/dist/__tests__/useController.test.d.ts +0 -2
  146. package/dist/__tests__/useController.test.d.ts.map +0 -1
  147. package/dist/__tests__/useFieldArray/append.test.d.ts +0 -2
  148. package/dist/__tests__/useFieldArray/append.test.d.ts.map +0 -1
  149. package/dist/__tests__/useFieldArray/dirtyFields.test.d.ts +0 -2
  150. package/dist/__tests__/useFieldArray/dirtyFields.test.d.ts.map +0 -1
  151. package/dist/__tests__/useFieldArray/focus.test.d.ts +0 -2
  152. package/dist/__tests__/useFieldArray/focus.test.d.ts.map +0 -1
  153. package/dist/__tests__/useFieldArray/insert.test.d.ts +0 -2
  154. package/dist/__tests__/useFieldArray/insert.test.d.ts.map +0 -1
  155. package/dist/__tests__/useFieldArray/move.test.d.ts +0 -2
  156. package/dist/__tests__/useFieldArray/move.test.d.ts.map +0 -1
  157. package/dist/__tests__/useFieldArray/prepend.test.d.ts +0 -2
  158. package/dist/__tests__/useFieldArray/prepend.test.d.ts.map +0 -1
  159. package/dist/__tests__/useFieldArray/remove.test.d.ts +0 -2
  160. package/dist/__tests__/useFieldArray/remove.test.d.ts.map +0 -1
  161. package/dist/__tests__/useFieldArray/replace.test.d.ts +0 -2
  162. package/dist/__tests__/useFieldArray/replace.test.d.ts.map +0 -1
  163. package/dist/__tests__/useFieldArray/swap.test.d.ts +0 -2
  164. package/dist/__tests__/useFieldArray/swap.test.d.ts.map +0 -1
  165. package/dist/__tests__/useFieldArray/update.test.d.ts +0 -2
  166. package/dist/__tests__/useFieldArray/update.test.d.ts.map +0 -1
  167. package/dist/__tests__/useFieldArray.test.d.ts +0 -2
  168. package/dist/__tests__/useFieldArray.test.d.ts.map +0 -1
  169. package/dist/__tests__/useForm/clearErrors.test.d.ts +0 -2
  170. package/dist/__tests__/useForm/clearErrors.test.d.ts.map +0 -1
  171. package/dist/__tests__/useForm/formState.test.d.ts +0 -2
  172. package/dist/__tests__/useForm/formState.test.d.ts.map +0 -1
  173. package/dist/__tests__/useForm/getFieldState.test.d.ts +0 -2
  174. package/dist/__tests__/useForm/getFieldState.test.d.ts.map +0 -1
  175. package/dist/__tests__/useForm/getValues.test.d.ts +0 -2
  176. package/dist/__tests__/useForm/getValues.test.d.ts.map +0 -1
  177. package/dist/__tests__/useForm/handleSubmit.test.d.ts +0 -2
  178. package/dist/__tests__/useForm/handleSubmit.test.d.ts.map +0 -1
  179. package/dist/__tests__/useForm/register.test.d.ts +0 -2
  180. package/dist/__tests__/useForm/register.test.d.ts.map +0 -1
  181. package/dist/__tests__/useForm/reset.test.d.ts +0 -2
  182. package/dist/__tests__/useForm/reset.test.d.ts.map +0 -1
  183. package/dist/__tests__/useForm/resetField.test.d.ts +0 -2
  184. package/dist/__tests__/useForm/resetField.test.d.ts.map +0 -1
  185. package/dist/__tests__/useForm/resolver.test.d.ts +0 -2
  186. package/dist/__tests__/useForm/resolver.test.d.ts.map +0 -1
  187. package/dist/__tests__/useForm/setError.test.d.ts +0 -2
  188. package/dist/__tests__/useForm/setError.test.d.ts.map +0 -1
  189. package/dist/__tests__/useForm/setFocus.test.d.ts +0 -2
  190. package/dist/__tests__/useForm/setFocus.test.d.ts.map +0 -1
  191. package/dist/__tests__/useForm/setValue.test.d.ts +0 -2
  192. package/dist/__tests__/useForm/setValue.test.d.ts.map +0 -1
  193. package/dist/__tests__/useForm/subscribe.test.d.ts +0 -2
  194. package/dist/__tests__/useForm/subscribe.test.d.ts.map +0 -1
  195. package/dist/__tests__/useForm/trigger.test.d.ts +0 -2
  196. package/dist/__tests__/useForm/trigger.test.d.ts.map +0 -1
  197. package/dist/__tests__/useForm/unregister.test.d.ts +0 -2
  198. package/dist/__tests__/useForm/unregister.test.d.ts.map +0 -1
  199. package/dist/__tests__/useForm/useFormWithNullValues.test.d.ts +0 -2
  200. package/dist/__tests__/useForm/useFormWithNullValues.test.d.ts.map +0 -1
  201. package/dist/__tests__/useForm/watch.test.d.ts +0 -2
  202. package/dist/__tests__/useForm/watch.test.d.ts.map +0 -1
  203. package/dist/__tests__/useForm.server.test.d.ts +0 -2
  204. package/dist/__tests__/useForm.server.test.d.ts.map +0 -1
  205. package/dist/__tests__/useForm.test.d.ts +0 -2
  206. package/dist/__tests__/useForm.test.d.ts.map +0 -1
  207. package/dist/__tests__/useFormContext.server.test.d.ts +0 -2
  208. package/dist/__tests__/useFormContext.server.test.d.ts.map +0 -1
  209. package/dist/__tests__/useFormContext.test.d.ts +0 -2
  210. package/dist/__tests__/useFormContext.test.d.ts.map +0 -1
  211. package/dist/__tests__/useFormState.test.d.ts +0 -2
  212. package/dist/__tests__/useFormState.test.d.ts.map +0 -1
  213. package/dist/__tests__/useWatch.test.d.ts +0 -2
  214. package/dist/__tests__/useWatch.test.d.ts.map +0 -1
  215. package/dist/__tests__/utils/append.test.d.ts +0 -2
  216. package/dist/__tests__/utils/append.test.d.ts.map +0 -1
  217. package/dist/__tests__/utils/cloneObject.test.d.ts +0 -2
  218. package/dist/__tests__/utils/cloneObject.test.d.ts.map +0 -1
  219. package/dist/__tests__/utils/compact.test.d.ts +0 -2
  220. package/dist/__tests__/utils/compact.test.d.ts.map +0 -1
  221. package/dist/__tests__/utils/convertToArrayPayload.test.d.ts +0 -2
  222. package/dist/__tests__/utils/convertToArrayPayload.test.d.ts.map +0 -1
  223. package/dist/__tests__/utils/createSubject.test.d.ts +0 -2
  224. package/dist/__tests__/utils/createSubject.test.d.ts.map +0 -1
  225. package/dist/__tests__/utils/deepEqual.test.d.ts +0 -2
  226. package/dist/__tests__/utils/deepEqual.test.d.ts.map +0 -1
  227. package/dist/__tests__/utils/deepMerge.test.d.ts +0 -2
  228. package/dist/__tests__/utils/deepMerge.test.d.ts.map +0 -1
  229. package/dist/__tests__/utils/extractFormValues.test.d.ts +0 -2
  230. package/dist/__tests__/utils/extractFormValues.test.d.ts.map +0 -1
  231. package/dist/__tests__/utils/fillEmptyArray.test.d.ts +0 -2
  232. package/dist/__tests__/utils/fillEmptyArray.test.d.ts.map +0 -1
  233. package/dist/__tests__/utils/flatten.test.d.ts +0 -2
  234. package/dist/__tests__/utils/flatten.test.d.ts.map +0 -1
  235. package/dist/__tests__/utils/get.test.d.ts +0 -2
  236. package/dist/__tests__/utils/get.test.d.ts.map +0 -1
  237. package/dist/__tests__/utils/insert.test.d.ts +0 -2
  238. package/dist/__tests__/utils/insert.test.d.ts.map +0 -1
  239. package/dist/__tests__/utils/isBoolean.test.d.ts +0 -2
  240. package/dist/__tests__/utils/isBoolean.test.d.ts.map +0 -1
  241. package/dist/__tests__/utils/isCheckBoxInput.test.d.ts +0 -2
  242. package/dist/__tests__/utils/isCheckBoxInput.test.d.ts.map +0 -1
  243. package/dist/__tests__/utils/isEmptyObject.test.d.ts +0 -2
  244. package/dist/__tests__/utils/isEmptyObject.test.d.ts.map +0 -1
  245. package/dist/__tests__/utils/isFileInput.test.d.ts +0 -2
  246. package/dist/__tests__/utils/isFileInput.test.d.ts.map +0 -1
  247. package/dist/__tests__/utils/isFunction.test.d.ts +0 -2
  248. package/dist/__tests__/utils/isFunction.test.d.ts.map +0 -1
  249. package/dist/__tests__/utils/isHTMLElement.test.d.ts +0 -2
  250. package/dist/__tests__/utils/isHTMLElement.test.d.ts.map +0 -1
  251. package/dist/__tests__/utils/isKey.test.d.ts +0 -2
  252. package/dist/__tests__/utils/isKey.test.d.ts.map +0 -1
  253. package/dist/__tests__/utils/isMultipleSelect.test.d.ts +0 -2
  254. package/dist/__tests__/utils/isMultipleSelect.test.d.ts.map +0 -1
  255. package/dist/__tests__/utils/isNullOrUndefined.test.d.ts +0 -2
  256. package/dist/__tests__/utils/isNullOrUndefined.test.d.ts.map +0 -1
  257. package/dist/__tests__/utils/isObject.test.d.ts +0 -2
  258. package/dist/__tests__/utils/isObject.test.d.ts.map +0 -1
  259. package/dist/__tests__/utils/isPrimitive.test.d.ts +0 -2
  260. package/dist/__tests__/utils/isPrimitive.test.d.ts.map +0 -1
  261. package/dist/__tests__/utils/isRadioInput.test.d.ts +0 -2
  262. package/dist/__tests__/utils/isRadioInput.test.d.ts.map +0 -1
  263. package/dist/__tests__/utils/isRadioOrCheckbox.test.d.ts +0 -2
  264. package/dist/__tests__/utils/isRadioOrCheckbox.test.d.ts.map +0 -1
  265. package/dist/__tests__/utils/isRegex.test.d.ts +0 -2
  266. package/dist/__tests__/utils/isRegex.test.d.ts.map +0 -1
  267. package/dist/__tests__/utils/isString.test.d.ts +0 -2
  268. package/dist/__tests__/utils/isString.test.d.ts.map +0 -1
  269. package/dist/__tests__/utils/isUndefined.test.d.ts +0 -2
  270. package/dist/__tests__/utils/isUndefined.test.d.ts.map +0 -1
  271. package/dist/__tests__/utils/live.test.d.ts +0 -2
  272. package/dist/__tests__/utils/live.test.d.ts.map +0 -1
  273. package/dist/__tests__/utils/move.test.d.ts +0 -2
  274. package/dist/__tests__/utils/move.test.d.ts.map +0 -1
  275. package/dist/__tests__/utils/noop.test.d.ts +0 -2
  276. package/dist/__tests__/utils/noop.test.d.ts.map +0 -1
  277. package/dist/__tests__/utils/objectHasFunction.test.d.ts +0 -2
  278. package/dist/__tests__/utils/objectHasFunction.test.d.ts.map +0 -1
  279. package/dist/__tests__/utils/prepend.test.d.ts +0 -2
  280. package/dist/__tests__/utils/prepend.test.d.ts.map +0 -1
  281. package/dist/__tests__/utils/remove.test.d.ts +0 -2
  282. package/dist/__tests__/utils/remove.test.d.ts.map +0 -1
  283. package/dist/__tests__/utils/set.test.d.ts +0 -2
  284. package/dist/__tests__/utils/set.test.d.ts.map +0 -1
  285. package/dist/__tests__/utils/stringToPath.test.d.ts +0 -2
  286. package/dist/__tests__/utils/stringToPath.test.d.ts.map +0 -1
  287. package/dist/__tests__/utils/swap.test.d.ts +0 -2
  288. package/dist/__tests__/utils/swap.test.d.ts.map +0 -1
  289. package/dist/__tests__/utils/unset.test.d.ts +0 -2
  290. package/dist/__tests__/utils/unset.test.d.ts.map +0 -1
  291. package/dist/__tests__/utils/update.test.d.ts +0 -2
  292. package/dist/__tests__/utils/update.test.d.ts.map +0 -1
  293. package/dist/__tests__/utils/validationModeChecker.test.d.ts +0 -2
  294. package/dist/__tests__/utils/validationModeChecker.test.d.ts.map +0 -1
  295. package/dist/__tests__/watch.server.test.d.ts +0 -2
  296. package/dist/__tests__/watch.server.test.d.ts.map +0 -1
  297. package/dist/__tests__/watch.test.d.ts +0 -2
  298. package/dist/__tests__/watch.test.d.ts.map +0 -1
@@ -2,6 +2,8 @@ import React from 'react';
2
2
 
3
3
  var isCheckBoxInput = (element) => element.type === 'checkbox';
4
4
 
5
+ var isFileInput = (element) => element.type === 'file';
6
+
5
7
  var isDateObject = (value) => value instanceof Date;
6
8
 
7
9
  var isNullOrUndefined = (value) => value == null;
@@ -15,12 +17,14 @@ var isObject = (value) => !isNullOrUndefined(value) &&
15
17
  var getEventValue = (event) => isObject(event) && event.target
16
18
  ? isCheckBoxInput(event.target)
17
19
  ? event.target.checked
18
- : event.target.value
20
+ : isFileInput(event.target)
21
+ ? event.target.files
22
+ : event.target.value
19
23
  : event;
20
24
 
21
- var getNodeParentName = (name) => name.substring(0, name.search(/\.\d+(\.|$)/)) || name;
22
-
23
- var isNameInFieldArray = (names, name) => names.has(getNodeParentName(name));
25
+ var isNameInFieldArray = (names, name) => name
26
+ .split('.')
27
+ .some((part, index, arr) => !isNaN(Number(part)) && names.has(arr.slice(0, index).join('.')));
24
28
 
25
29
  var isPlainObject = (tempObject) => {
26
30
  const prototypeCopy = tempObject.constructor && tempObject.constructor.prototype;
@@ -52,19 +56,52 @@ function cloneObject(data) {
52
56
  return copy;
53
57
  }
54
58
 
55
- var isKey = (value) => /^\w*$/.test(value);
59
+ const EVENTS = {
60
+ BLUR: 'blur',
61
+ FOCUS_OUT: 'focusout',
62
+ CHANGE: 'change',
63
+ SUBMIT: 'submit',
64
+ TRIGGER: 'trigger',
65
+ VALID: 'valid',
66
+ };
67
+ const VALIDATION_MODE = {
68
+ onBlur: 'onBlur',
69
+ onChange: 'onChange',
70
+ onSubmit: 'onSubmit',
71
+ onTouched: 'onTouched',
72
+ all: 'all',
73
+ };
74
+ const INPUT_VALIDATION_RULES = {
75
+ max: 'max',
76
+ min: 'min',
77
+ maxLength: 'maxLength',
78
+ minLength: 'minLength',
79
+ pattern: 'pattern',
80
+ required: 'required',
81
+ validate: 'validate',
82
+ };
83
+ const ROOT_ERROR_TYPE = 'root';
84
+ const PROTOTYPE_KEYWORDS = ['__proto__', 'constructor', 'prototype'];
85
+
86
+ const IS_KEY_RE = /^\w*$/;
87
+ var isKey = (value) => IS_KEY_RE.test(value);
56
88
 
57
89
  var isUndefined = (val) => val === undefined;
58
90
 
59
- var compact = (value) => Array.isArray(value) ? value.filter(Boolean) : [];
60
-
61
- var stringToPath = (input) => compact(input.replace(/["|']|\]/g, '').split(/\.|\[/));
91
+ const FIELD_PATH_RE = /[.[\]'"]/;
92
+ var stringToPath = (input) => input.split(FIELD_PATH_RE).filter(Boolean);
62
93
 
63
94
  var get = (object, path, defaultValue) => {
64
95
  if (!path || !isObject(object)) {
65
96
  return defaultValue;
66
97
  }
67
- const result = (isKey(path) ? [path] : stringToPath(path)).reduce((result, key) => isNullOrUndefined(result) ? result : result[key], object);
98
+ const paths = isKey(path) ? [path] : stringToPath(path);
99
+ if (paths.some((key) => PROTOTYPE_KEYWORDS.includes(key))) {
100
+ return defaultValue;
101
+ }
102
+ const result = paths.reduce((result, key) => {
103
+ return isNullOrUndefined(result) ? undefined : result[key];
104
+ }, object);
68
105
  return isUndefined(result) || result === object
69
106
  ? isUndefined(object[path])
70
107
  ? defaultValue
@@ -93,7 +130,7 @@ var set = (object, path, value) => {
93
130
  ? []
94
131
  : {};
95
132
  }
96
- if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
133
+ if (PROTOTYPE_KEYWORDS.includes(key)) {
97
134
  return;
98
135
  }
99
136
  object[key] = newValue;
@@ -101,33 +138,6 @@ var set = (object, path, value) => {
101
138
  }
102
139
  };
103
140
 
104
- const EVENTS = {
105
- BLUR: 'blur',
106
- FOCUS_OUT: 'focusout',
107
- CHANGE: 'change',
108
- SUBMIT: 'submit',
109
- TRIGGER: 'trigger',
110
- VALID: 'valid',
111
- };
112
- const VALIDATION_MODE = {
113
- onBlur: 'onBlur',
114
- onChange: 'onChange',
115
- onSubmit: 'onSubmit',
116
- onTouched: 'onTouched',
117
- all: 'all',
118
- };
119
- const INPUT_VALIDATION_RULES = {
120
- max: 'max',
121
- min: 'min',
122
- maxLength: 'maxLength',
123
- minLength: 'minLength',
124
- pattern: 'pattern',
125
- required: 'required',
126
- validate: 'validate',
127
- };
128
- const FORM_ERROR_TYPE = 'form';
129
- const ROOT_ERROR_TYPE = 'root';
130
-
131
141
  /**
132
142
  * Separate context for `control` to prevent unnecessary rerenders.
133
143
  * Internal hooks that only need control use this instead of full form context.
@@ -140,9 +150,7 @@ HookFormControlContext.displayName = 'HookFormControlContext';
140
150
  const useFormControlContext = () => React.useContext(HookFormControlContext);
141
151
 
142
152
  var getProxyFormState = (formState, control, localProxyFormState, isRoot = true) => {
143
- const result = {
144
- defaultValues: control._defaultValues,
145
- };
153
+ const result = {};
146
154
  for (const key in formState) {
147
155
  Object.defineProperty(result, key, {
148
156
  get: () => {
@@ -158,15 +166,17 @@ var getProxyFormState = (formState, control, localProxyFormState, isRoot = true)
158
166
  return result;
159
167
  };
160
168
 
161
- const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect;
169
+ const useIsomorphicLayoutEffect = isWeb
170
+ ? React.useLayoutEffect
171
+ : React.useEffect;
162
172
 
163
173
  /**
164
- * This custom hook allows you to subscribe to each form state, and isolate the re-render at the custom hook level. It has its scope in terms of form state subscription, so it would not affect other useFormState and useForm. Using this hook can reduce the re-render impact on large and complex form application.
174
+ * Subscribes to each form state and isolates re-renders at the custom hook level. It has its own scope for form state subscriptions, so it will not affect other useFormState or useForm instances. Using this hook can reduce the re-render impact on large and complex form applications.
165
175
  *
166
176
  * @remarks
167
177
  * [API](https://react-hook-form.com/docs/useformstate) • [Demo](https://codesandbox.io/s/useformstate-75xly)
168
178
  *
169
- * @param props - include options on specify fields to subscribe. {@link UseFormStateReturn}
179
+ * @param props - Include options to specify fields to subscribe to. {@link UseFormStateReturn}
170
180
  *
171
181
  * @example
172
182
  * ```tsx
@@ -193,7 +203,10 @@ const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? React.useLayou
193
203
  function useFormState(props) {
194
204
  const formControl = useFormControlContext();
195
205
  const { control = formControl, disabled, name, exact } = props || {};
196
- const [formState, updateFormState] = React.useState(control._formState);
206
+ const [formState, updateFormState] = React.useState(() => ({
207
+ ...control._formState,
208
+ defaultValues: control._defaultValues,
209
+ }));
197
210
  const _localProxyFormState = React.useRef({
198
211
  isDirty: false,
199
212
  isLoading: false,
@@ -213,6 +226,7 @@ function useFormState(props) {
213
226
  updateFormState({
214
227
  ...control._formState,
215
228
  ...formState,
229
+ defaultValues: control._defaultValues,
216
230
  });
217
231
  },
218
232
  }), [name, disabled, exact]);
@@ -239,7 +253,11 @@ var generateWatchOutput = (names, _names, formValues, isGlobal, defaultValue) =>
239
253
 
240
254
  var isPrimitive = (value) => isNullOrUndefined(value) || !isObjectType(value);
241
255
 
242
- function deepEqual(object1, object2, _internal_visited = new WeakSet()) {
256
+ const isEmptyObjectWithCustomPrototype = (object, keys) => keys.length === 0 && !Array.isArray(object) && !isPlainObject(object);
257
+ function deepEqual(object1, object2, visited = new WeakMap()) {
258
+ if (object1 === object2) {
259
+ return true;
260
+ }
243
261
  if (isPrimitive(object1) || isPrimitive(object2)) {
244
262
  return Object.is(object1, object2);
245
263
  }
@@ -251,22 +269,36 @@ function deepEqual(object1, object2, _internal_visited = new WeakSet()) {
251
269
  if (keys1.length !== keys2.length) {
252
270
  return false;
253
271
  }
254
- if (_internal_visited.has(object1) || _internal_visited.has(object2)) {
272
+ if (isEmptyObjectWithCustomPrototype(object1, keys1) ||
273
+ isEmptyObjectWithCustomPrototype(object2, keys2)) {
274
+ return Object.is(object1, object2);
275
+ }
276
+ if (!keys1.length && Array.isArray(object1) !== Array.isArray(object2)) {
277
+ return false;
278
+ }
279
+ const visitedPairs = visited.get(object1);
280
+ if (visitedPairs && visitedPairs.has(object2)) {
255
281
  return true;
256
282
  }
257
- _internal_visited.add(object1);
258
- _internal_visited.add(object2);
283
+ if (visitedPairs) {
284
+ visitedPairs.add(object2);
285
+ }
286
+ else {
287
+ const ws = new WeakSet();
288
+ ws.add(object2);
289
+ visited.set(object1, ws);
290
+ }
259
291
  for (const key of keys1) {
260
292
  const val1 = object1[key];
261
- if (!keys2.includes(key)) {
293
+ if (!(key in object2)) {
262
294
  return false;
263
295
  }
264
296
  if (key !== 'ref') {
265
297
  const val2 = object2[key];
266
298
  if ((isDateObject(val1) && isDateObject(val2)) ||
267
- (isObject(val1) && isObject(val2)) ||
268
- (Array.isArray(val1) && Array.isArray(val2))
269
- ? !deepEqual(val1, val2, _internal_visited)
299
+ ((isObject(val1) || Array.isArray(val1)) &&
300
+ (isObject(val2) || Array.isArray(val2)))
301
+ ? !deepEqual(val1, val2, visited)
270
302
  : !Object.is(val1, val2)) {
271
303
  return false;
272
304
  }
@@ -276,7 +308,7 @@ function deepEqual(object1, object2, _internal_visited = new WeakSet()) {
276
308
  }
277
309
 
278
310
  /**
279
- * Custom hook to subscribe to field change and isolate re-rendering at the component level.
311
+ * Custom hook to subscribe to field changes and isolate re-rendering at the component level.
280
312
  *
281
313
  * @remarks
282
314
  *
@@ -286,7 +318,7 @@ function deepEqual(object1, object2, _internal_visited = new WeakSet()) {
286
318
  * ```tsx
287
319
  * const { control } = useForm();
288
320
  * const values = useWatch({
289
- * name: "fieldName"
321
+ * name: "fieldName",
290
322
  * control,
291
323
  * })
292
324
  * ```
@@ -402,7 +434,7 @@ function useController(props) {
402
434
  exact,
403
435
  });
404
436
  const _props = React.useRef(props);
405
- const _previousNameRef = React.useRef(undefined);
437
+ const _proxyRef = React.useRef(null);
406
438
  const _registerProps = React.useRef(control.register(name, {
407
439
  ...props.rules,
408
440
  value,
@@ -431,13 +463,22 @@ function useController(props) {
431
463
  get: () => get(formState.errors, name),
432
464
  },
433
465
  }), [formState, name]);
434
- const onChange = React.useCallback((event) => _registerProps.current.onChange({
435
- target: {
436
- value: getEventValue(event),
437
- name: name,
438
- },
439
- type: EVENTS.CHANGE,
440
- }), [name]);
466
+ const onChange = React.useCallback((event) => {
467
+ const value = getEventValue(event);
468
+ if (!get(control._fields, name)) {
469
+ _registerProps.current = control.register(name, {
470
+ ..._props.current.rules,
471
+ value,
472
+ });
473
+ }
474
+ return _registerProps.current.onChange({
475
+ target: {
476
+ value: getEventValue(event),
477
+ name: name,
478
+ },
479
+ type: EVENTS.CHANGE,
480
+ });
481
+ }, [name, control]);
441
482
  const onBlur = React.useCallback(() => _registerProps.current.onBlur({
442
483
  target: {
443
484
  value: get(control._formValues, name),
@@ -446,15 +487,18 @@ function useController(props) {
446
487
  type: EVENTS.BLUR,
447
488
  }), [name, control._formValues]);
448
489
  const ref = React.useCallback((elm) => {
449
- const field = get(control._fields, name);
450
- if (field && field._f && elm) {
451
- field._f.ref = {
490
+ if (elm) {
491
+ _proxyRef.current = {
452
492
  focus: () => isFunction(elm.focus) && elm.focus(),
453
493
  select: () => isFunction(elm.select) && elm.select(),
454
494
  setCustomValidity: (message) => isFunction(elm.setCustomValidity) && elm.setCustomValidity(message),
455
495
  reportValidity: () => isFunction(elm.reportValidity) && elm.reportValidity(),
456
496
  };
457
497
  }
498
+ const field = get(control._fields, name);
499
+ if (field && field._f && elm) {
500
+ field._f.ref = _proxyRef.current;
501
+ }
458
502
  }, [control._fields, name]);
459
503
  const field = React.useMemo(() => ({
460
504
  name,
@@ -468,11 +512,7 @@ function useController(props) {
468
512
  }), [name, disabled, formState.disabled, onChange, onBlur, ref, value]);
469
513
  React.useEffect(() => {
470
514
  const _shouldUnregisterField = control._options.shouldUnregister || shouldUnregister;
471
- const previousName = _previousNameRef.current;
472
- if (previousName && previousName !== name && !isArrayField) {
473
- control.unregister(previousName);
474
- }
475
- control.register(name, {
515
+ _registerProps.current = control.register(name, {
476
516
  ..._props.current.rules,
477
517
  ...(isBoolean(_props.current.disabled)
478
518
  ? { disabled: _props.current.disabled }
@@ -486,14 +526,21 @@ function useController(props) {
486
526
  };
487
527
  updateMounted(name, true);
488
528
  if (_shouldUnregisterField) {
489
- const value = cloneObject(get(control._options.defaultValues, name, _props.current.defaultValue));
529
+ const value = cloneObject(get(shouldUnregister
530
+ ? control._defaultValues
531
+ : control._options.values || control._defaultValues, name, get(control._options.defaultValues, name, _props.current.defaultValue)));
490
532
  set(control._defaultValues, name, value);
491
533
  if (isUndefined(get(control._formValues, name))) {
492
534
  set(control._formValues, name, value);
493
535
  }
494
536
  }
495
537
  !isArrayField && control.register(name);
496
- _previousNameRef.current = name;
538
+ if (_proxyRef.current) {
539
+ const field = get(control._fields, name);
540
+ if (field && field._f) {
541
+ field._f.ref = _proxyRef.current;
542
+ }
543
+ }
497
544
  return () => {
498
545
  (isArrayField
499
546
  ? _shouldUnregisterField && !control._state.action
@@ -559,292 +606,80 @@ function useController(props) {
559
606
  */
560
607
  const Controller = (props) => props.render(useController(props));
561
608
 
562
- const flatten = (obj) => {
563
- const output = {};
564
- for (const key of Object.keys(obj)) {
565
- if (isObjectType(obj[key]) && obj[key] !== null) {
566
- const nested = flatten(obj[key]);
567
- for (const nestedKey of Object.keys(nested)) {
568
- output[`${key}.${nestedKey}`] = nested[nestedKey];
609
+ var generateId = () => {
610
+ if (typeof crypto !== 'undefined' && crypto.randomUUID) {
611
+ return crypto.randomUUID();
612
+ }
613
+ const d = typeof performance === 'undefined' ? Date.now() : performance.now() * 1000;
614
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
615
+ const r = ((Math.random() * 16 + d) % 16) | 0;
616
+ return (c == 'x' ? r : (r & 0x3) | 0x8).toString(16);
617
+ });
618
+ };
619
+
620
+ var getFocusFieldName = (name, index, options = {}) => options.shouldFocus || isUndefined(options.shouldFocus)
621
+ ? options.focusName ||
622
+ `${name}.${isUndefined(options.focusIndex) ? index : options.focusIndex}.`
623
+ : '';
624
+
625
+ var getValidationModes = (mode) => ({
626
+ isOnSubmit: !mode || mode === VALIDATION_MODE.onSubmit,
627
+ isOnBlur: mode === VALIDATION_MODE.onBlur,
628
+ isOnChange: mode === VALIDATION_MODE.onChange,
629
+ isOnAll: mode === VALIDATION_MODE.all,
630
+ isOnTouch: mode === VALIDATION_MODE.onTouched,
631
+ });
632
+
633
+ var isWatched = (name, _names, isBlurEvent) => {
634
+ if (isBlurEvent)
635
+ return false;
636
+ if (_names.watchAll || _names.watch.has(name))
637
+ return true;
638
+ for (const watchName of _names.watch) {
639
+ if (name.startsWith(watchName) && name.charAt(watchName.length) === '.')
640
+ return true;
641
+ }
642
+ return false;
643
+ };
644
+
645
+ const iterateFieldsByAction = (fields, action, fieldsNames, abortEarly) => {
646
+ for (const key of fieldsNames || Object.keys(fields)) {
647
+ const field = get(fields, key);
648
+ if (field) {
649
+ const { _f, ...currentField } = field;
650
+ if (_f) {
651
+ if (_f.refs && _f.refs[0] && action(_f.refs[0], key) && !abortEarly) {
652
+ return true;
653
+ }
654
+ else if (_f.ref && action(_f.ref, _f.name) && !abortEarly) {
655
+ return true;
656
+ }
657
+ else {
658
+ if (iterateFieldsByAction(currentField, action)) {
659
+ break;
660
+ }
661
+ }
662
+ }
663
+ else if (isObject(currentField)) {
664
+ if (iterateFieldsByAction(currentField, action)) {
665
+ break;
666
+ }
569
667
  }
570
- }
571
- else {
572
- output[key] = obj[key];
573
668
  }
574
669
  }
575
- return output;
670
+ return;
576
671
  };
577
672
 
578
- const HookFormContext = React.createContext(null);
579
- HookFormContext.displayName = 'HookFormContext';
580
- /**
581
- * This custom hook allows you to access the form context. useFormContext is intended to be used in deeply nested structures, where it would become inconvenient to pass the context as a prop. To be used with {@link FormProvider}.
582
- *
583
- * @remarks
584
- * [API](https://react-hook-form.com/docs/useformcontext) • [Demo](https://codesandbox.io/s/react-hook-form-v7-form-context-ytudi)
585
- *
586
- * @returns return all useForm methods
587
- *
588
- * @example
589
- * ```tsx
590
- * function App() {
591
- * const methods = useForm();
592
- * const onSubmit = data => console.log(data);
593
- *
594
- * return (
595
- * <FormProvider {...methods} >
596
- * <form onSubmit={methods.handleSubmit(onSubmit)}>
597
- * <NestedInput />
598
- * <input type="submit" />
599
- * </form>
600
- * </FormProvider>
601
- * );
602
- * }
603
- *
604
- * function NestedInput() {
605
- * const { register } = useFormContext(); // retrieve all hook methods
606
- * return <input {...register("test")} />;
607
- * }
608
- * ```
609
- */
610
- const useFormContext = () => React.useContext(HookFormContext);
611
- /**
612
- * A provider component that propagates the `useForm` methods to all children components via [React Context](https://react.dev/reference/react/useContext) API. To be used with {@link useFormContext}.
613
- *
614
- * @remarks
615
- * [API](https://react-hook-form.com/docs/useformcontext) • [Demo](https://codesandbox.io/s/react-hook-form-v7-form-context-ytudi)
616
- *
617
- * @param props - all useForm methods
618
- *
619
- * @example
620
- * ```tsx
621
- * function App() {
622
- * const methods = useForm();
623
- * const onSubmit = data => console.log(data);
624
- *
625
- * return (
626
- * <FormProvider {...methods} >
627
- * <form onSubmit={methods.handleSubmit(onSubmit)}>
628
- * <NestedInput />
629
- * <input type="submit" />
630
- * </form>
631
- * </FormProvider>
632
- * );
633
- * }
634
- *
635
- * function NestedInput() {
636
- * const { register } = useFormContext(); // retrieve all hook methods
637
- * return <input {...register("test")} />;
638
- * }
639
- * ```
640
- */
641
- const FormProvider = (props) => {
642
- const { children, watch, getValues, getFieldState, setError, clearErrors, setValue, trigger, formState, resetField, reset, handleSubmit, unregister, control, register, setFocus, subscribe, } = props;
643
- return (React.createElement(HookFormContext.Provider, { value: React.useMemo(() => ({
644
- watch,
645
- getValues,
646
- getFieldState,
647
- setError,
648
- clearErrors,
649
- setValue,
650
- trigger,
651
- formState,
652
- resetField,
653
- reset,
654
- handleSubmit,
655
- unregister,
656
- control,
657
- register,
658
- setFocus,
659
- subscribe,
660
- }), [
661
- clearErrors,
662
- control,
663
- formState,
664
- getFieldState,
665
- getValues,
666
- handleSubmit,
667
- register,
668
- reset,
669
- resetField,
670
- setError,
671
- setFocus,
672
- setValue,
673
- subscribe,
674
- trigger,
675
- unregister,
676
- watch,
677
- ]) },
678
- React.createElement(HookFormControlContext.Provider, { value: control }, children)));
673
+ var updateFieldArrayRootError = (errors, error, name) => {
674
+ const existingErrors = get(errors, name);
675
+ const fieldArrayErrors = Array.isArray(existingErrors) ? existingErrors : [];
676
+ set(fieldArrayErrors, ROOT_ERROR_TYPE, error[name]);
677
+ set(errors, name, fieldArrayErrors);
678
+ return errors;
679
679
  };
680
680
 
681
- const POST_REQUEST = 'post';
682
- /**
683
- * Form component to manage submission.
684
- *
685
- * @param props - to setup submission detail. {@link FormProps}
686
- *
687
- * @returns form component or headless render prop.
688
- *
689
- * @example
690
- * ```tsx
691
- * function App() {
692
- * const { control, formState: { errors } } = useForm();
693
- *
694
- * return (
695
- * <Form action="/api" control={control}>
696
- * <input {...register("name")} />
697
- * <p>{errors?.root?.server && 'Server error'}</p>
698
- * <button>Submit</button>
699
- * </Form>
700
- * );
701
- * }
702
- * ```
703
- */
704
- function Form(props) {
705
- const methods = useFormContext();
706
- const [mounted, setMounted] = React.useState(false);
707
- const { control = methods.control, onSubmit, children, action, method = POST_REQUEST, headers, encType, onError, render, onSuccess, validateStatus, ...rest } = props;
708
- const submit = async (event) => {
709
- let hasError = false;
710
- let type = '';
711
- await control.handleSubmit(async (data) => {
712
- const formData = new FormData();
713
- let formDataJson = '';
714
- try {
715
- formDataJson = JSON.stringify(data);
716
- }
717
- catch (_a) { }
718
- const flattenFormValues = flatten(control._formValues);
719
- for (const key in flattenFormValues) {
720
- formData.append(key, flattenFormValues[key]);
721
- }
722
- if (onSubmit) {
723
- await onSubmit({
724
- data,
725
- event,
726
- method,
727
- formData,
728
- formDataJson,
729
- });
730
- }
731
- if (action) {
732
- try {
733
- const shouldStringifySubmissionData = [
734
- headers && headers['Content-Type'],
735
- encType,
736
- ].some((value) => value && value.includes('json'));
737
- const response = await fetch(String(action), {
738
- method,
739
- headers: {
740
- ...headers,
741
- ...(encType && encType !== 'multipart/form-data'
742
- ? { 'Content-Type': encType }
743
- : {}),
744
- },
745
- body: shouldStringifySubmissionData ? formDataJson : formData,
746
- });
747
- if (response &&
748
- (validateStatus
749
- ? !validateStatus(response.status)
750
- : response.status < 200 || response.status >= 300)) {
751
- hasError = true;
752
- onError && onError({ response });
753
- type = String(response.status);
754
- }
755
- else {
756
- onSuccess && onSuccess({ response });
757
- }
758
- }
759
- catch (error) {
760
- hasError = true;
761
- onError && onError({ error });
762
- }
763
- }
764
- })(event);
765
- if (hasError && props.control) {
766
- props.control._subjects.state.next({
767
- isSubmitSuccessful: false,
768
- });
769
- props.control.setError('root.server', {
770
- type,
771
- });
772
- }
773
- };
774
- React.useEffect(() => {
775
- setMounted(true);
776
- }, []);
777
- return render ? (React.createElement(React.Fragment, null, render({
778
- submit,
779
- }))) : (React.createElement("form", { noValidate: mounted, action: action, method: method, encType: encType, onSubmit: submit, ...rest }, children));
780
- }
781
-
782
- const FormStateSubscribe = ({ control, disabled, exact, name, render, }) => render(useFormState({ control, name, disabled, exact }));
783
-
784
- var appendErrors = (name, validateAllFieldCriteria, errors, type, message) => validateAllFieldCriteria
785
- ? {
786
- ...errors[name],
787
- types: {
788
- ...(errors[name] && errors[name].types ? errors[name].types : {}),
789
- [type]: message || true,
790
- },
791
- }
792
- : {};
793
-
794
- var convertToArrayPayload = (value) => (Array.isArray(value) ? value : [value]);
795
-
796
- var createSubject = () => {
797
- let _observers = [];
798
- const next = (value) => {
799
- for (const observer of _observers) {
800
- observer.next && observer.next(value);
801
- }
802
- };
803
- const subscribe = (observer) => {
804
- _observers.push(observer);
805
- return {
806
- unsubscribe: () => {
807
- _observers = _observers.filter((o) => o !== observer);
808
- },
809
- };
810
- };
811
- const unsubscribe = () => {
812
- _observers = [];
813
- };
814
- return {
815
- get observers() {
816
- return _observers;
817
- },
818
- next,
819
- subscribe,
820
- unsubscribe,
821
- };
822
- };
823
-
824
- function extractFormValues(fieldsState, formValues) {
825
- const values = {};
826
- for (const key in fieldsState) {
827
- if (fieldsState.hasOwnProperty(key)) {
828
- const fieldState = fieldsState[key];
829
- const fieldValue = formValues[key];
830
- if (fieldState && isObject(fieldState) && fieldValue) {
831
- const nestedFieldsState = extractFormValues(fieldState, fieldValue);
832
- if (isObject(nestedFieldsState)) {
833
- values[key] = nestedFieldsState;
834
- }
835
- }
836
- else if (fieldsState[key]) {
837
- values[key] = fieldValue;
838
- }
839
- }
840
- }
841
- return values;
842
- }
843
-
844
681
  var isEmptyObject = (value) => isObject(value) && !Object.keys(value).length;
845
682
 
846
- var isFileInput = (element) => element.type === 'file';
847
-
848
683
  var isHTMLElement = (value) => {
849
684
  if (!isWeb) {
850
685
  return false;
@@ -854,96 +689,19 @@ var isHTMLElement = (value) => {
854
689
  (owner && owner.defaultView ? owner.defaultView.HTMLElement : HTMLElement));
855
690
  };
856
691
 
857
- var isMultipleSelect = (element) => element.type === `select-multiple`;
858
-
859
692
  var isRadioInput = (element) => element.type === 'radio';
860
693
 
861
- var isRadioOrCheckbox = (ref) => isRadioInput(ref) || isCheckBoxInput(ref);
862
-
863
- var live = (ref) => isHTMLElement(ref) && ref.isConnected;
864
-
865
- function baseGet(object, updatePath) {
866
- const length = updatePath.slice(0, -1).length;
867
- let index = 0;
868
- while (index < length) {
869
- object = isUndefined(object) ? index++ : object[updatePath[index++]];
870
- }
871
- return object;
872
- }
873
- function isEmptyArray(obj) {
874
- for (const key in obj) {
875
- if (obj.hasOwnProperty(key) && !isUndefined(obj[key])) {
876
- return false;
877
- }
878
- }
879
- return true;
880
- }
881
- function unset(object, path) {
882
- const paths = Array.isArray(path)
883
- ? path
884
- : isKey(path)
885
- ? [path]
886
- : stringToPath(path);
887
- const childObject = paths.length === 1 ? object : baseGet(object, paths);
888
- const index = paths.length - 1;
889
- const key = paths[index];
890
- if (childObject) {
891
- delete childObject[key];
892
- }
893
- if (index !== 0 &&
894
- ((isObject(childObject) && isEmptyObject(childObject)) ||
895
- (Array.isArray(childObject) && isEmptyArray(childObject)))) {
896
- unset(object, paths.slice(0, -1));
897
- }
898
- return object;
899
- }
900
-
901
- var objectHasFunction = (data) => {
902
- for (const key in data) {
903
- if (isFunction(data[key])) {
904
- return true;
905
- }
906
- }
907
- return false;
908
- };
694
+ var isRegex = (value) => value instanceof RegExp;
909
695
 
910
- function isTraversable(value) {
911
- return Array.isArray(value) || (isObject(value) && !objectHasFunction(value));
912
- }
913
- function markFieldsDirty(data, fields = {}) {
914
- for (const key in data) {
915
- const value = data[key];
916
- if (isTraversable(value)) {
917
- fields[key] = Array.isArray(value) ? [] : {};
918
- markFieldsDirty(value, fields[key]);
919
- }
920
- else if (!isUndefined(value)) {
921
- fields[key] = true;
922
- }
923
- }
924
- return fields;
925
- }
926
- function getDirtyFields(data, formValues, dirtyFieldsFromValues) {
927
- if (!dirtyFieldsFromValues) {
928
- dirtyFieldsFromValues = markFieldsDirty(formValues);
929
- }
930
- for (const key in data) {
931
- const value = data[key];
932
- if (isTraversable(value)) {
933
- if (isUndefined(formValues) || isPrimitive(dirtyFieldsFromValues[key])) {
934
- dirtyFieldsFromValues[key] = markFieldsDirty(value, Array.isArray(value) ? [] : {});
935
- }
936
- else {
937
- getDirtyFields(value, isNullOrUndefined(formValues) ? {} : formValues[key], dirtyFieldsFromValues[key]);
938
- }
939
- }
940
- else {
941
- const formValue = formValues[key];
942
- dirtyFieldsFromValues[key] = !deepEqual(value, formValue);
943
- }
696
+ var appendErrors = (name, validateAllFieldCriteria, errors, type, message) => validateAllFieldCriteria
697
+ ? {
698
+ ...errors[name],
699
+ types: {
700
+ ...(errors[name] && errors[name].types ? errors[name].types : {}),
701
+ [type]: message || true,
702
+ },
944
703
  }
945
- return dirtyFieldsFromValues;
946
- }
704
+ : {};
947
705
 
948
706
  const defaultResult = {
949
707
  value: false,
@@ -970,20 +728,6 @@ var getCheckboxValue = (options) => {
970
728
  return defaultResult;
971
729
  };
972
730
 
973
- var getFieldValueAs = (value, { valueAsNumber, valueAsDate, setValueAs }) => isUndefined(value)
974
- ? value
975
- : valueAsNumber
976
- ? value === ''
977
- ? NaN
978
- : value
979
- ? +value
980
- : value
981
- : valueAsDate && isString(value)
982
- ? new Date(value)
983
- : setValueAs
984
- ? setValueAs(value)
985
- : value;
986
-
987
731
  const defaultReturn = {
988
732
  isValid: false,
989
733
  value: null,
@@ -997,195 +741,15 @@ var getRadioValue = (options) => Array.isArray(options)
997
741
  : previous, defaultReturn)
998
742
  : defaultReturn;
999
743
 
1000
- function getFieldValue(_f) {
1001
- const ref = _f.ref;
1002
- if (isFileInput(ref)) {
1003
- return ref.files;
1004
- }
1005
- if (isRadioInput(ref)) {
1006
- return getRadioValue(_f.refs).value;
1007
- }
1008
- if (isMultipleSelect(ref)) {
1009
- return [...ref.selectedOptions].map(({ value }) => value);
1010
- }
1011
- if (isCheckBoxInput(ref)) {
1012
- return getCheckboxValue(_f.refs).value;
1013
- }
1014
- return getFieldValueAs(isUndefined(ref.value) ? _f.ref.value : ref.value, _f);
1015
- }
1016
-
1017
- var getResolverOptions = (fieldsNames, _fields, criteriaMode, shouldUseNativeValidation) => {
1018
- const fields = {};
1019
- for (const name of fieldsNames) {
1020
- const field = get(_fields, name);
1021
- field && set(fields, name, field._f);
1022
- }
1023
- return {
1024
- criteriaMode,
1025
- names: [...fieldsNames],
1026
- fields,
1027
- shouldUseNativeValidation,
1028
- };
1029
- };
1030
-
1031
- var isRegex = (value) => value instanceof RegExp;
1032
-
1033
- var getRuleValue = (rule) => isUndefined(rule)
1034
- ? rule
1035
- : isRegex(rule)
1036
- ? rule.source
1037
- : isObject(rule)
1038
- ? isRegex(rule.value)
1039
- ? rule.value.source
1040
- : rule.value
1041
- : rule;
1042
-
1043
- var getValidationModes = (mode) => ({
1044
- isOnSubmit: !mode || mode === VALIDATION_MODE.onSubmit,
1045
- isOnBlur: mode === VALIDATION_MODE.onBlur,
1046
- isOnChange: mode === VALIDATION_MODE.onChange,
1047
- isOnAll: mode === VALIDATION_MODE.all,
1048
- isOnTouch: mode === VALIDATION_MODE.onTouched,
1049
- });
1050
-
1051
- const ASYNC_FUNCTION = 'AsyncFunction';
1052
- var hasPromiseValidation = (fieldReference) => !!fieldReference &&
1053
- !!fieldReference.validate &&
1054
- !!((isFunction(fieldReference.validate) &&
1055
- fieldReference.validate.constructor.name === ASYNC_FUNCTION) ||
1056
- (isObject(fieldReference.validate) &&
1057
- Object.values(fieldReference.validate).find((validateFunction) => validateFunction.constructor.name === ASYNC_FUNCTION)));
1058
-
1059
- var hasValidation = (options) => options.mount &&
1060
- (options.required ||
1061
- options.min ||
1062
- options.max ||
1063
- options.maxLength ||
1064
- options.minLength ||
1065
- options.pattern ||
1066
- options.validate);
1067
-
1068
- var isWatched = (name, _names, isBlurEvent) => !isBlurEvent &&
1069
- (_names.watchAll ||
1070
- _names.watch.has(name) ||
1071
- [..._names.watch].some((watchName) => name.startsWith(watchName) &&
1072
- /^\.\w+/.test(name.slice(watchName.length))));
1073
-
1074
- const iterateFieldsByAction = (fields, action, fieldsNames, abortEarly) => {
1075
- for (const key of fieldsNames || Object.keys(fields)) {
1076
- const field = get(fields, key);
1077
- if (field) {
1078
- const { _f, ...currentField } = field;
1079
- if (_f) {
1080
- if (_f.refs && _f.refs[0] && action(_f.refs[0], key) && !abortEarly) {
1081
- return true;
1082
- }
1083
- else if (_f.ref && action(_f.ref, _f.name) && !abortEarly) {
1084
- return true;
1085
- }
1086
- else {
1087
- if (iterateFieldsByAction(currentField, action)) {
1088
- break;
1089
- }
1090
- }
1091
- }
1092
- else if (isObject(currentField)) {
1093
- if (iterateFieldsByAction(currentField, action)) {
1094
- break;
1095
- }
1096
- }
1097
- }
1098
- }
1099
- return;
1100
- };
1101
-
1102
- function schemaErrorLookup(errors, _fields, name) {
1103
- const error = get(errors, name);
1104
- if (error || isKey(name)) {
1105
- return {
1106
- error,
1107
- name,
1108
- };
1109
- }
1110
- const names = name.split('.');
1111
- while (names.length) {
1112
- const fieldName = names.join('.');
1113
- const field = get(_fields, fieldName);
1114
- const foundError = get(errors, fieldName);
1115
- if (field && !Array.isArray(field) && name !== fieldName) {
1116
- return { name };
1117
- }
1118
- if (foundError && foundError.type) {
1119
- return {
1120
- name: fieldName,
1121
- error: foundError,
1122
- };
1123
- }
1124
- if (foundError && foundError.root && foundError.root.type) {
1125
- return {
1126
- name: `${fieldName}.root`,
1127
- error: foundError.root,
1128
- };
1129
- }
1130
- names.pop();
1131
- }
1132
- return {
1133
- name,
1134
- };
1135
- }
1136
-
1137
- var shouldRenderFormState = (formStateData, _proxyFormState, updateFormState, isRoot) => {
1138
- updateFormState(formStateData);
1139
- const { name, ...formState } = formStateData;
1140
- return (isEmptyObject(formState) ||
1141
- Object.keys(formState).length >= Object.keys(_proxyFormState).length ||
1142
- Object.keys(formState).find((key) => _proxyFormState[key] ===
1143
- (!isRoot || VALIDATION_MODE.all)));
1144
- };
1145
-
1146
- var shouldSubscribeByName = (name, signalName, exact) => !name ||
1147
- !signalName ||
1148
- name === signalName ||
1149
- convertToArrayPayload(name).some((currentName) => currentName &&
1150
- (exact
1151
- ? currentName === signalName
1152
- : currentName.startsWith(signalName) ||
1153
- signalName.startsWith(currentName)));
1154
-
1155
- var skipValidation = (isBlurEvent, isTouched, isSubmitted, reValidateMode, mode) => {
1156
- if (mode.isOnAll) {
1157
- return false;
1158
- }
1159
- else if (!isSubmitted && mode.isOnTouch) {
1160
- return !(isTouched || isBlurEvent);
1161
- }
1162
- else if (isSubmitted ? reValidateMode.isOnBlur : mode.isOnBlur) {
1163
- return !isBlurEvent;
1164
- }
1165
- else if (isSubmitted ? reValidateMode.isOnChange : mode.isOnChange) {
1166
- return isBlurEvent;
1167
- }
1168
- return true;
1169
- };
1170
-
1171
- var unsetEmptyArray = (ref, name) => !compact(get(ref, name)).length && unset(ref, name);
1172
-
1173
- var updateFieldArrayRootError = (errors, error, name) => {
1174
- const fieldArrayErrors = convertToArrayPayload(get(errors, name));
1175
- set(fieldArrayErrors, ROOT_ERROR_TYPE, error[name]);
1176
- set(errors, name, fieldArrayErrors);
1177
- return errors;
1178
- };
1179
-
1180
- function getValidateError(result, ref, type = 'validate') {
1181
- if (isString(result) ||
1182
- (Array.isArray(result) && result.every(isString)) ||
1183
- (isBoolean(result) && !result)) {
1184
- return {
1185
- type,
1186
- message: isString(result) ? result : '',
1187
- ref,
1188
- };
744
+ function getValidateError(result, ref, type = 'validate') {
745
+ if (isString(result) ||
746
+ (Array.isArray(result) && result.every(isString)) ||
747
+ (isBoolean(result) && !result)) {
748
+ return {
749
+ type,
750
+ message: isString(result) ? result : '',
751
+ ref,
752
+ };
1189
753
  }
1190
754
  }
1191
755
 
@@ -1205,7 +769,13 @@ var validateField = async (field, disabledFieldNames, formValues, validateAllFie
1205
769
  const inputRef = refs ? refs[0] : ref;
1206
770
  const setCustomValidity = (message) => {
1207
771
  if (shouldUseNativeValidation && inputRef.reportValidity) {
1208
- inputRef.setCustomValidity(isBoolean(message) ? '' : message || '');
772
+ const validityMessage = isBoolean(message) ? '' : message || '';
773
+ if (refs) {
774
+ refs.forEach((ref) => ref.setCustomValidity(validityMessage));
775
+ }
776
+ else {
777
+ inputRef.setCustomValidity(validityMessage);
778
+ }
1209
779
  inputRef.reportValidity();
1210
780
  }
1211
781
  };
@@ -1375,1513 +945,2383 @@ var validateField = async (field, disabledFieldNames, formValues, validateAllFie
1375
945
  return error;
1376
946
  };
1377
947
 
1378
- const defaultOptions = {
1379
- mode: VALIDATION_MODE.onSubmit,
1380
- reValidateMode: VALIDATION_MODE.onChange,
1381
- shouldFocusError: true,
948
+ var convertToArrayPayload = (value) => (Array.isArray(value) ? value : [value]);
949
+
950
+ var appendAt = (data, value) => [
951
+ ...data,
952
+ ...convertToArrayPayload(value),
953
+ ];
954
+
955
+ var fillEmptyArray = (value) => Array.isArray(value) ? value.map(() => undefined) : undefined;
956
+
957
+ function insert(data, index, value) {
958
+ return [
959
+ ...data.slice(0, index),
960
+ ...convertToArrayPayload(value),
961
+ ...data.slice(index),
962
+ ];
963
+ }
964
+
965
+ var moveArrayAt = (data, from, to) => {
966
+ if (!Array.isArray(data)) {
967
+ return [];
968
+ }
969
+ if (isUndefined(data[to])) {
970
+ data[to] = undefined;
971
+ }
972
+ data.splice(to, 0, data.splice(from, 1)[0]);
973
+ return data;
1382
974
  };
1383
- function createFormControl(props = {}) {
1384
- let _options = {
1385
- ...defaultOptions,
1386
- ...props,
1387
- };
1388
- let _formState = {
1389
- submitCount: 0,
1390
- isDirty: false,
1391
- isReady: false,
1392
- isLoading: isFunction(_options.defaultValues),
1393
- isValidating: false,
1394
- isSubmitted: false,
1395
- isSubmitting: false,
1396
- isSubmitSuccessful: false,
1397
- isValid: false,
1398
- touchedFields: {},
1399
- dirtyFields: {},
1400
- validatingFields: {},
1401
- errors: _options.errors || {},
1402
- disabled: _options.disabled || false,
1403
- };
1404
- let _fields = {};
1405
- let _defaultValues = isObject(_options.defaultValues) || isObject(_options.values)
1406
- ? cloneObject(_options.defaultValues || _options.values) || {}
1407
- : {};
1408
- let _formValues = _options.shouldUnregister
1409
- ? {}
1410
- : cloneObject(_defaultValues);
1411
- let _state = {
1412
- action: false,
1413
- mount: false,
1414
- watch: false,
1415
- keepIsValid: false,
1416
- };
1417
- let _names = {
1418
- mount: new Set(),
1419
- disabled: new Set(),
1420
- unMount: new Set(),
1421
- array: new Set(),
1422
- watch: new Set(),
1423
- };
1424
- let delayErrorCallback;
1425
- let timer = 0;
1426
- const defaultProxyFormState = {
1427
- isDirty: false,
1428
- dirtyFields: false,
1429
- validatingFields: false,
1430
- touchedFields: false,
1431
- isValidating: false,
1432
- isValid: false,
1433
- errors: false,
1434
- };
1435
- const _proxyFormState = {
1436
- ...defaultProxyFormState,
1437
- };
1438
- let _proxySubscribeFormState = {
1439
- ..._proxyFormState,
1440
- };
1441
- const _subjects = {
1442
- array: createSubject(),
1443
- state: createSubject(),
1444
- };
1445
- const shouldDisplayAllAssociatedErrors = _options.criteriaMode === VALIDATION_MODE.all;
1446
- const debounce = (callback) => (wait) => {
1447
- clearTimeout(timer);
1448
- timer = setTimeout(callback, wait);
1449
- };
1450
- const _setValid = async (shouldUpdateValid) => {
1451
- if (_state.keepIsValid) {
1452
- return;
1453
- }
1454
- if (!_options.disabled &&
1455
- (_proxyFormState.isValid ||
1456
- _proxySubscribeFormState.isValid ||
1457
- shouldUpdateValid)) {
1458
- let isValid;
1459
- if (_options.resolver) {
1460
- isValid = isEmptyObject((await _runSchema()).errors);
1461
- _updateIsValidating();
1462
- }
1463
- else {
1464
- isValid = await executeBuiltInValidation({
1465
- fields: _fields,
1466
- onlyCheckValid: true,
1467
- eventType: EVENTS.VALID,
1468
- });
1469
- }
1470
- if (isValid !== _formState.isValid) {
1471
- _subjects.state.next({
1472
- isValid,
1473
- });
1474
- }
975
+
976
+ var prependAt = (data, value) => [
977
+ ...convertToArrayPayload(value),
978
+ ...convertToArrayPayload(data),
979
+ ];
980
+
981
+ var compact = (value) => Array.isArray(value) ? value.filter(Boolean) : [];
982
+
983
+ function removeAtIndexes(data, indexes) {
984
+ let i = 0;
985
+ const temp = [...data];
986
+ for (const index of indexes) {
987
+ temp.splice(index - i, 1);
988
+ i++;
989
+ }
990
+ return compact(temp).length ? temp : [];
991
+ }
992
+ var removeArrayAt = (data, index) => isUndefined(index)
993
+ ? []
994
+ : removeAtIndexes(data, convertToArrayPayload(index).sort((a, b) => a - b));
995
+
996
+ var swapArrayAt = (data, indexA, indexB) => {
997
+ [data[indexA], data[indexB]] = [data[indexB], data[indexA]];
998
+ };
999
+
1000
+ function baseGet(object, updatePath) {
1001
+ const length = updatePath.slice(0, -1).length;
1002
+ let index = 0;
1003
+ while (index < length) {
1004
+ if (isNullOrUndefined(object)) {
1005
+ object = undefined;
1006
+ break;
1475
1007
  }
1476
- };
1477
- const _updateIsValidating = (names, isValidating) => {
1478
- if (!_options.disabled &&
1479
- (_proxyFormState.isValidating ||
1480
- _proxyFormState.validatingFields ||
1481
- _proxySubscribeFormState.isValidating ||
1482
- _proxySubscribeFormState.validatingFields)) {
1483
- (names || Array.from(_names.mount)).forEach((name) => {
1484
- if (name) {
1485
- isValidating
1486
- ? set(_formState.validatingFields, name, isValidating)
1487
- : unset(_formState.validatingFields, name);
1488
- }
1489
- });
1490
- _subjects.state.next({
1491
- validatingFields: _formState.validatingFields,
1492
- isValidating: !isEmptyObject(_formState.validatingFields),
1493
- });
1008
+ object = object[updatePath[index]];
1009
+ index++;
1010
+ }
1011
+ return object;
1012
+ }
1013
+ function isEmptyArray(obj) {
1014
+ for (const key in obj) {
1015
+ if (obj.hasOwnProperty(key) && !isUndefined(obj[key])) {
1016
+ return false;
1494
1017
  }
1495
- };
1496
- const _setFieldArray = (name, values = [], method, args, shouldSetValues = true, shouldUpdateFieldsAndState = true) => {
1497
- if (args && method && !_options.disabled) {
1498
- _state.action = true;
1499
- if (shouldUpdateFieldsAndState && Array.isArray(get(_fields, name))) {
1500
- const fieldValues = method(get(_fields, name), args.argA, args.argB);
1501
- shouldSetValues && set(_fields, name, fieldValues);
1502
- }
1503
- if (shouldUpdateFieldsAndState &&
1504
- Array.isArray(get(_formState.errors, name))) {
1505
- const errors = method(get(_formState.errors, name), args.argA, args.argB);
1506
- shouldSetValues && set(_formState.errors, name, errors);
1507
- unsetEmptyArray(_formState.errors, name);
1508
- }
1509
- if ((_proxyFormState.touchedFields ||
1510
- _proxySubscribeFormState.touchedFields) &&
1511
- shouldUpdateFieldsAndState &&
1512
- Array.isArray(get(_formState.touchedFields, name))) {
1513
- const touchedFields = method(get(_formState.touchedFields, name), args.argA, args.argB);
1514
- shouldSetValues && set(_formState.touchedFields, name, touchedFields);
1515
- }
1516
- if (_proxyFormState.dirtyFields || _proxySubscribeFormState.dirtyFields) {
1517
- const fullDirtyFields = getDirtyFields(_defaultValues, _formValues);
1518
- const rootName = getNodeParentName(name);
1519
- set(_formState.dirtyFields, rootName, get(fullDirtyFields, rootName));
1520
- }
1521
- _subjects.state.next({
1522
- name,
1523
- isDirty: _getDirty(name, values),
1524
- dirtyFields: _formState.dirtyFields,
1525
- errors: _formState.errors,
1526
- isValid: _formState.isValid,
1527
- });
1018
+ }
1019
+ return true;
1020
+ }
1021
+ function unset(object, path) {
1022
+ if (isString(path) && Object.prototype.hasOwnProperty.call(object, path)) {
1023
+ delete object[path];
1024
+ return object;
1025
+ }
1026
+ const paths = Array.isArray(path)
1027
+ ? path
1028
+ : isKey(path)
1029
+ ? [path]
1030
+ : stringToPath(path);
1031
+ if (paths.some((segment) => PROTOTYPE_KEYWORDS.includes(String(segment)))) {
1032
+ return object;
1033
+ }
1034
+ const childObject = paths.length === 1 ? object : baseGet(object, paths);
1035
+ const index = paths.length - 1;
1036
+ const key = paths[index];
1037
+ if (childObject) {
1038
+ delete childObject[key];
1039
+ }
1040
+ if (index !== 0 &&
1041
+ ((isObject(childObject) && isEmptyObject(childObject)) ||
1042
+ (Array.isArray(childObject) && isEmptyArray(childObject)))) {
1043
+ unset(object, paths.slice(0, -1));
1044
+ }
1045
+ return object;
1046
+ }
1047
+
1048
+ var updateAt = (fieldValues, index, value) => {
1049
+ fieldValues[index] = value;
1050
+ return fieldValues;
1051
+ };
1052
+
1053
+ /**
1054
+ * A custom hook that exposes convenient methods to perform operations with a list of dynamic inputs that need to be appended, updated, removed etc. • [Demo](https://codesandbox.io/s/react-hook-form-usefieldarray-ssugn) • [Video](https://youtu.be/4MrbfGSFY2A)
1055
+ *
1056
+ * @remarks
1057
+ * [API](https://react-hook-form.com/docs/usefieldarray) • [Demo](https://codesandbox.io/s/react-hook-form-usefieldarray-ssugn)
1058
+ *
1059
+ * @param props - useFieldArray props
1060
+ *
1061
+ * @returns methods - functions to manipulate with the Field Arrays (dynamic inputs) {@link UseFieldArrayReturn}
1062
+ *
1063
+ * @example
1064
+ * ```tsx
1065
+ * function App() {
1066
+ * const { register, control, handleSubmit, reset, trigger, setError } = useForm({
1067
+ * defaultValues: {
1068
+ * test: []
1069
+ * }
1070
+ * });
1071
+ * const { fields, append } = useFieldArray({
1072
+ * control,
1073
+ * name: "test"
1074
+ * });
1075
+ *
1076
+ * return (
1077
+ * <form onSubmit={handleSubmit(data => console.log(data))}>
1078
+ * {fields.map((item, index) => (
1079
+ * <input key={item.id} {...register(`test.${index}.firstName`)} />
1080
+ * ))}
1081
+ * <button type="button" onClick={() => append({ firstName: "bill" })}>
1082
+ * append
1083
+ * </button>
1084
+ * <input type="submit" />
1085
+ * </form>
1086
+ * );
1087
+ * }
1088
+ * ```
1089
+ */
1090
+ function useFieldArray(props) {
1091
+ const formControl = useFormControlContext();
1092
+ const { control = formControl, name, keyName = 'id', disabled, shouldUnregister, rules, } = props;
1093
+ const [fields, setFields] = React.useState(control._getFieldArray(name));
1094
+ const ids = React.useRef(control._getFieldArray(name).map(generateId));
1095
+ const _actioned = React.useRef(false);
1096
+ if (!disabled) {
1097
+ control._names.array.add(name);
1098
+ }
1099
+ React.useMemo(() => !disabled &&
1100
+ rules &&
1101
+ fields.length >= 0 &&
1102
+ control.register(name, rules), [control, name, fields.length, rules, disabled]);
1103
+ useIsomorphicLayoutEffect(() => {
1104
+ if (disabled) {
1105
+ return;
1528
1106
  }
1529
- else {
1530
- set(_formValues, name, values);
1107
+ return control._subjects.array.subscribe({
1108
+ next: ({ values, name: fieldArrayName, }) => {
1109
+ if (fieldArrayName === name || !fieldArrayName) {
1110
+ const fieldValues = get(values, name);
1111
+ if (Array.isArray(fieldValues)) {
1112
+ setFields(fieldValues);
1113
+ ids.current = fieldValues.map(generateId);
1114
+ }
1115
+ else if (!fieldArrayName) {
1116
+ setFields([]);
1117
+ ids.current = [];
1118
+ }
1119
+ }
1120
+ },
1121
+ }).unsubscribe;
1122
+ }, [control, name, disabled]);
1123
+ const updateValues = React.useCallback((updatedFieldArrayValues) => {
1124
+ _actioned.current = true;
1125
+ control._setFieldArray(name, updatedFieldArrayValues);
1126
+ }, [control, name]);
1127
+ const append = (value, options) => {
1128
+ if (disabled) {
1129
+ return;
1531
1130
  }
1131
+ const appendValue = convertToArrayPayload(cloneObject(value));
1132
+ const updatedFieldArrayValues = appendAt(control._getFieldArray(name), appendValue);
1133
+ control._names.focus = getFocusFieldName(name, updatedFieldArrayValues.length - 1, options);
1134
+ ids.current = appendAt(ids.current, appendValue.map(generateId));
1135
+ updateValues(updatedFieldArrayValues);
1136
+ setFields(updatedFieldArrayValues);
1137
+ control._setFieldArray(name, updatedFieldArrayValues, appendAt, {
1138
+ argA: fillEmptyArray(value),
1139
+ });
1532
1140
  };
1533
- const updateErrors = (name, error) => {
1534
- set(_formState.errors, name, error);
1535
- _subjects.state.next({
1536
- errors: _formState.errors,
1141
+ const prepend = (value, options) => {
1142
+ if (disabled) {
1143
+ return;
1144
+ }
1145
+ const prependValue = convertToArrayPayload(cloneObject(value));
1146
+ const updatedFieldArrayValues = prependAt(control._getFieldArray(name), prependValue);
1147
+ control._names.focus = getFocusFieldName(name, 0, options);
1148
+ ids.current = prependAt(ids.current, prependValue.map(generateId));
1149
+ updateValues(updatedFieldArrayValues);
1150
+ setFields(updatedFieldArrayValues);
1151
+ control._setFieldArray(name, updatedFieldArrayValues, prependAt, {
1152
+ argA: fillEmptyArray(value),
1537
1153
  });
1538
1154
  };
1539
- const _setErrors = (errors) => {
1540
- _formState.errors = errors;
1541
- _subjects.state.next({
1542
- errors: _formState.errors,
1543
- isValid: false,
1155
+ const remove = (index) => {
1156
+ if (disabled) {
1157
+ return;
1158
+ }
1159
+ const updatedFieldArrayValues = removeArrayAt(control._getFieldArray(name), index);
1160
+ ids.current = removeArrayAt(ids.current, index);
1161
+ updateValues(updatedFieldArrayValues);
1162
+ setFields(updatedFieldArrayValues);
1163
+ !Array.isArray(get(control._fields, name)) &&
1164
+ set(control._fields, name, undefined);
1165
+ control._setFieldArray(name, updatedFieldArrayValues, removeArrayAt, {
1166
+ argA: index,
1544
1167
  });
1545
1168
  };
1546
- const updateValidAndValue = (name, shouldSkipSetValueAs, value, ref) => {
1547
- const field = get(_fields, name);
1548
- if (field) {
1549
- const defaultValue = get(_formValues, name, isUndefined(value) ? get(_defaultValues, name) : value);
1550
- isUndefined(defaultValue) ||
1551
- (ref && ref.defaultChecked) ||
1552
- shouldSkipSetValueAs
1553
- ? set(_formValues, name, shouldSkipSetValueAs ? defaultValue : getFieldValue(field._f))
1554
- : setFieldValue(name, defaultValue);
1555
- _state.mount && !_state.action && _setValid();
1169
+ const insert$1 = (index, value, options) => {
1170
+ if (disabled) {
1171
+ return;
1556
1172
  }
1173
+ const insertValue = convertToArrayPayload(cloneObject(value));
1174
+ const updatedFieldArrayValues = insert(control._getFieldArray(name), index, insertValue);
1175
+ control._names.focus = getFocusFieldName(name, index, options);
1176
+ ids.current = insert(ids.current, index, insertValue.map(generateId));
1177
+ updateValues(updatedFieldArrayValues);
1178
+ setFields(updatedFieldArrayValues);
1179
+ control._setFieldArray(name, updatedFieldArrayValues, insert, {
1180
+ argA: index,
1181
+ argB: fillEmptyArray(value),
1182
+ });
1557
1183
  };
1558
- const updateTouchAndDirty = (name, fieldValue, isBlurEvent, shouldDirty, shouldRender) => {
1559
- let shouldUpdateField = false;
1560
- let isPreviousDirty = false;
1561
- const output = {
1562
- name,
1563
- };
1564
- if (!_options.disabled) {
1565
- if (!isBlurEvent || shouldDirty) {
1566
- if (_proxyFormState.isDirty || _proxySubscribeFormState.isDirty) {
1567
- isPreviousDirty = _formState.isDirty;
1568
- _formState.isDirty = output.isDirty = _getDirty();
1569
- shouldUpdateField = isPreviousDirty !== output.isDirty;
1570
- }
1571
- const isCurrentFieldPristine = deepEqual(get(_defaultValues, name), fieldValue);
1572
- isPreviousDirty = !!get(_formState.dirtyFields, name);
1573
- isCurrentFieldPristine
1574
- ? unset(_formState.dirtyFields, name)
1575
- : set(_formState.dirtyFields, name, true);
1576
- output.dirtyFields = _formState.dirtyFields;
1577
- shouldUpdateField =
1578
- shouldUpdateField ||
1579
- ((_proxyFormState.dirtyFields ||
1580
- _proxySubscribeFormState.dirtyFields) &&
1581
- isPreviousDirty !== !isCurrentFieldPristine);
1582
- }
1583
- if (isBlurEvent) {
1584
- const isPreviousFieldTouched = get(_formState.touchedFields, name);
1585
- if (!isPreviousFieldTouched) {
1586
- set(_formState.touchedFields, name, isBlurEvent);
1587
- output.touchedFields = _formState.touchedFields;
1588
- shouldUpdateField =
1589
- shouldUpdateField ||
1590
- ((_proxyFormState.touchedFields ||
1591
- _proxySubscribeFormState.touchedFields) &&
1592
- isPreviousFieldTouched !== isBlurEvent);
1593
- }
1594
- }
1595
- shouldUpdateField && shouldRender && _subjects.state.next(output);
1184
+ const swap = (indexA, indexB) => {
1185
+ if (disabled) {
1186
+ return;
1596
1187
  }
1597
- return shouldUpdateField ? output : {};
1188
+ const updatedFieldArrayValues = control._getFieldArray(name);
1189
+ swapArrayAt(updatedFieldArrayValues, indexA, indexB);
1190
+ swapArrayAt(ids.current, indexA, indexB);
1191
+ updateValues(updatedFieldArrayValues);
1192
+ setFields(updatedFieldArrayValues);
1193
+ control._setFieldArray(name, updatedFieldArrayValues, swapArrayAt, {
1194
+ argA: indexA,
1195
+ argB: indexB,
1196
+ }, false);
1598
1197
  };
1599
- const shouldRenderByError = (name, isValid, error, fieldState) => {
1600
- const previousFieldError = get(_formState.errors, name);
1601
- const shouldUpdateValid = (_proxyFormState.isValid || _proxySubscribeFormState.isValid) &&
1602
- isBoolean(isValid) &&
1603
- _formState.isValid !== isValid;
1604
- if (_options.delayError && error) {
1605
- delayErrorCallback = debounce(() => updateErrors(name, error));
1606
- delayErrorCallback(_options.delayError);
1607
- }
1608
- else {
1609
- clearTimeout(timer);
1610
- delayErrorCallback = null;
1611
- error
1612
- ? set(_formState.errors, name, error)
1613
- : unset(_formState.errors, name);
1614
- }
1615
- if ((error ? !deepEqual(previousFieldError, error) : previousFieldError) ||
1616
- !isEmptyObject(fieldState) ||
1617
- shouldUpdateValid) {
1618
- const updatedFormState = {
1619
- ...fieldState,
1620
- ...(shouldUpdateValid && isBoolean(isValid) ? { isValid } : {}),
1621
- errors: _formState.errors,
1622
- name,
1623
- };
1624
- _formState = {
1625
- ..._formState,
1626
- ...updatedFormState,
1627
- };
1628
- _subjects.state.next(updatedFormState);
1198
+ const move = (from, to) => {
1199
+ if (disabled) {
1200
+ return;
1629
1201
  }
1202
+ const updatedFieldArrayValues = control._getFieldArray(name);
1203
+ moveArrayAt(updatedFieldArrayValues, from, to);
1204
+ moveArrayAt(ids.current, from, to);
1205
+ updateValues(updatedFieldArrayValues);
1206
+ setFields(updatedFieldArrayValues);
1207
+ control._setFieldArray(name, updatedFieldArrayValues, moveArrayAt, {
1208
+ argA: from,
1209
+ argB: to,
1210
+ }, false);
1630
1211
  };
1631
- const _runSchema = async (name) => {
1632
- _updateIsValidating(name, true);
1633
- return await _options.resolver(_formValues, _options.context, getResolverOptions(name || _names.mount, _fields, _options.criteriaMode, _options.shouldUseNativeValidation));
1634
- };
1635
- const executeSchemaAndUpdateState = async (names) => {
1636
- const { errors } = await _runSchema(names);
1637
- _updateIsValidating(names);
1638
- if (names) {
1639
- for (const name of names) {
1640
- const error = get(errors, name);
1641
- error
1642
- ? set(_formState.errors, name, error)
1643
- : unset(_formState.errors, name);
1644
- }
1212
+ const update = (index, value) => {
1213
+ if (disabled) {
1214
+ return;
1645
1215
  }
1646
- else {
1647
- _formState.errors = errors;
1216
+ const updateValue = cloneObject(value);
1217
+ const updatedFieldArrayValues = updateAt(control._getFieldArray(name), index, updateValue);
1218
+ ids.current = [...updatedFieldArrayValues].map((item, i) => !item || i === index ? generateId() : ids.current[i]);
1219
+ updateValues(updatedFieldArrayValues);
1220
+ setFields([...updatedFieldArrayValues]);
1221
+ control._setFieldArray(name, updatedFieldArrayValues, updateAt, {
1222
+ argA: index,
1223
+ argB: updateValue,
1224
+ }, true, false);
1225
+ };
1226
+ const replace = (value) => {
1227
+ if (disabled) {
1228
+ return;
1648
1229
  }
1649
- return errors;
1230
+ const updatedFieldArrayValues = convertToArrayPayload(cloneObject(value));
1231
+ ids.current = updatedFieldArrayValues.map(generateId);
1232
+ updateValues([...updatedFieldArrayValues]);
1233
+ setFields([...updatedFieldArrayValues]);
1234
+ control._setFieldArray(name, [...updatedFieldArrayValues], (data) => data, {}, true, false);
1650
1235
  };
1651
- const validateForm = async ({ name, eventType, }) => {
1652
- if (props.validate) {
1653
- const result = await props.validate({
1654
- formValues: _formValues,
1655
- formState: _formState,
1656
- name,
1657
- eventType,
1236
+ React.useEffect(() => {
1237
+ if (disabled) {
1238
+ return;
1239
+ }
1240
+ control._state.action = false;
1241
+ isWatched(name, control._names) &&
1242
+ control._subjects.state.next({
1243
+ ...control._formState,
1658
1244
  });
1659
- if (isObject(result)) {
1660
- for (const key in result) {
1661
- const error = result[key];
1662
- if (error) {
1663
- setError(`${FORM_ERROR_TYPE}.${key}`, {
1664
- message: isString(result.message) ? result.message : '',
1665
- type: INPUT_VALIDATION_RULES.validate,
1245
+ const validationModes = getValidationModes(control._options.mode);
1246
+ if (_actioned.current &&
1247
+ (!validationModes.isOnSubmit || control._formState.isSubmitted) &&
1248
+ !getValidationModes(control._options.reValidateMode).isOnSubmit &&
1249
+ !validationModes.isOnBlur) {
1250
+ if (control._options.resolver) {
1251
+ control._runSchema([name]).then((result) => {
1252
+ var _a, _b;
1253
+ control._updateIsValidating([name]);
1254
+ const error = get(result.errors, name);
1255
+ const existingError = get(control._formState.errors, name);
1256
+ const existingErrorType = existingError && (existingError.type || ((_a = existingError.root) === null || _a === void 0 ? void 0 : _a.type));
1257
+ const existingErrorMessage = existingError &&
1258
+ (existingError.message || ((_b = existingError.root) === null || _b === void 0 ? void 0 : _b.message));
1259
+ if (existingError
1260
+ ? (!error && existingErrorType) ||
1261
+ (error &&
1262
+ (existingErrorType !== error.type ||
1263
+ existingErrorMessage !== error.message))
1264
+ : error && error.type) {
1265
+ if (error) {
1266
+ isObject(error) &&
1267
+ !Object.keys(error).some((key) => !Number.isNaN(+key))
1268
+ ? updateFieldArrayRootError(control._formState.errors, { [name]: error }, name)
1269
+ : set(control._formState.errors, name, error);
1270
+ }
1271
+ else {
1272
+ unset(control._formState.errors, name);
1273
+ }
1274
+ control._subjects.state.next({
1275
+ errors: control._formState.errors,
1666
1276
  });
1667
1277
  }
1668
- }
1669
- }
1670
- else if (isString(result) || !result) {
1671
- setError(FORM_ERROR_TYPE, {
1672
- message: result || '',
1673
- type: INPUT_VALIDATION_RULES.validate,
1674
1278
  });
1675
1279
  }
1676
1280
  else {
1677
- clearErrors(FORM_ERROR_TYPE);
1281
+ const field = get(control._fields, name);
1282
+ if (field &&
1283
+ field._f &&
1284
+ !(getValidationModes(control._options.reValidateMode).isOnSubmit &&
1285
+ getValidationModes(control._options.mode).isOnSubmit)) {
1286
+ validateField(field, control._names.disabled, control._formValues, control._options.criteriaMode === VALIDATION_MODE.all, control._options.shouldUseNativeValidation, true).then((error) => !isEmptyObject(error) &&
1287
+ control._subjects.state.next({
1288
+ errors: updateFieldArrayRootError(control._formState.errors, error, name),
1289
+ }));
1290
+ }
1678
1291
  }
1679
- return result;
1680
1292
  }
1681
- return true;
1682
- };
1683
- const executeBuiltInValidation = async ({ fields, onlyCheckValid, name, eventType, context = {
1684
- valid: true,
1685
- runRootValidation: false,
1686
- }, }) => {
1687
- if (props.validate) {
1688
- context.runRootValidation = true;
1689
- const result = await validateForm({
1293
+ // External updates that change `fields` (e.g. reset() or setValue() on
1294
+ // the array) already notify subscribers with the up-to-date values
1295
+ // themselves, so only re-broadcast here for genuine array method calls.
1296
+ _actioned.current &&
1297
+ control._subjects.state.next({
1690
1298
  name,
1691
- eventType,
1299
+ values: cloneObject(control._formValues),
1692
1300
  });
1693
- if (!result) {
1694
- context.valid = false;
1695
- if (onlyCheckValid) {
1696
- return context.valid;
1301
+ control._names.focus &&
1302
+ iterateFieldsByAction(control._fields, (ref, key) => {
1303
+ if (control._names.focus &&
1304
+ key.startsWith(control._names.focus) &&
1305
+ ref.focus) {
1306
+ ref.focus();
1307
+ return 1;
1697
1308
  }
1698
- }
1309
+ return;
1310
+ });
1311
+ control._names.focus = '';
1312
+ control._setValid();
1313
+ _actioned.current = false;
1314
+ }, [fields, name, control, disabled]);
1315
+ React.useEffect(() => {
1316
+ if (!disabled) {
1317
+ !get(control._formValues, name) && control._setFieldArray(name);
1699
1318
  }
1700
- for (const name in fields) {
1701
- const field = fields[name];
1702
- if (field) {
1703
- const { _f, ...fieldValue } = field;
1704
- if (_f) {
1705
- const isFieldArrayRoot = _names.array.has(_f.name);
1706
- const isPromiseFunction = field._f && hasPromiseValidation(field._f);
1707
- if (isPromiseFunction && _proxyFormState.validatingFields) {
1708
- _updateIsValidating([_f.name], true);
1709
- }
1710
- const fieldError = await validateField(field, _names.disabled, _formValues, shouldDisplayAllAssociatedErrors, _options.shouldUseNativeValidation && !onlyCheckValid, isFieldArrayRoot);
1711
- if (isPromiseFunction && _proxyFormState.validatingFields) {
1712
- _updateIsValidating([_f.name]);
1713
- }
1714
- if (fieldError[_f.name]) {
1715
- context.valid = false;
1716
- if (onlyCheckValid) {
1717
- break;
1718
- }
1719
- }
1720
- !onlyCheckValid &&
1721
- (get(fieldError, _f.name)
1722
- ? isFieldArrayRoot
1723
- ? updateFieldArrayRootError(_formState.errors, fieldError, _f.name)
1724
- : set(_formState.errors, _f.name, fieldError[_f.name])
1725
- : unset(_formState.errors, _f.name));
1726
- if (props.shouldUseNativeValidation && fieldError[_f.name]) {
1727
- break;
1728
- }
1319
+ return () => {
1320
+ if (disabled) {
1321
+ return;
1322
+ }
1323
+ const shouldKeepFieldArrayValues = !(control._options.shouldUnregister || shouldUnregister);
1324
+ const updateMounted = (name, value) => {
1325
+ const field = get(control._fields, name);
1326
+ if (field && field._f) {
1327
+ field._f.mount = value;
1729
1328
  }
1730
- !isEmptyObject(fieldValue) &&
1731
- (await executeBuiltInValidation({
1732
- context,
1733
- onlyCheckValid,
1734
- fields: fieldValue,
1735
- name: name,
1736
- eventType,
1737
- }));
1329
+ };
1330
+ if (_actioned.current && shouldKeepFieldArrayValues) {
1331
+ control._subjects.state.next({
1332
+ name,
1333
+ values: cloneObject(control._formValues),
1334
+ });
1738
1335
  }
1739
- }
1740
- return context.valid;
1741
- };
1742
- const _removeUnmounted = () => {
1743
- for (const name of _names.unMount) {
1744
- const field = get(_fields, name);
1745
- field &&
1746
- (field._f.refs
1747
- ? field._f.refs.every((ref) => !live(ref))
1748
- : !live(field._f.ref)) &&
1749
- unregister(name);
1750
- }
1751
- _names.unMount = new Set();
1336
+ shouldKeepFieldArrayValues
1337
+ ? updateMounted(name, false)
1338
+ : control.unregister(name);
1339
+ };
1340
+ }, [name, control, keyName, shouldUnregister, disabled]);
1341
+ return {
1342
+ swap: React.useCallback(swap, [updateValues, name, control, disabled]),
1343
+ move: React.useCallback(move, [updateValues, name, control, disabled]),
1344
+ prepend: React.useCallback(prepend, [
1345
+ updateValues,
1346
+ name,
1347
+ control,
1348
+ disabled,
1349
+ ]),
1350
+ append: React.useCallback(append, [updateValues, name, control, disabled]),
1351
+ remove: React.useCallback(remove, [updateValues, name, control, disabled]),
1352
+ insert: React.useCallback(insert$1, [updateValues, name, control, disabled]),
1353
+ update: React.useCallback(update, [updateValues, name, control, disabled]),
1354
+ replace: React.useCallback(replace, [
1355
+ updateValues,
1356
+ name,
1357
+ control,
1358
+ disabled,
1359
+ ]),
1360
+ fields: React.useMemo(() => fields.map((field, index) => ({
1361
+ ...field,
1362
+ ...(isBoolean(disabled) ? { disabled } : {}),
1363
+ [keyName]: ids.current[index] || generateId(),
1364
+ })), [fields, keyName, disabled]),
1752
1365
  };
1753
- const _getDirty = (name, data) => !_options.disabled &&
1754
- (name && data && set(_formValues, name, data),
1755
- !deepEqual(getValues(), _defaultValues));
1756
- const _getWatch = (names, defaultValue, isGlobal) => generateWatchOutput(names, _names, {
1757
- ...(_state.mount
1758
- ? _formValues
1759
- : isUndefined(defaultValue)
1760
- ? _defaultValues
1761
- : isString(names)
1762
- ? { [names]: defaultValue }
1763
- : defaultValue),
1764
- }, isGlobal, defaultValue);
1765
- const _getFieldArray = (name) => compact(get(_state.mount ? _formValues : _defaultValues, name, _options.shouldUnregister ? get(_defaultValues, name, []) : []));
1766
- const setFieldValue = (name, value, options = {}) => {
1767
- const field = get(_fields, name);
1768
- let fieldValue = value;
1769
- if (field) {
1770
- const fieldReference = field._f;
1771
- if (fieldReference) {
1772
- !fieldReference.disabled &&
1773
- set(_formValues, name, getFieldValueAs(value, fieldReference));
1774
- fieldValue =
1775
- isHTMLElement(fieldReference.ref) && isNullOrUndefined(value)
1776
- ? ''
1777
- : value;
1778
- if (isMultipleSelect(fieldReference.ref)) {
1779
- [...fieldReference.ref.options].forEach((optionRef) => (optionRef.selected = fieldValue.includes(optionRef.value)));
1780
- }
1781
- else if (fieldReference.refs) {
1782
- if (isCheckBoxInput(fieldReference.ref)) {
1783
- fieldReference.refs.forEach((checkboxRef) => {
1784
- if (!checkboxRef.defaultChecked || !checkboxRef.disabled) {
1785
- if (Array.isArray(fieldValue)) {
1786
- checkboxRef.checked = !!fieldValue.find((data) => data === checkboxRef.value);
1787
- }
1788
- else {
1789
- checkboxRef.checked =
1790
- fieldValue === checkboxRef.value || !!fieldValue;
1791
- }
1792
- }
1793
- });
1366
+ }
1367
+
1368
+ /**
1369
+ * Component based on `useFieldArray` hook to work with controlled component.
1370
+ *
1371
+ * @example
1372
+ * ```tsx
1373
+ * function App() {
1374
+ * const { control, register } = useForm<FormValues>({
1375
+ * defaultValues: {
1376
+ * test: [
1377
+ * {
1378
+ * value: '',
1379
+ * },
1380
+ * ],
1381
+ * },
1382
+ * });
1383
+ *
1384
+ * return (
1385
+ * <form>
1386
+ * <FieldArray
1387
+ * control={control}
1388
+ * name="test"
1389
+ * render={({ fields }) =>
1390
+ * fields.map((field, index) => (
1391
+ * <input key={field.id} {...register(`test.${index}.value`)} />
1392
+ * ))
1393
+ * }
1394
+ * />
1395
+ * </form>
1396
+ * );
1397
+ * }
1398
+ * ```
1399
+ */
1400
+ const FieldArray = (props) => props.render(useFieldArray(props));
1401
+
1402
+ const flatten = (obj) => {
1403
+ const output = {};
1404
+ for (const key of Object.keys(obj)) {
1405
+ if (isObjectType(obj[key]) &&
1406
+ obj[key] !== null &&
1407
+ !isDateObject(obj[key])) {
1408
+ const nested = flatten(obj[key]);
1409
+ for (const nestedKey of Object.keys(nested)) {
1410
+ output[`${key}.${nestedKey}`] = nested[nestedKey];
1411
+ }
1412
+ }
1413
+ else {
1414
+ output[key] = obj[key];
1415
+ }
1416
+ }
1417
+ return output;
1418
+ };
1419
+
1420
+ const HookFormContext = React.createContext(null);
1421
+ HookFormContext.displayName = 'HookFormContext';
1422
+ /**
1423
+ * This custom hook allows you to access the form context. useFormContext is intended to be used in deeply nested structures, where it would become inconvenient to pass the context as a prop. To be used with {@link FormProvider}.
1424
+ *
1425
+ * @remarks
1426
+ * [API](https://react-hook-form.com/docs/useformcontext) • [Demo](https://codesandbox.io/s/react-hook-form-v7-form-context-ytudi)
1427
+ *
1428
+ * @returns return all useForm methods
1429
+ *
1430
+ * @example
1431
+ * ```tsx
1432
+ * function App() {
1433
+ * const methods = useForm();
1434
+ * const onSubmit = data => console.log(data);
1435
+ *
1436
+ * return (
1437
+ * <FormProvider {...methods} >
1438
+ * <form onSubmit={methods.handleSubmit(onSubmit)}>
1439
+ * <NestedInput />
1440
+ * <input type="submit" />
1441
+ * </form>
1442
+ * </FormProvider>
1443
+ * );
1444
+ * }
1445
+ *
1446
+ * function NestedInput() {
1447
+ * const { register } = useFormContext(); // retrieve all hook methods
1448
+ * return <input {...register("test")} />;
1449
+ * }
1450
+ * ```
1451
+ */
1452
+ const useFormContext = () => React.useContext(HookFormContext);
1453
+ /**
1454
+ * A provider component that propagates the `useForm` methods to all children components via [React Context](https://react.dev/reference/react/useContext) API. To be used with {@link useFormContext}.
1455
+ *
1456
+ * @remarks
1457
+ * [API](https://react-hook-form.com/docs/useformcontext) • [Demo](https://codesandbox.io/s/react-hook-form-v7-form-context-ytudi)
1458
+ *
1459
+ * @param props - all useForm methods
1460
+ *
1461
+ * @example
1462
+ * ```tsx
1463
+ * function App() {
1464
+ * const methods = useForm();
1465
+ * const onSubmit = data => console.log(data);
1466
+ *
1467
+ * return (
1468
+ * <FormProvider {...methods} >
1469
+ * <form onSubmit={methods.handleSubmit(onSubmit)}>
1470
+ * <NestedInput />
1471
+ * <input type="submit" />
1472
+ * </form>
1473
+ * </FormProvider>
1474
+ * );
1475
+ * }
1476
+ *
1477
+ * function NestedInput() {
1478
+ * const { register } = useFormContext(); // retrieve all hook methods
1479
+ * return <input {...register("test")} />;
1480
+ * }
1481
+ * ```
1482
+ */
1483
+ const FormProvider = ({ children, watch, getValues, getFieldState, setError, clearErrors, setValue, setValues, trigger, formState, resetField, reset, resetDefaultValues, handleSubmit, unregister, control, register, setFocus, subscribe, }) => {
1484
+ const memoizedValue = React.useMemo(() => ({
1485
+ watch,
1486
+ getValues,
1487
+ getFieldState,
1488
+ setError,
1489
+ clearErrors,
1490
+ setValue,
1491
+ setValues,
1492
+ trigger,
1493
+ formState,
1494
+ resetField,
1495
+ reset,
1496
+ resetDefaultValues,
1497
+ handleSubmit,
1498
+ unregister,
1499
+ control,
1500
+ register,
1501
+ setFocus,
1502
+ subscribe,
1503
+ }), [
1504
+ clearErrors,
1505
+ control,
1506
+ formState,
1507
+ getFieldState,
1508
+ getValues,
1509
+ handleSubmit,
1510
+ register,
1511
+ reset,
1512
+ resetDefaultValues,
1513
+ resetField,
1514
+ setError,
1515
+ setFocus,
1516
+ setValue,
1517
+ setValues,
1518
+ subscribe,
1519
+ trigger,
1520
+ unregister,
1521
+ watch,
1522
+ ]);
1523
+ return (React.createElement(HookFormContext.Provider, { value: memoizedValue },
1524
+ React.createElement(HookFormControlContext.Provider, { value: memoizedValue.control }, children)));
1525
+ };
1526
+
1527
+ const POST_REQUEST = 'post';
1528
+ /**
1529
+ * Form component to manage submission.
1530
+ *
1531
+ * @param props - to setup submission detail. {@link FormProps}
1532
+ *
1533
+ * @returns form component or headless render prop.
1534
+ *
1535
+ * @example
1536
+ * ```tsx
1537
+ * function App() {
1538
+ * const { control, formState: { errors } } = useForm();
1539
+ *
1540
+ * return (
1541
+ * <Form action="/api" control={control}>
1542
+ * <input {...register("name")} />
1543
+ * <p>{errors?.root?.server && 'Server error'}</p>
1544
+ * <button>Submit</button>
1545
+ * </Form>
1546
+ * );
1547
+ * }
1548
+ * ```
1549
+ */
1550
+ function Form(props) {
1551
+ const methods = useFormContext();
1552
+ const [mounted, setMounted] = React.useState(false);
1553
+ const { control = methods.control, onSubmit, children, action, method = POST_REQUEST, headers, encType, onError, render, onSuccess, validateStatus, ...rest } = props;
1554
+ const submit = React.useCallback(async (event) => {
1555
+ let hasError = false;
1556
+ let type = '';
1557
+ await control.handleSubmit(async (data) => {
1558
+ const formData = new FormData();
1559
+ let formDataJson = '';
1560
+ try {
1561
+ formDataJson = JSON.stringify(data);
1562
+ }
1563
+ catch (_a) { }
1564
+ const flattenFormValues = flatten(data);
1565
+ for (const key in flattenFormValues) {
1566
+ formData.append(key, flattenFormValues[key]);
1567
+ }
1568
+ if (onSubmit) {
1569
+ await onSubmit({
1570
+ data,
1571
+ event,
1572
+ method,
1573
+ formData,
1574
+ formDataJson,
1575
+ });
1576
+ }
1577
+ if (action) {
1578
+ try {
1579
+ const shouldStringifySubmissionData = [
1580
+ headers && headers['Content-Type'],
1581
+ encType,
1582
+ ].some((value) => value && value.includes('json'));
1583
+ const response = await fetch(String(action), {
1584
+ method,
1585
+ headers: {
1586
+ ...headers,
1587
+ ...(encType && encType !== 'multipart/form-data'
1588
+ ? { 'Content-Type': encType }
1589
+ : {}),
1590
+ },
1591
+ body: shouldStringifySubmissionData ? formDataJson : formData,
1592
+ });
1593
+ if (response &&
1594
+ (validateStatus
1595
+ ? !validateStatus(response.status)
1596
+ : response.status < 200 || response.status >= 300)) {
1597
+ hasError = true;
1598
+ onError && onError({ response });
1599
+ type = String(response.status);
1794
1600
  }
1795
1601
  else {
1796
- fieldReference.refs.forEach((radioRef) => (radioRef.checked = radioRef.value === fieldValue));
1602
+ onSuccess && onSuccess({ response });
1797
1603
  }
1798
1604
  }
1799
- else if (isFileInput(fieldReference.ref)) {
1800
- fieldReference.ref.value = '';
1605
+ catch (error) {
1606
+ hasError = true;
1607
+ onError && onError({ error });
1801
1608
  }
1802
- else {
1803
- fieldReference.ref.value = fieldValue;
1804
- if (!fieldReference.ref.type) {
1805
- _subjects.state.next({
1806
- name,
1807
- values: cloneObject(_formValues),
1808
- });
1809
- }
1609
+ }
1610
+ })(event);
1611
+ if (hasError && control) {
1612
+ control._subjects.state.next({
1613
+ isSubmitSuccessful: false,
1614
+ });
1615
+ control.setError('root.server', {
1616
+ type,
1617
+ });
1618
+ }
1619
+ }, [
1620
+ control,
1621
+ onSubmit,
1622
+ method,
1623
+ action,
1624
+ headers,
1625
+ encType,
1626
+ validateStatus,
1627
+ onError,
1628
+ onSuccess,
1629
+ ]);
1630
+ React.useEffect(() => {
1631
+ setMounted(true);
1632
+ }, []);
1633
+ return render ? (React.createElement(React.Fragment, null, render({
1634
+ submit,
1635
+ }))) : (React.createElement("form", { noValidate: mounted, action: action, method: method, encType: encType, onSubmit: submit, ...rest }, children));
1636
+ }
1637
+
1638
+ const FormStateSubscribe = ({ control, disabled, exact, name, render, }) => render(useFormState({ control, name, disabled, exact }));
1639
+
1640
+ var createSubject = () => {
1641
+ let _observers = [];
1642
+ const next = (value) => {
1643
+ for (const observer of _observers) {
1644
+ observer.next && observer.next(value);
1645
+ }
1646
+ };
1647
+ const subscribe = (observer) => {
1648
+ _observers.push(observer);
1649
+ return {
1650
+ unsubscribe: () => {
1651
+ _observers = _observers.filter((o) => o !== observer);
1652
+ },
1653
+ };
1654
+ };
1655
+ const unsubscribe = () => {
1656
+ _observers = [];
1657
+ };
1658
+ return {
1659
+ get observers() {
1660
+ return _observers;
1661
+ },
1662
+ next,
1663
+ subscribe,
1664
+ unsubscribe,
1665
+ };
1666
+ };
1667
+
1668
+ function extractFormValues(fieldsState, formValues) {
1669
+ const values = {};
1670
+ for (const key in fieldsState) {
1671
+ if (fieldsState.hasOwnProperty(key)) {
1672
+ const fieldState = fieldsState[key];
1673
+ const fieldValue = formValues[key];
1674
+ if (fieldState && isObject(fieldState) && fieldValue) {
1675
+ const nestedFieldsState = extractFormValues(fieldState, fieldValue);
1676
+ if (isObject(nestedFieldsState)) {
1677
+ values[key] = nestedFieldsState;
1810
1678
  }
1811
1679
  }
1680
+ else if (fieldsState[key]) {
1681
+ values[key] = fieldValue;
1682
+ }
1812
1683
  }
1813
- (options.shouldDirty || options.shouldTouch) &&
1814
- updateTouchAndDirty(name, fieldValue, options.shouldTouch, options.shouldDirty, true);
1815
- options.shouldValidate && trigger(name);
1684
+ }
1685
+ return values;
1686
+ }
1687
+
1688
+ var isMultipleSelect = (element) => element.type === `select-multiple`;
1689
+
1690
+ var isRadioOrCheckbox = (ref) => isRadioInput(ref) || isCheckBoxInput(ref);
1691
+
1692
+ var live = (ref) => isHTMLElement(ref) && ref.isConnected;
1693
+
1694
+ var objectHasFunction = (data) => {
1695
+ for (const key in data) {
1696
+ if (isFunction(data[key])) {
1697
+ return true;
1698
+ }
1699
+ }
1700
+ return false;
1701
+ };
1702
+
1703
+ function isTraversable(value) {
1704
+ return Array.isArray(value) || (isObject(value) && !objectHasFunction(value));
1705
+ }
1706
+ function isRegisteredLeaf(fieldRef) {
1707
+ return !!(fieldRef && '_f' in fieldRef);
1708
+ }
1709
+ function isEmptyDirtyContainer(value) {
1710
+ return Array.isArray(value)
1711
+ ? !value.some((item) => !isUndefined(item))
1712
+ : !Object.keys(value).length;
1713
+ }
1714
+ function clearDirtyField(container, key) {
1715
+ if (Array.isArray(container)) {
1716
+ container[key] = undefined;
1717
+ }
1718
+ else {
1719
+ delete container[key];
1720
+ }
1721
+ }
1722
+ function markFieldsDirty(data, fields = {}, fieldRefs) {
1723
+ for (const key in data) {
1724
+ const value = data[key];
1725
+ const fieldRef = fieldRefs && fieldRefs[key];
1726
+ if (isTraversable(value) &&
1727
+ (!Array.isArray(value) || !isRegisteredLeaf(fieldRef))) {
1728
+ fields[key] = Array.isArray(value) ? [] : {};
1729
+ markFieldsDirty(value, fields[key], fieldRef);
1730
+ if (isEmptyDirtyContainer(fields[key])) {
1731
+ clearDirtyField(fields, key);
1732
+ }
1733
+ }
1734
+ else if (!isUndefined(value)) {
1735
+ fields[key] = true;
1736
+ }
1737
+ }
1738
+ return fields;
1739
+ }
1740
+ function getDirtyFields(data, formValues, dirtyFieldsFromValues, fieldRefs) {
1741
+ if (!dirtyFieldsFromValues) {
1742
+ dirtyFieldsFromValues = markFieldsDirty(formValues, {}, fieldRefs);
1743
+ }
1744
+ for (const key in data) {
1745
+ const value = data[key];
1746
+ const fieldRef = fieldRefs && fieldRefs[key];
1747
+ if (isTraversable(value) &&
1748
+ (!Array.isArray(value) || !isRegisteredLeaf(fieldRef))) {
1749
+ if (isUndefined(formValues) || isPrimitive(dirtyFieldsFromValues[key])) {
1750
+ dirtyFieldsFromValues[key] = markFieldsDirty(value, Array.isArray(value) ? [] : {}, fieldRef);
1751
+ }
1752
+ else {
1753
+ getDirtyFields(value, isNullOrUndefined(formValues) ? {} : formValues[key], dirtyFieldsFromValues[key], fieldRef);
1754
+ }
1755
+ if (isEmptyDirtyContainer(dirtyFieldsFromValues[key])) {
1756
+ clearDirtyField(dirtyFieldsFromValues, key);
1757
+ }
1758
+ }
1759
+ else if (deepEqual(value, formValues[key])) {
1760
+ clearDirtyField(dirtyFieldsFromValues, key);
1761
+ }
1762
+ else {
1763
+ dirtyFieldsFromValues[key] = true;
1764
+ }
1765
+ }
1766
+ return dirtyFieldsFromValues;
1767
+ }
1768
+
1769
+ var getFieldValueAs = (value, { valueAsNumber, valueAsDate, setValueAs }) => isUndefined(value)
1770
+ ? value
1771
+ : valueAsNumber
1772
+ ? value === ''
1773
+ ? NaN
1774
+ : value
1775
+ ? +value
1776
+ : value
1777
+ : valueAsDate && isString(value)
1778
+ ? new Date(value)
1779
+ : setValueAs
1780
+ ? setValueAs(value)
1781
+ : value;
1782
+
1783
+ function getFieldValue(_f) {
1784
+ const ref = _f.ref;
1785
+ if (isFileInput(ref)) {
1786
+ return ref.files;
1787
+ }
1788
+ if (isRadioInput(ref)) {
1789
+ return getRadioValue(_f.refs).value;
1790
+ }
1791
+ if (isMultipleSelect(ref)) {
1792
+ return [...ref.selectedOptions].map(({ value }) => value);
1793
+ }
1794
+ if (isCheckBoxInput(ref)) {
1795
+ return getCheckboxValue(_f.refs).value;
1796
+ }
1797
+ return getFieldValueAs(isUndefined(ref.value) ? _f.ref.value : ref.value, _f);
1798
+ }
1799
+
1800
+ var getResolverOptions = (fieldsNames, _fields, criteriaMode, shouldUseNativeValidation) => {
1801
+ const fields = {};
1802
+ for (const name of fieldsNames) {
1803
+ const field = get(_fields, name);
1804
+ field && set(fields, name, field._f);
1805
+ }
1806
+ return {
1807
+ criteriaMode,
1808
+ names: [...fieldsNames],
1809
+ fields,
1810
+ shouldUseNativeValidation,
1816
1811
  };
1817
- const setValues = (name, value, options) => {
1818
- for (const fieldKey in value) {
1819
- if (!value.hasOwnProperty(fieldKey)) {
1820
- return;
1812
+ };
1813
+
1814
+ var getRuleValue = (rule) => isUndefined(rule)
1815
+ ? rule
1816
+ : isRegex(rule)
1817
+ ? rule.source
1818
+ : isObject(rule)
1819
+ ? isRegex(rule.value)
1820
+ ? rule.value.source
1821
+ : rule.value
1822
+ : rule;
1823
+
1824
+ const ASYNC_FUNCTION = 'AsyncFunction';
1825
+ var hasPromiseValidation = (fieldReference) => {
1826
+ if (!fieldReference || !fieldReference.validate)
1827
+ return false;
1828
+ if (isFunction(fieldReference.validate)) {
1829
+ return fieldReference.validate.constructor.name === ASYNC_FUNCTION;
1830
+ }
1831
+ if (isObject(fieldReference.validate)) {
1832
+ for (const key in fieldReference.validate) {
1833
+ if (fieldReference.validate[key].constructor
1834
+ .name === ASYNC_FUNCTION) {
1835
+ return true;
1821
1836
  }
1822
- const fieldValue = value[fieldKey];
1823
- const fieldName = name + '.' + fieldKey;
1824
- const field = get(_fields, fieldName);
1825
- (_names.array.has(name) ||
1826
- isObject(fieldValue) ||
1827
- (field && !field._f)) &&
1828
- !isDateObject(fieldValue)
1829
- ? setValues(fieldName, fieldValue, options)
1830
- : setFieldValue(fieldName, fieldValue, options);
1837
+ }
1838
+ }
1839
+ return false;
1840
+ };
1841
+
1842
+ var hasValidation = (options) => options.mount &&
1843
+ (options.required ||
1844
+ options.min ||
1845
+ options.max ||
1846
+ options.maxLength ||
1847
+ options.minLength ||
1848
+ options.pattern ||
1849
+ options.validate);
1850
+
1851
+ function schemaErrorLookup(errors, _fields, name) {
1852
+ const error = get(errors, name);
1853
+ if (error || isKey(name)) {
1854
+ return {
1855
+ error,
1856
+ name,
1857
+ };
1858
+ }
1859
+ const names = name.split('.');
1860
+ while (names.length) {
1861
+ const fieldName = names.join('.');
1862
+ const field = get(_fields, fieldName);
1863
+ const foundError = get(errors, fieldName);
1864
+ if (field && !Array.isArray(field) && name !== fieldName) {
1865
+ return { name };
1866
+ }
1867
+ if (foundError && foundError.type) {
1868
+ return {
1869
+ name: fieldName,
1870
+ error: foundError,
1871
+ };
1872
+ }
1873
+ if (foundError && foundError.root && foundError.root.type) {
1874
+ return {
1875
+ name: `${fieldName}.root`,
1876
+ error: foundError.root,
1877
+ };
1878
+ }
1879
+ names.pop();
1880
+ }
1881
+ return {
1882
+ name,
1883
+ };
1884
+ }
1885
+
1886
+ var shouldRenderFormState = (formStateData, _proxyFormState, updateFormState, isRoot) => {
1887
+ updateFormState(formStateData);
1888
+ const { name, ...formState } = formStateData;
1889
+ const keys = Object.keys(formState);
1890
+ return (!keys.length ||
1891
+ (isRoot && keys.length >= Object.keys(_proxyFormState).length) ||
1892
+ keys.find((key) => _proxyFormState[key] ===
1893
+ (!isRoot || VALIDATION_MODE.all)));
1894
+ };
1895
+
1896
+ var shouldSubscribeByName = (name, signalName, exact) => !name ||
1897
+ !signalName ||
1898
+ name === signalName ||
1899
+ convertToArrayPayload(name).some((currentName) => currentName &&
1900
+ (exact
1901
+ ? currentName === signalName || currentName.startsWith(signalName + '.')
1902
+ : currentName.startsWith(signalName) ||
1903
+ signalName.startsWith(currentName)));
1904
+
1905
+ var skipValidation = (isBlurEvent, isTouched, isSubmitted, reValidateMode, mode) => {
1906
+ if (mode.isOnAll) {
1907
+ return false;
1908
+ }
1909
+ else if (!isSubmitted && mode.isOnTouch) {
1910
+ return !(isTouched || isBlurEvent);
1911
+ }
1912
+ else if (isSubmitted ? reValidateMode.isOnBlur : mode.isOnBlur) {
1913
+ return !isBlurEvent;
1914
+ }
1915
+ else if (isSubmitted ? reValidateMode.isOnChange : mode.isOnChange) {
1916
+ return isBlurEvent;
1917
+ }
1918
+ return true;
1919
+ };
1920
+
1921
+ var unsetEmptyArray = (ref, name) => !compact(get(ref, name)).length && unset(ref, name);
1922
+
1923
+ const defaultOptions = {
1924
+ mode: VALIDATION_MODE.onSubmit,
1925
+ reValidateMode: VALIDATION_MODE.onChange,
1926
+ shouldFocusError: true,
1927
+ };
1928
+ const FORM_ERROR_TYPE = 'form';
1929
+ const updateDirtyFields = (dirtyFields, nextDirtyFields) => {
1930
+ for (const key in dirtyFields) {
1931
+ if (!(key in nextDirtyFields)) {
1932
+ delete dirtyFields[key];
1933
+ }
1934
+ }
1935
+ Object.assign(dirtyFields, nextDirtyFields);
1936
+ };
1937
+ const DEFAULT_FORM_STATE = {
1938
+ submitCount: 0,
1939
+ isDirty: false,
1940
+ isReady: false,
1941
+ isValidating: false,
1942
+ isSubmitted: false,
1943
+ isSubmitting: false,
1944
+ isSubmitSuccessful: false,
1945
+ isValid: false,
1946
+ touchedFields: {},
1947
+ dirtyFields: {},
1948
+ validatingFields: {},
1949
+ };
1950
+ function createFormControl(props = {}) {
1951
+ let _options = {
1952
+ ...defaultOptions,
1953
+ ...props,
1954
+ };
1955
+ let _formState = {
1956
+ ...cloneObject(DEFAULT_FORM_STATE),
1957
+ isLoading: isFunction(_options.defaultValues),
1958
+ errors: _options.errors || {},
1959
+ disabled: _options.disabled || false,
1960
+ };
1961
+ let _fields = {};
1962
+ let _defaultValues = isObject(_options.defaultValues) || isObject(_options.values)
1963
+ ? cloneObject(_options.defaultValues || _options.values) || {}
1964
+ : {};
1965
+ let _formValues = _options.shouldUnregister
1966
+ ? {}
1967
+ : cloneObject(_defaultValues);
1968
+ let _state = {
1969
+ action: false,
1970
+ mount: false,
1971
+ watch: false,
1972
+ keepIsValid: false,
1973
+ };
1974
+ let _names = {
1975
+ mount: new Set(),
1976
+ disabled: new Set(),
1977
+ unMount: new Set(),
1978
+ array: new Set(),
1979
+ watch: new Set(),
1980
+ registerName: new Set(),
1981
+ };
1982
+ const delayErrorCallbacks = {};
1983
+ const timers = {};
1984
+ let _valuesSubscriberCount = 0;
1985
+ let _validationModeBeforeSubmit = getValidationModes(_options.mode);
1986
+ let _validationModeAfterSubmit = getValidationModes(_options.reValidateMode);
1987
+ const defaultProxyFormState = {
1988
+ isDirty: false,
1989
+ dirtyFields: false,
1990
+ validatingFields: false,
1991
+ touchedFields: false,
1992
+ isValidating: false,
1993
+ isValid: false,
1994
+ errors: false,
1995
+ };
1996
+ const _proxyFormState = {
1997
+ ...defaultProxyFormState,
1998
+ };
1999
+ let _proxySubscribeFormState = {
2000
+ ..._proxyFormState,
2001
+ };
2002
+ const _subjects = {
2003
+ array: createSubject(),
2004
+ state: createSubject(),
2005
+ };
2006
+ let _setValidCallId = 0;
2007
+ const shouldDisplayAllAssociatedErrors = _options.criteriaMode === VALIDATION_MODE.all;
2008
+ const debounce = (name, callback) => (wait) => {
2009
+ clearTimeout(timers[name]);
2010
+ timers[name] = setTimeout(callback, wait);
2011
+ };
2012
+ const _setValid = async (shouldUpdateValid) => {
2013
+ if (_state.keepIsValid) {
2014
+ return;
2015
+ }
2016
+ if (!_options.disabled &&
2017
+ (_proxyFormState.isValid ||
2018
+ _proxySubscribeFormState.isValid ||
2019
+ shouldUpdateValid)) {
2020
+ const callId = ++_setValidCallId;
2021
+ let isValid;
2022
+ if (_options.resolver) {
2023
+ isValid = isEmptyObject((await _runSchema()).errors);
2024
+ callId === _setValidCallId && _updateIsValidating();
2025
+ }
2026
+ else {
2027
+ isValid = await executeBuiltInValidation({
2028
+ fields: _fields,
2029
+ onlyCheckValid: true,
2030
+ eventType: EVENTS.VALID,
2031
+ });
2032
+ }
2033
+ if (callId === _setValidCallId && isValid !== _formState.isValid) {
2034
+ _subjects.state.next({
2035
+ isValid,
2036
+ });
2037
+ }
2038
+ }
2039
+ };
2040
+ const _updateIsValidating = (names, isValidating) => {
2041
+ if (!_options.disabled &&
2042
+ (_proxyFormState.isValidating ||
2043
+ _proxyFormState.validatingFields ||
2044
+ _proxySubscribeFormState.isValidating ||
2045
+ _proxySubscribeFormState.validatingFields)) {
2046
+ (names || Array.from(_names.mount)).forEach((name) => {
2047
+ if (name) {
2048
+ isValidating
2049
+ ? set(_formState.validatingFields, name, isValidating)
2050
+ : unset(_formState.validatingFields, name);
2051
+ }
2052
+ });
2053
+ _subjects.state.next({
2054
+ validatingFields: _formState.validatingFields,
2055
+ isValidating: !isEmptyObject(_formState.validatingFields),
2056
+ });
1831
2057
  }
1832
2058
  };
1833
- const setValue = (name, value, options = {}) => {
1834
- const field = get(_fields, name);
1835
- const isFieldArray = _names.array.has(name);
1836
- const cloneValue = cloneObject(value);
1837
- set(_formValues, name, cloneValue);
1838
- if (isFieldArray) {
1839
- _subjects.array.next({
1840
- name,
1841
- values: cloneObject(_formValues),
1842
- });
1843
- if ((_proxyFormState.isDirty ||
1844
- _proxyFormState.dirtyFields ||
1845
- _proxySubscribeFormState.isDirty ||
1846
- _proxySubscribeFormState.dirtyFields) &&
1847
- options.shouldDirty) {
1848
- _subjects.state.next({
1849
- name,
1850
- dirtyFields: getDirtyFields(_defaultValues, _formValues),
1851
- isDirty: _getDirty(name, cloneValue),
1852
- });
2059
+ const _updateDirtyFields = () => {
2060
+ _formState.dirtyFields = getDirtyFields(_defaultValues, _formValues, undefined, _fields);
2061
+ };
2062
+ const _setFieldArray = (name, values = [], method, args, shouldSetValues = true, shouldUpdateFieldsAndState = true) => {
2063
+ if (args && method && !_options.disabled) {
2064
+ _state.action = true;
2065
+ if (shouldUpdateFieldsAndState && Array.isArray(get(_fields, name))) {
2066
+ const fieldValues = method(get(_fields, name), args.argA, args.argB);
2067
+ shouldSetValues && set(_fields, name, fieldValues);
2068
+ }
2069
+ if (shouldUpdateFieldsAndState &&
2070
+ Array.isArray(get(_formState.errors, name))) {
2071
+ const errors = method(get(_formState.errors, name), args.argA, args.argB);
2072
+ shouldSetValues && set(_formState.errors, name, errors);
2073
+ unsetEmptyArray(_formState.errors, name);
2074
+ }
2075
+ if ((_proxyFormState.touchedFields ||
2076
+ _proxySubscribeFormState.touchedFields) &&
2077
+ shouldUpdateFieldsAndState &&
2078
+ Array.isArray(get(_formState.touchedFields, name))) {
2079
+ const touchedFields = method(get(_formState.touchedFields, name), args.argA, args.argB);
2080
+ shouldSetValues && set(_formState.touchedFields, name, touchedFields);
2081
+ }
2082
+ if (_proxyFormState.dirtyFields || _proxySubscribeFormState.dirtyFields) {
2083
+ _updateDirtyFields();
1853
2084
  }
1854
- }
1855
- else {
1856
- field && !field._f && !isNullOrUndefined(cloneValue)
1857
- ? setValues(name, cloneValue, options)
1858
- : setFieldValue(name, cloneValue, options);
1859
- }
1860
- if (isWatched(name, _names)) {
1861
2085
  _subjects.state.next({
1862
- ..._formState,
1863
2086
  name,
1864
- values: cloneObject(_formValues),
2087
+ isDirty: _getDirty(name, values),
2088
+ dirtyFields: _formState.dirtyFields,
2089
+ errors: _formState.errors,
2090
+ isValid: _formState.isValid,
1865
2091
  });
1866
2092
  }
1867
2093
  else {
1868
- _subjects.state.next({
1869
- name: _state.mount ? name : undefined,
1870
- values: cloneObject(_formValues),
1871
- });
2094
+ set(_formValues, name, values);
1872
2095
  }
1873
2096
  };
1874
- const onChange = async (event) => {
1875
- _state.mount = true;
1876
- const target = event.target;
1877
- let name = target.name;
1878
- let isFieldValueUpdated = true;
2097
+ const updateErrors = (name, error) => {
2098
+ set(_formState.errors, name, error);
2099
+ _formState.errors = { ..._formState.errors };
2100
+ _subjects.state.next({
2101
+ errors: _formState.errors,
2102
+ });
2103
+ };
2104
+ const _setErrors = (errors) => {
2105
+ _formState.errors = errors;
2106
+ _subjects.state.next({
2107
+ errors: _formState.errors,
2108
+ isValid: false,
2109
+ });
2110
+ };
2111
+ const hasExplicitNullIntermediate = (name) => {
2112
+ const segments = isKey(name) ? [name] : stringToPath(name);
2113
+ let formValues = _formValues;
2114
+ let defaultValues = _defaultValues;
2115
+ for (let i = 0; i < segments.length - 1; i++) {
2116
+ const key = segments[i];
2117
+ formValues = isNullOrUndefined(formValues) ? formValues : formValues[key];
2118
+ defaultValues = isNullOrUndefined(defaultValues)
2119
+ ? defaultValues
2120
+ : defaultValues[key];
2121
+ if (formValues === null && defaultValues !== null) {
2122
+ return true;
2123
+ }
2124
+ }
2125
+ return false;
2126
+ };
2127
+ const updateValidAndValue = (name, shouldSkipSetValueAs, value, ref) => {
1879
2128
  const field = get(_fields, name);
1880
- const _updateIsFieldValueUpdated = (fieldValue) => {
1881
- isFieldValueUpdated =
1882
- Number.isNaN(fieldValue) ||
1883
- (isDateObject(fieldValue) && isNaN(fieldValue.getTime())) ||
1884
- deepEqual(fieldValue, get(_formValues, name, fieldValue));
1885
- };
1886
- const validationModeBeforeSubmit = getValidationModes(_options.mode);
1887
- const validationModeAfterSubmit = getValidationModes(_options.reValidateMode);
1888
2129
  if (field) {
1889
- let error;
1890
- let isValid;
1891
- const fieldValue = target.type
1892
- ? getFieldValue(field._f)
1893
- : getEventValue(event);
1894
- const isBlurEvent = event.type === EVENTS.BLUR || event.type === EVENTS.FOCUS_OUT;
1895
- const shouldSkipValidation = (!hasValidation(field._f) &&
1896
- !props.validate &&
1897
- !_options.resolver &&
1898
- !get(_formState.errors, name) &&
1899
- !field._f.deps) ||
1900
- skipValidation(isBlurEvent, get(_formState.touchedFields, name), _formState.isSubmitted, validationModeAfterSubmit, validationModeBeforeSubmit);
1901
- const watched = isWatched(name, _names, isBlurEvent);
1902
- set(_formValues, name, fieldValue);
1903
- if (isBlurEvent) {
1904
- if (!target || !target.readOnly) {
1905
- field._f.onBlur && field._f.onBlur(event);
1906
- delayErrorCallback && delayErrorCallback(0);
1907
- }
1908
- }
1909
- else if (field._f.onChange) {
1910
- field._f.onChange(event);
2130
+ if (hasExplicitNullIntermediate(name)) {
2131
+ return;
1911
2132
  }
1912
- const fieldState = updateTouchAndDirty(name, fieldValue, isBlurEvent);
1913
- const shouldRender = !isEmptyObject(fieldState) || watched;
1914
- !isBlurEvent &&
1915
- _subjects.state.next({
1916
- name,
1917
- type: event.type,
1918
- values: cloneObject(_formValues),
1919
- });
1920
- if (shouldSkipValidation) {
1921
- if (_proxyFormState.isValid || _proxySubscribeFormState.isValid) {
1922
- if (_options.mode === 'onBlur') {
1923
- if (isBlurEvent) {
1924
- _setValid();
1925
- }
1926
- }
1927
- else if (!isBlurEvent) {
1928
- _setValid();
2133
+ const wasUnsetInFormValues = isUndefined(get(_formValues, name));
2134
+ const defaultValue = get(_formValues, name, isUndefined(value) ? get(_defaultValues, name) : value);
2135
+ isUndefined(defaultValue) ||
2136
+ (ref && ref.defaultChecked) ||
2137
+ shouldSkipSetValueAs
2138
+ ? set(_formValues, name, shouldSkipSetValueAs ? defaultValue : getFieldValue(field._f))
2139
+ : setFieldValue(name, defaultValue);
2140
+ if (_state.mount && !_state.action) {
2141
+ _setValid();
2142
+ if (wasUnsetInFormValues &&
2143
+ _formState.isDirty &&
2144
+ (_proxyFormState.isDirty || _proxySubscribeFormState.isDirty)) {
2145
+ const isDirty = _getDirty();
2146
+ if (!isDirty) {
2147
+ _formState.isDirty = false;
2148
+ _subjects.state.next({ ..._formState });
1929
2149
  }
1930
2150
  }
1931
- return (shouldRender &&
1932
- _subjects.state.next({ name, ...(watched ? {} : fieldState) }));
1933
- }
1934
- if (!_options.resolver && props.validate) {
1935
- await validateForm({
1936
- name: name,
1937
- eventType: event.type,
1938
- });
1939
- }
1940
- !isBlurEvent && watched && _subjects.state.next({ ..._formState });
1941
- if (_options.resolver) {
1942
- const { errors } = await _runSchema([name]);
1943
- _updateIsValidating([name]);
1944
- _updateIsFieldValueUpdated(fieldValue);
1945
- if (isFieldValueUpdated) {
1946
- const previousErrorLookupResult = schemaErrorLookup(_formState.errors, _fields, name);
1947
- const errorLookupResult = schemaErrorLookup(errors, _fields, previousErrorLookupResult.name || name);
1948
- error = errorLookupResult.error;
1949
- name = errorLookupResult.name;
1950
- isValid = isEmptyObject(errors);
2151
+ if (props.shouldUnregister &&
2152
+ wasUnsetInFormValues &&
2153
+ !isUndefined(get(_formValues, name)) &&
2154
+ isWatched(name, _names)) {
2155
+ _state.watch = true;
1951
2156
  }
1952
2157
  }
1953
- else {
1954
- _updateIsValidating([name], true);
1955
- error = (await validateField(field, _names.disabled, _formValues, shouldDisplayAllAssociatedErrors, _options.shouldUseNativeValidation))[name];
1956
- _updateIsValidating([name]);
1957
- _updateIsFieldValueUpdated(fieldValue);
1958
- if (isFieldValueUpdated) {
1959
- if (error) {
1960
- isValid = false;
1961
- }
1962
- else if (_proxyFormState.isValid ||
1963
- _proxySubscribeFormState.isValid) {
1964
- isValid = await executeBuiltInValidation({
1965
- fields: _fields,
1966
- onlyCheckValid: true,
1967
- name: name,
1968
- eventType: event.type,
1969
- });
1970
- }
2158
+ }
2159
+ };
2160
+ const updateTouchAndDirty = (name, fieldValue, isBlurEvent, shouldDirty, shouldRender) => {
2161
+ let shouldUpdateField = false;
2162
+ let isPreviousDirty = false;
2163
+ const output = {
2164
+ name,
2165
+ };
2166
+ // an explicit programmatic update (e.g. setValue with shouldDirty: true)
2167
+ // opts into dirty tracking even when the form is disabled
2168
+ if (!_options.disabled || shouldDirty === true) {
2169
+ if (!isBlurEvent || shouldDirty) {
2170
+ const isCurrentFieldPristine = deepEqual(get(_defaultValues, name), fieldValue);
2171
+ if (_proxyFormState.isDirty || _proxySubscribeFormState.isDirty) {
2172
+ isPreviousDirty = _formState.isDirty;
2173
+ _formState.isDirty = output.isDirty =
2174
+ !isCurrentFieldPristine || _getDirty();
2175
+ shouldUpdateField = isPreviousDirty !== output.isDirty;
2176
+ }
2177
+ isPreviousDirty = !!get(_formState.dirtyFields, name);
2178
+ if (isCurrentFieldPristine !== _formState.isDirty) {
2179
+ updateDirtyFields(_formState.dirtyFields, getDirtyFields(_defaultValues, _formValues, undefined, _fields));
1971
2180
  }
2181
+ else {
2182
+ isCurrentFieldPristine
2183
+ ? unset(_formState.dirtyFields, name)
2184
+ : set(_formState.dirtyFields, name, true);
2185
+ }
2186
+ output.dirtyFields = _formState.dirtyFields;
2187
+ shouldUpdateField =
2188
+ shouldUpdateField ||
2189
+ ((_proxyFormState.dirtyFields ||
2190
+ _proxySubscribeFormState.dirtyFields) &&
2191
+ isPreviousDirty !== !isCurrentFieldPristine);
1972
2192
  }
1973
- if (isFieldValueUpdated) {
1974
- field._f.deps &&
1975
- (!Array.isArray(field._f.deps) || field._f.deps.length > 0) &&
1976
- trigger(field._f.deps);
1977
- shouldRenderByError(name, isValid, error, fieldState);
2193
+ if (isBlurEvent) {
2194
+ const isPreviousFieldTouched = get(_formState.touchedFields, name);
2195
+ if (!isPreviousFieldTouched) {
2196
+ set(_formState.touchedFields, name, isBlurEvent);
2197
+ output.touchedFields = _formState.touchedFields;
2198
+ shouldUpdateField =
2199
+ shouldUpdateField ||
2200
+ ((_proxyFormState.touchedFields ||
2201
+ _proxySubscribeFormState.touchedFields) &&
2202
+ isPreviousFieldTouched !== isBlurEvent);
2203
+ }
1978
2204
  }
2205
+ shouldUpdateField && shouldRender && _subjects.state.next(output);
1979
2206
  }
2207
+ return shouldUpdateField ? output : {};
1980
2208
  };
1981
- const _focusInput = (ref, key) => {
1982
- if (get(_formState.errors, key) && ref.focus) {
1983
- ref.focus();
1984
- return 1;
1985
- }
1986
- return;
1987
- };
1988
- const trigger = async (name, options = {}) => {
1989
- let isValid;
1990
- let validationResult;
1991
- const fieldNames = convertToArrayPayload(name);
1992
- if (_options.resolver) {
1993
- const errors = await executeSchemaAndUpdateState(isUndefined(name) ? name : fieldNames);
1994
- isValid = isEmptyObject(errors);
1995
- validationResult = name
1996
- ? !fieldNames.some((name) => get(errors, name))
1997
- : isValid;
1998
- }
1999
- else if (name) {
2000
- validationResult = (await Promise.all(fieldNames.map(async (fieldName) => {
2001
- const field = get(_fields, fieldName);
2002
- return await executeBuiltInValidation({
2003
- fields: field && field._f ? { [fieldName]: field } : field,
2004
- eventType: EVENTS.TRIGGER,
2005
- });
2006
- }))).every(Boolean);
2007
- !(!validationResult && !_formState.isValid) && _setValid();
2209
+ const shouldRenderByError = (name, isValid, error, fieldState) => {
2210
+ const previousFieldError = get(_formState.errors, name);
2211
+ const shouldUpdateValid = (_proxyFormState.isValid || _proxySubscribeFormState.isValid) &&
2212
+ isBoolean(isValid) &&
2213
+ _formState.isValid !== isValid;
2214
+ if (_options.delayError && error) {
2215
+ delayErrorCallbacks[name] = debounce(name, () => updateErrors(name, error));
2216
+ delayErrorCallbacks[name](_options.delayError);
2008
2217
  }
2009
2218
  else {
2010
- validationResult = isValid = await executeBuiltInValidation({
2011
- fields: _fields,
2012
- name,
2013
- eventType: EVENTS.TRIGGER,
2014
- });
2219
+ clearTimeout(timers[name]);
2220
+ delete delayErrorCallbacks[name];
2221
+ error
2222
+ ? set(_formState.errors, name, error)
2223
+ : unset(_formState.errors, name);
2224
+ _formState.errors = { ..._formState.errors };
2015
2225
  }
2016
- _subjects.state.next({
2017
- ...(!isString(name) ||
2018
- ((_proxyFormState.isValid || _proxySubscribeFormState.isValid) &&
2019
- isValid !== _formState.isValid)
2020
- ? {}
2021
- : { name }),
2022
- ...(_options.resolver || !name ? { isValid } : {}),
2023
- errors: _formState.errors,
2024
- });
2025
- options.shouldFocus &&
2026
- !validationResult &&
2027
- iterateFieldsByAction(_fields, _focusInput, name ? fieldNames : _names.mount);
2028
- return validationResult;
2029
- };
2030
- const getValues = (fieldNames, config) => {
2031
- let values = {
2032
- ...(_state.mount ? _formValues : _defaultValues),
2033
- };
2034
- if (config) {
2035
- values = extractFormValues(config.dirtyFields ? _formState.dirtyFields : _formState.touchedFields, values);
2226
+ if ((error ? !deepEqual(previousFieldError, error) : previousFieldError) ||
2227
+ !isEmptyObject(fieldState) ||
2228
+ shouldUpdateValid) {
2229
+ const updatedFormState = {
2230
+ ...fieldState,
2231
+ ...(shouldUpdateValid && isBoolean(isValid) ? { isValid } : {}),
2232
+ errors: _formState.errors,
2233
+ name,
2234
+ };
2235
+ _formState = {
2236
+ ..._formState,
2237
+ ...updatedFormState,
2238
+ };
2239
+ _subjects.state.next(updatedFormState);
2036
2240
  }
2037
- return isUndefined(fieldNames)
2038
- ? values
2039
- : isString(fieldNames)
2040
- ? get(values, fieldNames)
2041
- : fieldNames.map((name) => get(values, name));
2042
2241
  };
2043
- const getFieldState = (name, formState) => ({
2044
- invalid: !!get((formState || _formState).errors, name),
2045
- isDirty: !!get((formState || _formState).dirtyFields, name),
2046
- error: get((formState || _formState).errors, name),
2047
- isValidating: !!get(_formState.validatingFields, name),
2048
- isTouched: !!get((formState || _formState).touchedFields, name),
2049
- });
2050
- const clearErrors = (name) => {
2051
- const names = name ? convertToArrayPayload(name) : undefined;
2052
- names === null || names === void 0 ? void 0 : names.forEach((inputName) => unset(_formState.errors, inputName));
2242
+ const _runSchema = async (name) => {
2243
+ _updateIsValidating(name, true);
2244
+ return await _options.resolver(_formValues, _options.context, getResolverOptions(name || _names.mount, _fields, _options.criteriaMode, _options.shouldUseNativeValidation));
2245
+ };
2246
+ const executeSchemaAndUpdateState = async (names) => {
2247
+ const { errors } = await _runSchema(names);
2248
+ _updateIsValidating(names);
2053
2249
  if (names) {
2054
- // Emit for each cleared field with the field name so that
2055
- // shouldSubscribeByName can filter and avoid broad re-renders
2056
- names.forEach((inputName) => {
2057
- _subjects.state.next({
2058
- name: inputName,
2059
- errors: _formState.errors,
2060
- });
2061
- });
2250
+ for (const name of names) {
2251
+ const error = get(errors, name);
2252
+ error
2253
+ ? _names.array.has(name) &&
2254
+ isObject(error) &&
2255
+ !Object.keys(error).some((key) => !Number.isNaN(Number(key)))
2256
+ ? updateFieldArrayRootError(_formState.errors, { [name]: error }, name)
2257
+ : set(_formState.errors, name, error)
2258
+ : unset(_formState.errors, name);
2259
+ }
2260
+ _formState.errors = { ..._formState.errors };
2062
2261
  }
2063
2262
  else {
2064
- // Clear all errors - emit without name to notify all subscribers
2065
- _subjects.state.next({
2066
- errors: {},
2067
- });
2263
+ _formState.errors = errors;
2068
2264
  }
2265
+ return errors;
2069
2266
  };
2070
- const setError = (name, error, options) => {
2071
- const ref = (get(_fields, name, { _f: {} })._f || {}).ref;
2072
- const currentError = get(_formState.errors, name) || {};
2073
- // Don't override existing error messages elsewhere in the object tree.
2074
- const { ref: currentRef, message, type, ...restOfErrorTree } = currentError;
2075
- set(_formState.errors, name, {
2076
- ...restOfErrorTree,
2077
- ...error,
2078
- ref,
2079
- });
2080
- _subjects.state.next({
2081
- name,
2082
- errors: _formState.errors,
2083
- isValid: false,
2084
- });
2085
- options && options.shouldFocus && ref && ref.focus && ref.focus();
2086
- };
2087
- const watch = (name, defaultValue) => isFunction(name)
2088
- ? _subjects.state.subscribe({
2089
- next: (payload) => 'values' in payload &&
2090
- name(_getWatch(undefined, defaultValue), payload),
2091
- })
2092
- : _getWatch(name, defaultValue, true);
2093
- const _subscribe = (props) => _subjects.state.subscribe({
2094
- next: (formState) => {
2095
- if (shouldSubscribeByName(props.name, formState.name, props.exact) &&
2096
- shouldRenderFormState(formState, props.formState || _proxyFormState, _setFormState, props.reRenderRoot)) {
2097
- props.callback({
2098
- values: { ..._formValues },
2099
- ..._formState,
2100
- ...formState,
2101
- defaultValues: _defaultValues,
2267
+ const validateForm = async ({ name, eventType, }) => {
2268
+ if (props.validate) {
2269
+ const result = await props.validate({
2270
+ formValues: _formValues,
2271
+ formState: _formState,
2272
+ name,
2273
+ eventType,
2274
+ });
2275
+ if (isObject(result)) {
2276
+ for (const key in result) {
2277
+ const error = result[key];
2278
+ if (error) {
2279
+ setError(`${FORM_ERROR_TYPE}.${key}`, {
2280
+ message: isString(error.message) ? error.message : '',
2281
+ type: error.type || INPUT_VALIDATION_RULES.validate,
2282
+ });
2283
+ }
2284
+ }
2285
+ }
2286
+ else if (isString(result) || !result) {
2287
+ setError(FORM_ERROR_TYPE, {
2288
+ message: result || '',
2289
+ type: INPUT_VALIDATION_RULES.validate,
2102
2290
  });
2103
2291
  }
2104
- },
2105
- }).unsubscribe;
2106
- const subscribe = (props) => {
2107
- _state.mount = true;
2108
- _proxySubscribeFormState = {
2109
- ..._proxySubscribeFormState,
2110
- ...props.formState,
2111
- };
2112
- return _subscribe({
2113
- ...props,
2114
- formState: {
2115
- ...defaultProxyFormState,
2116
- ...props.formState,
2117
- },
2118
- });
2119
- };
2120
- const unregister = (name, options = {}) => {
2121
- for (const fieldName of name ? convertToArrayPayload(name) : _names.mount) {
2122
- _names.mount.delete(fieldName);
2123
- _names.array.delete(fieldName);
2124
- if (!options.keepValue) {
2125
- unset(_fields, fieldName);
2126
- unset(_formValues, fieldName);
2292
+ else {
2293
+ clearErrors(FORM_ERROR_TYPE);
2127
2294
  }
2128
- !options.keepError && unset(_formState.errors, fieldName);
2129
- !options.keepDirty && unset(_formState.dirtyFields, fieldName);
2130
- !options.keepTouched && unset(_formState.touchedFields, fieldName);
2131
- !options.keepIsValidating &&
2132
- unset(_formState.validatingFields, fieldName);
2133
- !_options.shouldUnregister &&
2134
- !options.keepDefaultValue &&
2135
- unset(_defaultValues, fieldName);
2136
- }
2137
- _subjects.state.next({
2138
- values: cloneObject(_formValues),
2139
- });
2140
- _subjects.state.next({
2141
- ..._formState,
2142
- ...(!options.keepDirty ? {} : { isDirty: _getDirty() }),
2143
- });
2144
- !options.keepIsValid && _setValid();
2145
- };
2146
- const _setDisabledField = ({ disabled, name, }) => {
2147
- if ((isBoolean(disabled) && _state.mount) ||
2148
- !!disabled ||
2149
- _names.disabled.has(name)) {
2150
- const wasDisabled = _names.disabled.has(name);
2151
- const isDisabled = !!disabled;
2152
- const disabledStateChanged = wasDisabled !== isDisabled;
2153
- disabled ? _names.disabled.add(name) : _names.disabled.delete(name);
2154
- disabledStateChanged && _state.mount && !_state.action && _setValid();
2295
+ return result;
2155
2296
  }
2297
+ return true;
2156
2298
  };
2157
- const register = (name, options = {}) => {
2158
- let field = get(_fields, name);
2159
- const disabledIsDefined = isBoolean(options.disabled) || isBoolean(_options.disabled);
2160
- set(_fields, name, {
2161
- ...(field || {}),
2162
- _f: {
2163
- ...(field && field._f ? field._f : { ref: { name } }),
2164
- name,
2165
- mount: true,
2166
- ...options,
2167
- },
2168
- });
2169
- _names.mount.add(name);
2170
- if (field) {
2171
- _setDisabledField({
2172
- disabled: isBoolean(options.disabled)
2173
- ? options.disabled
2174
- : _options.disabled,
2299
+ const executeBuiltInValidation = async ({ fields, onlyCheckValid, name, eventType, context = {
2300
+ valid: true,
2301
+ runRootValidation: false,
2302
+ }, }) => {
2303
+ if (props.validate) {
2304
+ context.runRootValidation = true;
2305
+ const result = await validateForm({
2175
2306
  name,
2307
+ eventType,
2176
2308
  });
2309
+ if (!result) {
2310
+ context.valid = false;
2311
+ if (onlyCheckValid) {
2312
+ return context.valid;
2313
+ }
2314
+ }
2177
2315
  }
2178
- else {
2179
- updateValidAndValue(name, true, options.value);
2316
+ for (const name in fields) {
2317
+ const field = fields[name];
2318
+ if (field) {
2319
+ const { _f, ...fieldValue } = field;
2320
+ if (_f) {
2321
+ const isFieldArrayRoot = _names.array.has(_f.name);
2322
+ const isPromiseFunction = field._f && hasPromiseValidation(field._f);
2323
+ const shouldTrackIsValidatingState = _proxyFormState.validatingFields ||
2324
+ _proxyFormState.isValidating ||
2325
+ _proxySubscribeFormState.validatingFields ||
2326
+ _proxySubscribeFormState.isValidating;
2327
+ if (isPromiseFunction && shouldTrackIsValidatingState) {
2328
+ _updateIsValidating([_f.name], true);
2329
+ }
2330
+ const fieldError = await validateField(field, _names.disabled, _formValues, shouldDisplayAllAssociatedErrors, _options.shouldUseNativeValidation && !onlyCheckValid, isFieldArrayRoot);
2331
+ if (isPromiseFunction && shouldTrackIsValidatingState) {
2332
+ _updateIsValidating([_f.name]);
2333
+ }
2334
+ if (fieldError[_f.name]) {
2335
+ context.valid = false;
2336
+ if (onlyCheckValid) {
2337
+ break;
2338
+ }
2339
+ }
2340
+ !onlyCheckValid &&
2341
+ (get(fieldError, _f.name)
2342
+ ? isFieldArrayRoot
2343
+ ? updateFieldArrayRootError(_formState.errors, fieldError, _f.name)
2344
+ : set(_formState.errors, _f.name, fieldError[_f.name])
2345
+ : unset(_formState.errors, _f.name));
2346
+ if (props.shouldUseNativeValidation && fieldError[_f.name]) {
2347
+ break;
2348
+ }
2349
+ }
2350
+ !isEmptyObject(fieldValue) &&
2351
+ (await executeBuiltInValidation({
2352
+ context,
2353
+ onlyCheckValid,
2354
+ fields: fieldValue,
2355
+ name: name,
2356
+ eventType,
2357
+ }));
2358
+ }
2180
2359
  }
2181
- return {
2182
- ...(disabledIsDefined
2183
- ? { disabled: options.disabled || _options.disabled }
2184
- : {}),
2185
- ...(_options.progressive
2186
- ? {
2187
- required: !!options.required,
2188
- min: getRuleValue(options.min),
2189
- max: getRuleValue(options.max),
2190
- minLength: getRuleValue(options.minLength),
2191
- maxLength: getRuleValue(options.maxLength),
2192
- pattern: getRuleValue(options.pattern),
2360
+ return context.valid;
2361
+ };
2362
+ const _removeUnmounted = () => {
2363
+ for (const name of _names.unMount) {
2364
+ const field = get(_fields, name);
2365
+ field &&
2366
+ (field._f.refs
2367
+ ? field._f.refs.every((ref) => !live(ref))
2368
+ : !live(field._f.ref)) &&
2369
+ unregister(name);
2370
+ }
2371
+ _names.unMount = new Set();
2372
+ };
2373
+ const _getDirty = (name, data) => (name && data && set(_formValues, name, data),
2374
+ !deepEqual(_state.mount ? _formValues : _defaultValues, _defaultValues));
2375
+ const _getWatch = (names, defaultValue, isGlobal) => generateWatchOutput(names, _names, {
2376
+ ...(_state.mount
2377
+ ? _formValues
2378
+ : isUndefined(defaultValue)
2379
+ ? _defaultValues
2380
+ : isString(names)
2381
+ ? { [names]: defaultValue }
2382
+ : defaultValue),
2383
+ }, isGlobal, defaultValue);
2384
+ const _getFieldArray = (name) => compact(get(_state.mount ? _formValues : _defaultValues, name, _options.shouldUnregister ? get(_defaultValues, name, []) : []));
2385
+ const setFieldValue = (name, value, options = {}, skipClone = false, skipRender = false) => {
2386
+ const field = get(_fields, name);
2387
+ let fieldValue = value;
2388
+ if (field) {
2389
+ const fieldReference = field._f;
2390
+ if (fieldReference) {
2391
+ !fieldReference.disabled &&
2392
+ set(_formValues, name, getFieldValueAs(value, fieldReference));
2393
+ fieldValue =
2394
+ isHTMLElement(fieldReference.ref) && isNullOrUndefined(value)
2395
+ ? ''
2396
+ : value;
2397
+ if (isMultipleSelect(fieldReference.ref)) {
2398
+ [...fieldReference.ref.options].forEach((optionRef) => (optionRef.selected = fieldValue.includes(optionRef.value)));
2193
2399
  }
2194
- : {}),
2195
- name,
2196
- onChange,
2197
- onBlur: onChange,
2198
- ref: (ref) => {
2199
- if (ref) {
2200
- register(name, options);
2201
- field = get(_fields, name);
2202
- const fieldRef = isUndefined(ref.value)
2203
- ? ref.querySelectorAll
2204
- ? ref.querySelectorAll('input,select,textarea')[0] || ref
2205
- : ref
2206
- : ref;
2207
- const radioOrCheckbox = isRadioOrCheckbox(fieldRef);
2208
- const refs = field._f.refs || [];
2209
- if (radioOrCheckbox
2210
- ? refs.find((option) => option === fieldRef)
2211
- : fieldRef === field._f.ref) {
2212
- return;
2213
- }
2214
- set(_fields, name, {
2215
- _f: {
2216
- ...field._f,
2217
- ...(radioOrCheckbox
2218
- ? {
2219
- refs: [
2220
- ...refs.filter(live),
2221
- fieldRef,
2222
- ...(Array.isArray(get(_defaultValues, name)) ? [{}] : []),
2223
- ],
2224
- ref: { type: fieldRef.type, name },
2400
+ else if (fieldReference.refs) {
2401
+ if (isCheckBoxInput(fieldReference.ref)) {
2402
+ fieldReference.refs.forEach((checkboxRef) => {
2403
+ if (!checkboxRef.defaultChecked || !checkboxRef.disabled) {
2404
+ if (Array.isArray(fieldValue)) {
2405
+ checkboxRef.checked = !!fieldValue.find((data) => data === checkboxRef.value);
2225
2406
  }
2226
- : { ref: fieldRef }),
2227
- },
2228
- });
2229
- updateValidAndValue(name, false, undefined, fieldRef);
2230
- }
2231
- else {
2232
- field = get(_fields, name, {});
2233
- if (field._f) {
2234
- field._f.mount = false;
2407
+ else {
2408
+ checkboxRef.checked =
2409
+ fieldValue === checkboxRef.value || !!fieldValue;
2410
+ }
2411
+ }
2412
+ });
2413
+ }
2414
+ else {
2415
+ fieldReference.refs.forEach((radioRef) => (radioRef.checked = radioRef.value === fieldValue));
2235
2416
  }
2236
- (_options.shouldUnregister || options.shouldUnregister) &&
2237
- !(isNameInFieldArray(_names.array, name) && _state.action) &&
2238
- _names.unMount.add(name);
2239
2417
  }
2240
- },
2241
- };
2242
- };
2243
- const _focusError = () => _options.shouldFocusError &&
2244
- iterateFieldsByAction(_fields, _focusInput, _names.mount);
2245
- const _disableForm = (disabled) => {
2246
- if (isBoolean(disabled)) {
2247
- _subjects.state.next({ disabled });
2248
- iterateFieldsByAction(_fields, (ref, name) => {
2249
- const currentField = get(_fields, name);
2250
- if (currentField) {
2251
- ref.disabled = currentField._f.disabled || disabled;
2252
- if (Array.isArray(currentField._f.refs)) {
2253
- currentField._f.refs.forEach((inputRef) => {
2254
- inputRef.disabled = currentField._f.disabled || disabled;
2418
+ else if (isFileInput(fieldReference.ref)) {
2419
+ fieldReference.ref.value = '';
2420
+ }
2421
+ else {
2422
+ fieldReference.ref.value = fieldValue;
2423
+ if (!fieldReference.ref.type && !skipRender) {
2424
+ _subjects.state.next({
2425
+ name,
2426
+ values: skipClone ? _formValues : cloneObject(_formValues),
2255
2427
  });
2256
2428
  }
2257
2429
  }
2258
- }, 0, false);
2430
+ }
2259
2431
  }
2432
+ (options.shouldDirty || options.shouldTouch) &&
2433
+ updateTouchAndDirty(name, fieldValue, options.shouldTouch, options.shouldDirty, !skipRender);
2434
+ options.shouldValidate &&
2435
+ trigger(name, {
2436
+ delayError: options.delayError,
2437
+ });
2260
2438
  };
2261
- const handleSubmit = (onValid, onInvalid) => async (e) => {
2262
- let onValidError = undefined;
2263
- if (e) {
2264
- e.preventDefault && e.preventDefault();
2265
- e.persist &&
2266
- e.persist();
2439
+ const setFieldValues = (name, value, options, skipClone = false, skipRender = false) => {
2440
+ for (const fieldKey in value) {
2441
+ if (!value.hasOwnProperty(fieldKey)) {
2442
+ return;
2443
+ }
2444
+ const fieldValue = value[fieldKey];
2445
+ const fieldName = name + '.' + fieldKey;
2446
+ const field = get(_fields, fieldName);
2447
+ (_names.array.has(name) ||
2448
+ isObject(fieldValue) ||
2449
+ (field && !field._f)) &&
2450
+ !isDateObject(fieldValue)
2451
+ ? setFieldValues(fieldName, fieldValue, options, skipClone, skipRender)
2452
+ : setFieldValue(fieldName, fieldValue, options, skipClone, skipRender);
2267
2453
  }
2268
- let fieldValues = cloneObject(_formValues);
2269
- _subjects.state.next({
2270
- isSubmitting: true,
2271
- });
2272
- if (_options.resolver) {
2273
- const { errors, values } = await _runSchema();
2274
- _updateIsValidating();
2275
- _formState.errors = errors;
2276
- fieldValues = cloneObject(values);
2454
+ };
2455
+ const _setValue = (name, value, options, skipClone, skipStateEmit = false) => {
2456
+ const field = get(_fields, name);
2457
+ const isFieldArray = _names.array.has(name);
2458
+ const cloneValue = skipClone ? value : cloneObject(value);
2459
+ const previousValue = get(_formValues, name);
2460
+ const isValueUnchanged = deepEqual(previousValue, cloneValue);
2461
+ if (!isValueUnchanged) {
2462
+ set(_formValues, name, cloneValue);
2277
2463
  }
2278
- else {
2279
- await executeBuiltInValidation({
2280
- fields: _fields,
2281
- eventType: EVENTS.SUBMIT,
2464
+ if (isFieldArray) {
2465
+ _subjects.array.next({
2466
+ name,
2467
+ values: skipClone ? _formValues : cloneObject(_formValues),
2282
2468
  });
2469
+ if ((_proxyFormState.isDirty ||
2470
+ _proxyFormState.dirtyFields ||
2471
+ _proxySubscribeFormState.isDirty ||
2472
+ _proxySubscribeFormState.dirtyFields) &&
2473
+ options.shouldDirty) {
2474
+ _updateDirtyFields();
2475
+ if (!skipStateEmit) {
2476
+ _subjects.state.next({
2477
+ name,
2478
+ dirtyFields: _formState.dirtyFields,
2479
+ isDirty: _getDirty(name, cloneValue),
2480
+ });
2481
+ }
2482
+ }
2283
2483
  }
2284
- if (_names.disabled.size) {
2285
- for (const name of _names.disabled) {
2286
- unset(fieldValues, name);
2484
+ else {
2485
+ const isEmpty = (Array.isArray(cloneValue) && !cloneValue.length) ||
2486
+ isEmptyObject(cloneValue);
2487
+ if (!field || field._f || isNullOrUndefined(cloneValue) || isEmpty) {
2488
+ setFieldValue(name, cloneValue, options, skipClone, skipStateEmit);
2489
+ }
2490
+ else {
2491
+ setFieldValues(name, cloneValue, options, skipClone, skipStateEmit);
2287
2492
  }
2288
2493
  }
2289
- unset(_formState.errors, ROOT_ERROR_TYPE);
2290
- if (isEmptyObject(_formState.errors)) {
2494
+ if (!isValueUnchanged && !skipStateEmit) {
2495
+ const watched = isWatched(name, _names);
2496
+ const values = skipClone ? _formValues : cloneObject(_formValues);
2291
2497
  _subjects.state.next({
2292
- errors: {},
2498
+ ...(watched && _formState),
2499
+ name: _state.mount || watched ? name : undefined,
2500
+ values,
2293
2501
  });
2294
- try {
2295
- await onValid(fieldValues, e);
2502
+ }
2503
+ };
2504
+ const setValue = (name, value, options = {}) => _setValue(name, value, options, false);
2505
+ const setValues = (formValues, options = {}) => {
2506
+ const updatedFormValues = isFunction(formValues)
2507
+ ? formValues(_formValues)
2508
+ : formValues;
2509
+ if (!deepEqual(_formValues, updatedFormValues)) {
2510
+ _formValues = {
2511
+ ..._formValues,
2512
+ ...updatedFormValues,
2513
+ };
2514
+ const flattenedUpdates = flatten(updatedFormValues);
2515
+ for (const fieldName of _names.mount) {
2516
+ if (fieldName in flattenedUpdates) {
2517
+ _setValue(fieldName, flattenedUpdates[fieldName], options, true, true);
2518
+ }
2296
2519
  }
2297
- catch (error) {
2298
- onValidError = error;
2520
+ _subjects.state.next({
2521
+ ..._formState,
2522
+ name: undefined,
2523
+ type: undefined,
2524
+ ...(_valuesSubscriberCount ? { values: _formValues } : {}),
2525
+ });
2526
+ if (options.shouldValidate) {
2527
+ _setValid();
2528
+ }
2529
+ }
2530
+ };
2531
+ const onChange = async (event) => {
2532
+ _state.mount = true;
2533
+ const target = event.target;
2534
+ let name = target.name;
2535
+ let isFieldValueUpdated = true;
2536
+ const field = get(_fields, name);
2537
+ const _updateIsFieldValueUpdated = (fieldValue) => {
2538
+ isFieldValueUpdated =
2539
+ Number.isNaN(fieldValue) ||
2540
+ (isDateObject(fieldValue) && isNaN(fieldValue.getTime())) ||
2541
+ deepEqual(fieldValue, get(_formValues, name, fieldValue));
2542
+ };
2543
+ if (field) {
2544
+ let error;
2545
+ let isValid;
2546
+ const fieldValue = target.type
2547
+ ? getFieldValue(field._f)
2548
+ : getEventValue(event);
2549
+ const isBlurEvent = event.type === EVENTS.BLUR || event.type === EVENTS.FOCUS_OUT;
2550
+ const hasNoValidationEffect = !hasValidation(field._f) &&
2551
+ !props.validate &&
2552
+ !_options.resolver &&
2553
+ !get(_formState.errors, name) &&
2554
+ !field._f.deps;
2555
+ const shouldSkipValidation = hasNoValidationEffect ||
2556
+ skipValidation(isBlurEvent, get(_formState.touchedFields, name), _formState.isSubmitted, _validationModeAfterSubmit, _validationModeBeforeSubmit);
2557
+ const watched = isWatched(name, _names, isBlurEvent);
2558
+ set(_formValues, name, fieldValue);
2559
+ if (isBlurEvent) {
2560
+ if (!target || !target.readOnly) {
2561
+ field._f.onBlur && field._f.onBlur(event);
2562
+ const pendingDelayError = delayErrorCallbacks[name];
2563
+ pendingDelayError && pendingDelayError(0);
2564
+ }
2565
+ }
2566
+ else if (field._f.onChange) {
2567
+ field._f.onChange(event);
2568
+ }
2569
+ const fieldState = updateTouchAndDirty(name, fieldValue, isBlurEvent);
2570
+ const shouldRender = !isEmptyObject(fieldState) || watched;
2571
+ !isBlurEvent &&
2572
+ _subjects.state.next({
2573
+ name,
2574
+ type: event.type,
2575
+ ...(_valuesSubscriberCount
2576
+ ? { values: cloneObject(_formValues) }
2577
+ : {}),
2578
+ });
2579
+ if (shouldSkipValidation) {
2580
+ if ((!hasNoValidationEffect || !_formState.isValid) &&
2581
+ (_proxyFormState.isValid || _proxySubscribeFormState.isValid)) {
2582
+ if (_options.mode === 'onBlur') {
2583
+ if (isBlurEvent) {
2584
+ _setValid();
2585
+ }
2586
+ }
2587
+ else if (!isBlurEvent) {
2588
+ _setValid();
2589
+ }
2590
+ }
2591
+ return (shouldRender &&
2592
+ _subjects.state.next({ name, ...(watched ? {} : fieldState) }));
2299
2593
  }
2594
+ if (!_options.resolver && props.validate) {
2595
+ await validateForm({
2596
+ name: name,
2597
+ eventType: event.type,
2598
+ });
2599
+ }
2600
+ !isBlurEvent && watched && _subjects.state.next({ ..._formState });
2601
+ if (_options.resolver) {
2602
+ const { errors } = await _runSchema([name]);
2603
+ _updateIsValidating([name]);
2604
+ _updateIsFieldValueUpdated(fieldValue);
2605
+ if (!isFieldValueUpdated) {
2606
+ !isEmptyObject(fieldState) && _subjects.state.next(fieldState);
2607
+ return;
2608
+ }
2609
+ const previousErrorLookupResult = schemaErrorLookup(_formState.errors, _fields, name);
2610
+ const errorLookupResult = schemaErrorLookup(errors, _fields, previousErrorLookupResult.name || name);
2611
+ error = errorLookupResult.error;
2612
+ name = errorLookupResult.name;
2613
+ isValid = isEmptyObject(errors);
2614
+ }
2615
+ else {
2616
+ _updateIsValidating([name], true);
2617
+ error = (await validateField(field, _names.disabled, _formValues, shouldDisplayAllAssociatedErrors, _options.shouldUseNativeValidation))[name];
2618
+ _updateIsValidating([name]);
2619
+ _updateIsFieldValueUpdated(fieldValue);
2620
+ if (isFieldValueUpdated) {
2621
+ if (error) {
2622
+ isValid = false;
2623
+ }
2624
+ else if (_proxyFormState.isValid ||
2625
+ _proxySubscribeFormState.isValid) {
2626
+ isValid = await executeBuiltInValidation({
2627
+ fields: _fields,
2628
+ onlyCheckValid: true,
2629
+ name: name,
2630
+ eventType: event.type,
2631
+ });
2632
+ }
2633
+ }
2634
+ }
2635
+ if (isFieldValueUpdated) {
2636
+ field._f.deps &&
2637
+ (!Array.isArray(field._f.deps) || field._f.deps.length > 0) &&
2638
+ trigger(field._f.deps);
2639
+ shouldRenderByError(name, isValid, error, fieldState);
2640
+ }
2641
+ }
2642
+ };
2643
+ const _focusInput = (ref, key) => {
2644
+ if (get(_formState.errors, key) && ref.focus) {
2645
+ ref.focus();
2646
+ return 1;
2647
+ }
2648
+ return;
2649
+ };
2650
+ const trigger = async (name, options = {}) => {
2651
+ let isValid;
2652
+ let validationResult;
2653
+ const fieldNames = convertToArrayPayload(name);
2654
+ if (_options.resolver) {
2655
+ const errors = await executeSchemaAndUpdateState(isUndefined(name) ? name : fieldNames);
2656
+ isValid = isEmptyObject(errors);
2657
+ validationResult = name
2658
+ ? !fieldNames.some((name) => get(errors, name))
2659
+ : isValid;
2660
+ }
2661
+ else if (name) {
2662
+ validationResult = (await Promise.all(fieldNames.map(async (fieldName) => {
2663
+ const field = get(_fields, fieldName);
2664
+ return await executeBuiltInValidation({
2665
+ fields: field && field._f ? { [fieldName]: field } : field,
2666
+ eventType: EVENTS.TRIGGER,
2667
+ });
2668
+ }))).every(Boolean);
2669
+ !(!validationResult && !_formState.isValid) && _setValid();
2300
2670
  }
2301
2671
  else {
2302
- if (onInvalid) {
2303
- await onInvalid({ ..._formState.errors }, e);
2672
+ validationResult = isValid = await executeBuiltInValidation({
2673
+ fields: _fields,
2674
+ name,
2675
+ eventType: EVENTS.TRIGGER,
2676
+ });
2677
+ }
2678
+ if (options.delayError && _options.delayError && isString(name)) {
2679
+ const error = get(_formState.errors, name);
2680
+ if (error) {
2681
+ unset(_formState.errors, name);
2682
+ delayErrorCallbacks[name] = debounce(name, () => updateErrors(name, error));
2683
+ delayErrorCallbacks[name](_options.delayError);
2684
+ }
2685
+ else {
2686
+ clearTimeout(timers[name]);
2687
+ delete delayErrorCallbacks[name];
2304
2688
  }
2305
- _focusError();
2306
- setTimeout(_focusError);
2307
2689
  }
2308
2690
  _subjects.state.next({
2309
- isSubmitted: true,
2310
- isSubmitting: false,
2311
- isSubmitSuccessful: isEmptyObject(_formState.errors) && !onValidError,
2312
- submitCount: _formState.submitCount + 1,
2691
+ ...(!isString(name) ||
2692
+ ((_proxyFormState.isValid || _proxySubscribeFormState.isValid) &&
2693
+ isValid !== _formState.isValid)
2694
+ ? {}
2695
+ : { name }),
2696
+ ...(_options.resolver || !name ? { isValid } : {}),
2313
2697
  errors: _formState.errors,
2314
2698
  });
2315
- if (onValidError) {
2316
- throw onValidError;
2317
- }
2699
+ options.shouldFocus &&
2700
+ !validationResult &&
2701
+ iterateFieldsByAction(_fields, _focusInput, name ? fieldNames : _names.mount);
2702
+ return validationResult;
2318
2703
  };
2319
- const resetField = (name, options = {}) => {
2320
- if (get(_fields, name)) {
2321
- if (isUndefined(options.defaultValue)) {
2322
- setValue(name, cloneObject(get(_defaultValues, name)));
2323
- }
2324
- else {
2325
- setValue(name, options.defaultValue);
2326
- set(_defaultValues, name, cloneObject(options.defaultValue));
2327
- }
2328
- if (!options.keepTouched) {
2329
- unset(_formState.touchedFields, name);
2330
- }
2331
- if (!options.keepDirty) {
2332
- unset(_formState.dirtyFields, name);
2333
- _formState.isDirty = options.defaultValue
2334
- ? _getDirty(name, cloneObject(get(_defaultValues, name)))
2335
- : _getDirty();
2336
- }
2337
- if (!options.keepError) {
2338
- unset(_formState.errors, name);
2339
- _proxyFormState.isValid && _setValid();
2340
- }
2341
- _subjects.state.next({ ..._formState });
2704
+ const getValues = (fieldNames, config) => {
2705
+ let values = {
2706
+ ...(_state.mount ? _formValues : _defaultValues),
2707
+ };
2708
+ if (config) {
2709
+ values = extractFormValues(config.dirtyFields ? _formState.dirtyFields : _formState.touchedFields, values);
2342
2710
  }
2711
+ return isUndefined(fieldNames)
2712
+ ? values
2713
+ : isString(fieldNames)
2714
+ ? get(values, fieldNames)
2715
+ : fieldNames.map((name) => get(values, name));
2343
2716
  };
2344
- const _reset = (formValues, keepStateOptions = {}) => {
2345
- const updatedValues = formValues ? cloneObject(formValues) : _defaultValues;
2346
- const cloneUpdatedValues = cloneObject(updatedValues);
2347
- const isEmptyResetValues = isEmptyObject(formValues);
2348
- const values = isEmptyResetValues ? _defaultValues : cloneUpdatedValues;
2349
- if (!keepStateOptions.keepDefaultValues) {
2350
- _defaultValues = updatedValues;
2351
- }
2352
- if (!keepStateOptions.keepValues) {
2353
- if (keepStateOptions.keepDirtyValues) {
2354
- const fieldsToCheck = new Set([
2355
- ..._names.mount,
2356
- ...Object.keys(getDirtyFields(_defaultValues, _formValues)),
2357
- ]);
2358
- for (const fieldName of Array.from(fieldsToCheck)) {
2359
- const isDirty = get(_formState.dirtyFields, fieldName);
2360
- const existingValue = get(_formValues, fieldName);
2361
- const newValue = get(values, fieldName);
2362
- if (isDirty && !isUndefined(existingValue)) {
2363
- set(values, fieldName, existingValue);
2364
- }
2365
- else if (!isDirty && !isUndefined(newValue)) {
2366
- setValue(fieldName, newValue);
2367
- }
2368
- }
2369
- }
2370
- else {
2371
- if (isWeb && isUndefined(formValues)) {
2372
- for (const name of _names.mount) {
2373
- const field = get(_fields, name);
2374
- if (field && field._f) {
2375
- const fieldReference = Array.isArray(field._f.refs)
2376
- ? field._f.refs[0]
2377
- : field._f.ref;
2378
- if (isHTMLElement(fieldReference)) {
2379
- const form = fieldReference.closest('form');
2380
- if (form) {
2381
- form.reset();
2382
- break;
2383
- }
2384
- }
2385
- }
2386
- }
2387
- }
2388
- if (keepStateOptions.keepFieldsRef) {
2389
- for (const fieldName of _names.mount) {
2390
- setValue(fieldName, get(values, fieldName));
2391
- }
2392
- }
2393
- else {
2394
- _fields = {};
2395
- }
2396
- }
2397
- _formValues = _options.shouldUnregister
2398
- ? keepStateOptions.keepDefaultValues
2399
- ? cloneObject(_defaultValues)
2400
- : {}
2401
- : cloneObject(values);
2402
- _subjects.array.next({
2403
- values: { ...values },
2404
- });
2405
- _subjects.state.next({
2406
- values: { ...values },
2717
+ const getFieldState = (name, formState) => ({
2718
+ invalid: !!get((formState || _formState).errors, name),
2719
+ isDirty: !!get((formState || _formState).dirtyFields, name),
2720
+ error: get((formState || _formState).errors, name),
2721
+ isValidating: !!get(_formState.validatingFields, name),
2722
+ isTouched: !!get((formState || _formState).touchedFields, name),
2723
+ });
2724
+ const clearErrors = (name) => {
2725
+ const names = name ? convertToArrayPayload(name) : undefined;
2726
+ names === null || names === void 0 ? void 0 : names.forEach((inputName) => unset(_formState.errors, inputName));
2727
+ if (names) {
2728
+ names.forEach((inputName) => {
2729
+ _subjects.state.next({
2730
+ name: inputName,
2731
+ errors: _formState.errors,
2732
+ });
2407
2733
  });
2408
2734
  }
2409
- _names = {
2410
- mount: keepStateOptions.keepDirtyValues ? _names.mount : new Set(),
2411
- unMount: new Set(),
2412
- array: new Set(),
2413
- disabled: new Set(),
2414
- watch: new Set(),
2415
- watchAll: false,
2416
- focus: '',
2417
- };
2418
- _state.mount =
2419
- !_proxyFormState.isValid ||
2420
- !!keepStateOptions.keepIsValid ||
2421
- !!keepStateOptions.keepDirtyValues ||
2422
- (!_options.shouldUnregister && !isEmptyObject(values));
2423
- _state.watch = !!_options.shouldUnregister;
2424
- _state.keepIsValid = !!keepStateOptions.keepIsValid;
2425
- _state.action = false;
2426
- // Clear errors synchronously to prevent validation errors on subsequent submissions
2427
- // This fixes the issue where form.reset() causes validation errors on subsequent
2428
- // submissions in Next.js 16 with Server Actions
2429
- if (!keepStateOptions.keepErrors) {
2735
+ else {
2430
2736
  _formState.errors = {};
2737
+ _subjects.state.next({
2738
+ errors: _formState.errors,
2739
+ });
2431
2740
  }
2741
+ };
2742
+ const setError = (name, error, options) => {
2743
+ const ref = (get(_fields, name, { _f: {} })._f || {}).ref;
2744
+ const currentError = get(_formState.errors, name) || {};
2745
+ const { ref: currentRef, message, type, ...restOfErrorTree } = currentError;
2746
+ set(_formState.errors, name, {
2747
+ ...restOfErrorTree,
2748
+ ...error,
2749
+ ref,
2750
+ });
2432
2751
  _subjects.state.next({
2433
- submitCount: keepStateOptions.keepSubmitCount
2434
- ? _formState.submitCount
2435
- : 0,
2436
- isDirty: isEmptyResetValues
2437
- ? false
2438
- : keepStateOptions.keepDirty
2439
- ? _formState.isDirty
2440
- : !!(keepStateOptions.keepDefaultValues &&
2441
- !deepEqual(formValues, _defaultValues)),
2442
- isSubmitted: keepStateOptions.keepIsSubmitted
2443
- ? _formState.isSubmitted
2444
- : false,
2445
- dirtyFields: isEmptyResetValues
2446
- ? {}
2447
- : keepStateOptions.keepDirtyValues
2448
- ? keepStateOptions.keepDefaultValues && _formValues
2449
- ? getDirtyFields(_defaultValues, _formValues)
2450
- : _formState.dirtyFields
2451
- : keepStateOptions.keepDefaultValues && formValues
2452
- ? getDirtyFields(_defaultValues, formValues)
2453
- : keepStateOptions.keepDirty
2454
- ? _formState.dirtyFields
2455
- : {},
2456
- touchedFields: keepStateOptions.keepTouched
2457
- ? _formState.touchedFields
2458
- : {},
2459
- errors: keepStateOptions.keepErrors ? _formState.errors : {},
2460
- isSubmitSuccessful: keepStateOptions.keepIsSubmitSuccessful
2461
- ? _formState.isSubmitSuccessful
2462
- : false,
2463
- isSubmitting: false,
2464
- defaultValues: _defaultValues,
2752
+ name,
2753
+ errors: _formState.errors,
2754
+ isValid: false,
2465
2755
  });
2756
+ options && options.shouldFocus && ref && ref.focus && ref.focus();
2466
2757
  };
2467
- const reset = (formValues, keepStateOptions) => _reset(isFunction(formValues)
2468
- ? formValues(_formValues)
2469
- : formValues, { ..._options.resetOptions, ...keepStateOptions });
2470
- const setFocus = (name, options = {}) => {
2471
- const field = get(_fields, name);
2472
- const fieldReference = field && field._f;
2473
- if (fieldReference) {
2474
- const fieldRef = fieldReference.refs
2475
- ? fieldReference.refs[0]
2476
- : fieldReference.ref;
2477
- if (fieldRef.focus) {
2478
- // Use setTimeout to ensure focus happens after any pending state updates
2479
- // This fixes the issue where setFocus doesn't work immediately after setError
2480
- setTimeout(() => {
2481
- fieldRef.focus();
2482
- options.shouldSelect &&
2483
- isFunction(fieldRef.select) &&
2484
- fieldRef.select();
2485
- });
2758
+ const watch = (name, defaultValue) => {
2759
+ if (isFunction(name)) {
2760
+ _valuesSubscriberCount++;
2761
+ const { unsubscribe } = _subjects.state.subscribe({
2762
+ next: (payload) => 'values' in payload &&
2763
+ name(payload.values || _getWatch(undefined, defaultValue), payload),
2764
+ });
2765
+ let called = false;
2766
+ return {
2767
+ unsubscribe: () => {
2768
+ if (called) {
2769
+ return;
2770
+ }
2771
+ called = true;
2772
+ _valuesSubscriberCount--;
2773
+ unsubscribe();
2774
+ },
2775
+ };
2776
+ }
2777
+ return _getWatch(name, defaultValue, true);
2778
+ };
2779
+ const _subscribe = (props) => {
2780
+ var _a;
2781
+ const needsValues = !!((_a = props.formState) === null || _a === void 0 ? void 0 : _a.values);
2782
+ if (needsValues) {
2783
+ _valuesSubscriberCount++;
2784
+ }
2785
+ const { unsubscribe } = _subjects.state.subscribe({
2786
+ next: (formState) => {
2787
+ if (shouldSubscribeByName(props.name, formState.name, props.exact) &&
2788
+ shouldRenderFormState(formState, props.formState || _proxyFormState, _setFormState, props.reRenderRoot)) {
2789
+ const snapshot = { ..._formValues };
2790
+ props.callback({
2791
+ values: snapshot,
2792
+ ..._formState,
2793
+ ...formState,
2794
+ defaultValues: _defaultValues,
2795
+ });
2796
+ }
2797
+ },
2798
+ });
2799
+ if (!needsValues) {
2800
+ return unsubscribe;
2801
+ }
2802
+ let called = false;
2803
+ return () => {
2804
+ if (called) {
2805
+ return;
2806
+ }
2807
+ called = true;
2808
+ _valuesSubscriberCount--;
2809
+ unsubscribe();
2810
+ };
2811
+ };
2812
+ const subscribe = (props) => {
2813
+ _state.mount = true;
2814
+ _proxySubscribeFormState = {
2815
+ ..._proxySubscribeFormState,
2816
+ ...props.formState,
2817
+ };
2818
+ return _subscribe({
2819
+ ...props,
2820
+ formState: {
2821
+ ...defaultProxyFormState,
2822
+ ...props.formState,
2823
+ },
2824
+ });
2825
+ };
2826
+ const unregister = (name, options = {}) => {
2827
+ for (const fieldName of name ? convertToArrayPayload(name) : _names.mount) {
2828
+ _names.mount.delete(fieldName);
2829
+ _names.array.delete(fieldName);
2830
+ if (!options.keepValue) {
2831
+ unset(_fields, fieldName);
2832
+ unset(_formValues, fieldName);
2486
2833
  }
2834
+ !options.keepError && unset(_formState.errors, fieldName);
2835
+ !options.keepDirty && unset(_formState.dirtyFields, fieldName);
2836
+ !options.keepTouched && unset(_formState.touchedFields, fieldName);
2837
+ !options.keepIsValidating &&
2838
+ unset(_formState.validatingFields, fieldName);
2839
+ !_options.shouldUnregister &&
2840
+ !options.keepDefaultValue &&
2841
+ unset(_defaultValues, fieldName);
2487
2842
  }
2488
- };
2489
- const _setFormState = (updatedFormState) => {
2490
- _formState = {
2843
+ _subjects.state.next({
2844
+ values: cloneObject(_formValues),
2845
+ });
2846
+ _subjects.state.next({
2491
2847
  ..._formState,
2492
- ...updatedFormState,
2493
- };
2494
- };
2495
- const _resetDefaultValues = () => isFunction(_options.defaultValues) &&
2496
- _options.defaultValues().then((values) => {
2497
- reset(values, _options.resetOptions);
2498
- _subjects.state.next({
2499
- isLoading: false,
2500
- });
2848
+ ...(!options.keepDirty ? {} : { isDirty: _getDirty() }),
2501
2849
  });
2502
- const methods = {
2503
- control: {
2504
- register,
2505
- unregister,
2506
- getFieldState,
2507
- handleSubmit,
2508
- setError,
2509
- _subscribe,
2510
- _runSchema,
2511
- _updateIsValidating,
2512
- _focusError,
2513
- _getWatch,
2514
- _getDirty,
2515
- _setValid,
2516
- _setFieldArray,
2517
- _setDisabledField,
2518
- _setErrors,
2519
- _getFieldArray,
2520
- _reset,
2521
- _resetDefaultValues,
2522
- _removeUnmounted,
2523
- _disableForm,
2524
- _subjects,
2525
- _proxyFormState,
2526
- get _fields() {
2527
- return _fields;
2528
- },
2529
- get _formValues() {
2530
- return _formValues;
2531
- },
2532
- get _state() {
2533
- return _state;
2534
- },
2535
- set _state(value) {
2536
- _state = value;
2537
- },
2538
- get _defaultValues() {
2539
- return _defaultValues;
2540
- },
2541
- get _names() {
2542
- return _names;
2543
- },
2544
- set _names(value) {
2545
- _names = value;
2546
- },
2547
- get _formState() {
2548
- return _formState;
2549
- },
2550
- get _options() {
2551
- return _options;
2552
- },
2553
- set _options(value) {
2554
- _options = {
2555
- ..._options,
2556
- ...value,
2557
- };
2558
- },
2559
- },
2560
- subscribe,
2561
- trigger,
2562
- register,
2563
- handleSubmit,
2564
- watch,
2565
- setValue,
2566
- getValues,
2567
- reset,
2568
- resetField,
2569
- clearErrors,
2570
- unregister,
2571
- setError,
2572
- setFocus,
2573
- getFieldState,
2850
+ !options.keepIsValid && _setValid();
2574
2851
  };
2575
- return {
2576
- ...methods,
2577
- formControl: methods,
2852
+ const _setDisabledField = ({ disabled, name, }) => {
2853
+ if ((isBoolean(disabled) && _state.mount) ||
2854
+ !!disabled ||
2855
+ _names.disabled.has(name)) {
2856
+ const wasDisabled = _names.disabled.has(name);
2857
+ const isDisabled = !!disabled;
2858
+ const disabledStateChanged = wasDisabled !== isDisabled;
2859
+ disabled ? _names.disabled.add(name) : _names.disabled.delete(name);
2860
+ disabledStateChanged && _state.mount && !_state.action && _setValid();
2861
+ }
2578
2862
  };
2579
- }
2580
-
2581
- var generateId = () => {
2582
- if (typeof crypto !== 'undefined' && crypto.randomUUID) {
2583
- return crypto.randomUUID();
2584
- }
2585
- const d = typeof performance === 'undefined' ? Date.now() : performance.now() * 1000;
2586
- return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
2587
- const r = ((Math.random() * 16 + d) % 16) | 0;
2588
- return (c == 'x' ? r : (r & 0x3) | 0x8).toString(16);
2589
- });
2590
- };
2591
-
2592
- var getFocusFieldName = (name, index, options = {}) => options.shouldFocus || isUndefined(options.shouldFocus)
2593
- ? options.focusName ||
2594
- `${name}.${isUndefined(options.focusIndex) ? index : options.focusIndex}.`
2595
- : '';
2596
-
2597
- var appendAt = (data, value) => [
2598
- ...data,
2599
- ...convertToArrayPayload(value),
2600
- ];
2601
-
2602
- var fillEmptyArray = (value) => Array.isArray(value) ? value.map(() => undefined) : undefined;
2603
-
2604
- function insert(data, index, value) {
2605
- return [
2606
- ...data.slice(0, index),
2607
- ...convertToArrayPayload(value),
2608
- ...data.slice(index),
2609
- ];
2610
- }
2611
-
2612
- var moveArrayAt = (data, from, to) => {
2613
- if (!Array.isArray(data)) {
2614
- return [];
2615
- }
2616
- if (isUndefined(data[to])) {
2617
- data[to] = undefined;
2618
- }
2619
- data.splice(to, 0, data.splice(from, 1)[0]);
2620
- return data;
2621
- };
2622
-
2623
- var prependAt = (data, value) => [
2624
- ...convertToArrayPayload(value),
2625
- ...convertToArrayPayload(data),
2626
- ];
2627
-
2628
- function removeAtIndexes(data, indexes) {
2629
- let i = 0;
2630
- const temp = [...data];
2631
- for (const index of indexes) {
2632
- temp.splice(index - i, 1);
2633
- i++;
2634
- }
2635
- return compact(temp).length ? temp : [];
2636
- }
2637
- var removeArrayAt = (data, index) => isUndefined(index)
2638
- ? []
2639
- : removeAtIndexes(data, convertToArrayPayload(index).sort((a, b) => a - b));
2640
-
2641
- var swapArrayAt = (data, indexA, indexB) => {
2642
- [data[indexA], data[indexB]] = [data[indexB], data[indexA]];
2643
- };
2644
-
2645
- var updateAt = (fieldValues, index, value) => {
2646
- fieldValues[index] = value;
2647
- return fieldValues;
2648
- };
2649
-
2650
- /**
2651
- * A custom hook that exposes convenient methods to perform operations with a list of dynamic inputs that need to be appended, updated, removed etc. • [Demo](https://codesandbox.io/s/react-hook-form-usefieldarray-ssugn) • [Video](https://youtu.be/4MrbfGSFY2A)
2652
- *
2653
- * @remarks
2654
- * [API](https://react-hook-form.com/docs/usefieldarray) • [Demo](https://codesandbox.io/s/react-hook-form-usefieldarray-ssugn)
2655
- *
2656
- * @param props - useFieldArray props
2657
- *
2658
- * @returns methods - functions to manipulate with the Field Arrays (dynamic inputs) {@link UseFieldArrayReturn}
2659
- *
2660
- * @example
2661
- * ```tsx
2662
- * function App() {
2663
- * const { register, control, handleSubmit, reset, trigger, setError } = useForm({
2664
- * defaultValues: {
2665
- * test: []
2666
- * }
2667
- * });
2668
- * const { fields, append } = useFieldArray({
2669
- * control,
2670
- * name: "test"
2671
- * });
2672
- *
2673
- * return (
2674
- * <form onSubmit={handleSubmit(data => console.log(data))}>
2675
- * {fields.map((item, index) => (
2676
- * <input key={item.id} {...register(`test.${index}.firstName`)} />
2677
- * ))}
2678
- * <button type="button" onClick={() => append({ firstName: "bill" })}>
2679
- * append
2680
- * </button>
2681
- * <input type="submit" />
2682
- * </form>
2683
- * );
2684
- * }
2685
- * ```
2686
- */
2687
- function useFieldArray(props) {
2688
- const formControl = useFormControlContext();
2689
- const { control = formControl, name, keyName = 'id', shouldUnregister, rules, } = props;
2690
- const [fields, setFields] = React.useState(control._getFieldArray(name));
2691
- const ids = React.useRef(control._getFieldArray(name).map(generateId));
2692
- const _actioned = React.useRef(false);
2693
- control._names.array.add(name);
2694
- React.useMemo(() => rules &&
2695
- fields.length >= 0 &&
2696
- control.register(name, rules), [control, name, fields.length, rules]);
2697
- useIsomorphicLayoutEffect(() => control._subjects.array.subscribe({
2698
- next: ({ values, name: fieldArrayName, }) => {
2699
- if (fieldArrayName === name || !fieldArrayName) {
2700
- const fieldValues = get(values, name);
2701
- if (Array.isArray(fieldValues)) {
2702
- setFields(fieldValues);
2703
- ids.current = fieldValues.map(generateId);
2704
- }
2705
- }
2706
- },
2707
- }).unsubscribe, [control, name]);
2708
- const updateValues = React.useCallback((updatedFieldArrayValues) => {
2709
- _actioned.current = true;
2710
- control._setFieldArray(name, updatedFieldArrayValues);
2711
- }, [control, name]);
2712
- const append = (value, options) => {
2713
- const appendValue = convertToArrayPayload(cloneObject(value));
2714
- const updatedFieldArrayValues = appendAt(control._getFieldArray(name), appendValue);
2715
- control._names.focus = getFocusFieldName(name, updatedFieldArrayValues.length - 1, options);
2716
- ids.current = appendAt(ids.current, appendValue.map(generateId));
2717
- updateValues(updatedFieldArrayValues);
2718
- setFields(updatedFieldArrayValues);
2719
- control._setFieldArray(name, updatedFieldArrayValues, appendAt, {
2720
- argA: fillEmptyArray(value),
2863
+ const register = (name, options = {}) => {
2864
+ let field = get(_fields, name);
2865
+ const disabledIsDefined = isBoolean(options.disabled) || isBoolean(_options.disabled);
2866
+ const shouldRevalidateRemount = !_names.registerName.has(name) && field && field._f && !field._f.mount;
2867
+ set(_fields, name, {
2868
+ ...(field || {}),
2869
+ _f: {
2870
+ ...(field && field._f ? field._f : { ref: { name } }),
2871
+ name,
2872
+ mount: true,
2873
+ ...options,
2874
+ },
2721
2875
  });
2876
+ _names.mount.add(name);
2877
+ if (field && !shouldRevalidateRemount) {
2878
+ _setDisabledField({
2879
+ disabled: isBoolean(options.disabled)
2880
+ ? options.disabled
2881
+ : _options.disabled,
2882
+ name,
2883
+ });
2884
+ }
2885
+ else {
2886
+ updateValidAndValue(name, true, options.value);
2887
+ }
2888
+ return {
2889
+ ...(disabledIsDefined
2890
+ ? { disabled: options.disabled || _options.disabled }
2891
+ : {}),
2892
+ ...(_options.progressive
2893
+ ? {
2894
+ required: !!options.required,
2895
+ min: getRuleValue(options.min),
2896
+ max: getRuleValue(options.max),
2897
+ minLength: getRuleValue(options.minLength),
2898
+ maxLength: getRuleValue(options.maxLength),
2899
+ pattern: getRuleValue(options.pattern),
2900
+ }
2901
+ : {}),
2902
+ name,
2903
+ onChange,
2904
+ onBlur: onChange,
2905
+ ref: (ref) => {
2906
+ if (ref) {
2907
+ _names.registerName.add(name);
2908
+ register(name, options);
2909
+ _names.registerName.delete(name);
2910
+ field = get(_fields, name);
2911
+ const fieldRef = isUndefined(ref.value)
2912
+ ? ref.querySelectorAll
2913
+ ? ref.querySelectorAll('input,select,textarea')[0] || ref
2914
+ : ref
2915
+ : ref;
2916
+ const radioOrCheckbox = isRadioOrCheckbox(fieldRef);
2917
+ const refs = field._f.refs || [];
2918
+ if (radioOrCheckbox
2919
+ ? refs.find((option) => option === fieldRef)
2920
+ : fieldRef === field._f.ref) {
2921
+ return;
2922
+ }
2923
+ const newField = {
2924
+ ...field._f,
2925
+ };
2926
+ if (radioOrCheckbox) {
2927
+ newField.refs = [
2928
+ ...refs.filter(live),
2929
+ fieldRef,
2930
+ ...(Array.isArray(get(_defaultValues, name)) ? [{}] : []),
2931
+ ];
2932
+ newField.ref = { type: fieldRef.type, name };
2933
+ }
2934
+ else {
2935
+ newField.ref = fieldRef;
2936
+ delete newField.refs;
2937
+ }
2938
+ set(_fields, name, {
2939
+ _f: newField,
2940
+ });
2941
+ updateValidAndValue(name, false, undefined, fieldRef);
2942
+ }
2943
+ else {
2944
+ field = get(_fields, name, {});
2945
+ if (field._f) {
2946
+ field._f.mount = false;
2947
+ }
2948
+ (_options.shouldUnregister || options.shouldUnregister) &&
2949
+ !(isNameInFieldArray(_names.array, name) && _state.action) &&
2950
+ _names.unMount.add(name);
2951
+ }
2952
+ },
2953
+ };
2722
2954
  };
2723
- const prepend = (value, options) => {
2724
- const prependValue = convertToArrayPayload(cloneObject(value));
2725
- const updatedFieldArrayValues = prependAt(control._getFieldArray(name), prependValue);
2726
- control._names.focus = getFocusFieldName(name, 0, options);
2727
- ids.current = prependAt(ids.current, prependValue.map(generateId));
2728
- updateValues(updatedFieldArrayValues);
2729
- setFields(updatedFieldArrayValues);
2730
- control._setFieldArray(name, updatedFieldArrayValues, prependAt, {
2731
- argA: fillEmptyArray(value),
2732
- });
2955
+ const _focusError = () => _options.shouldFocusError &&
2956
+ !_options.shouldUseNativeValidation &&
2957
+ iterateFieldsByAction(_fields, _focusInput, _names.mount);
2958
+ const _disableForm = (disabled) => {
2959
+ if (isBoolean(disabled)) {
2960
+ _subjects.state.next({ disabled });
2961
+ iterateFieldsByAction(_fields, (ref, name) => {
2962
+ const currentField = get(_fields, name);
2963
+ if (currentField) {
2964
+ ref.disabled = currentField._f.disabled || disabled;
2965
+ if (Array.isArray(currentField._f.refs)) {
2966
+ currentField._f.refs.forEach((inputRef) => {
2967
+ inputRef.disabled = currentField._f.disabled || disabled;
2968
+ });
2969
+ }
2970
+ }
2971
+ }, 0, false);
2972
+ }
2733
2973
  };
2734
- const remove = (index) => {
2735
- const updatedFieldArrayValues = removeArrayAt(control._getFieldArray(name), index);
2736
- ids.current = removeArrayAt(ids.current, index);
2737
- updateValues(updatedFieldArrayValues);
2738
- setFields(updatedFieldArrayValues);
2739
- !Array.isArray(get(control._fields, name)) &&
2740
- set(control._fields, name, undefined);
2741
- control._setFieldArray(name, updatedFieldArrayValues, removeArrayAt, {
2742
- argA: index,
2974
+ const handleSubmit = (onValid, onInvalid) => async (e) => {
2975
+ let onValidError = undefined;
2976
+ if (e) {
2977
+ e.preventDefault && e.preventDefault();
2978
+ e.persist &&
2979
+ e.persist();
2980
+ }
2981
+ let fieldValues = cloneObject(_formValues);
2982
+ _subjects.state.next({
2983
+ isSubmitting: true,
2743
2984
  });
2744
- };
2745
- const insert$1 = (index, value, options) => {
2746
- const insertValue = convertToArrayPayload(cloneObject(value));
2747
- const updatedFieldArrayValues = insert(control._getFieldArray(name), index, insertValue);
2748
- control._names.focus = getFocusFieldName(name, index, options);
2749
- ids.current = insert(ids.current, index, insertValue.map(generateId));
2750
- updateValues(updatedFieldArrayValues);
2751
- setFields(updatedFieldArrayValues);
2752
- control._setFieldArray(name, updatedFieldArrayValues, insert, {
2753
- argA: index,
2754
- argB: fillEmptyArray(value),
2985
+ if (_options.resolver) {
2986
+ const { errors, values } = await _runSchema();
2987
+ _updateIsValidating();
2988
+ _formState.errors = errors;
2989
+ fieldValues = cloneObject(values);
2990
+ }
2991
+ else {
2992
+ await executeBuiltInValidation({
2993
+ fields: _fields,
2994
+ eventType: EVENTS.SUBMIT,
2995
+ });
2996
+ }
2997
+ if (_names.disabled.size) {
2998
+ for (const name of _names.disabled) {
2999
+ unset(fieldValues, name);
3000
+ }
3001
+ }
3002
+ unset(_formState.errors, ROOT_ERROR_TYPE);
3003
+ if (isEmptyObject(_formState.errors)) {
3004
+ _subjects.state.next({
3005
+ errors: {},
3006
+ });
3007
+ try {
3008
+ await onValid(fieldValues, e);
3009
+ }
3010
+ catch (error) {
3011
+ onValidError = error;
3012
+ }
3013
+ }
3014
+ else {
3015
+ if (onInvalid) {
3016
+ await onInvalid({ ..._formState.errors }, e);
3017
+ }
3018
+ _focusError();
3019
+ setTimeout(_focusError);
3020
+ }
3021
+ _subjects.state.next({
3022
+ isSubmitted: true,
3023
+ isSubmitting: false,
3024
+ isSubmitSuccessful: isEmptyObject(_formState.errors) && !onValidError,
3025
+ submitCount: _formState.submitCount + 1,
3026
+ errors: _formState.errors,
2755
3027
  });
3028
+ if (onValidError) {
3029
+ throw onValidError;
3030
+ }
2756
3031
  };
2757
- const swap = (indexA, indexB) => {
2758
- const updatedFieldArrayValues = control._getFieldArray(name);
2759
- swapArrayAt(updatedFieldArrayValues, indexA, indexB);
2760
- swapArrayAt(ids.current, indexA, indexB);
2761
- updateValues(updatedFieldArrayValues);
2762
- setFields(updatedFieldArrayValues);
2763
- control._setFieldArray(name, updatedFieldArrayValues, swapArrayAt, {
2764
- argA: indexA,
2765
- argB: indexB,
2766
- }, false);
2767
- };
2768
- const move = (from, to) => {
2769
- const updatedFieldArrayValues = control._getFieldArray(name);
2770
- moveArrayAt(updatedFieldArrayValues, from, to);
2771
- moveArrayAt(ids.current, from, to);
2772
- updateValues(updatedFieldArrayValues);
2773
- setFields(updatedFieldArrayValues);
2774
- control._setFieldArray(name, updatedFieldArrayValues, moveArrayAt, {
2775
- argA: from,
2776
- argB: to,
2777
- }, false);
2778
- };
2779
- const update = (index, value) => {
2780
- const updateValue = cloneObject(value);
2781
- const updatedFieldArrayValues = updateAt(control._getFieldArray(name), index, updateValue);
2782
- ids.current = [...updatedFieldArrayValues].map((item, i) => !item || i === index ? generateId() : ids.current[i]);
2783
- updateValues(updatedFieldArrayValues);
2784
- setFields([...updatedFieldArrayValues]);
2785
- control._setFieldArray(name, updatedFieldArrayValues, updateAt, {
2786
- argA: index,
2787
- argB: updateValue,
2788
- }, true, false);
2789
- };
2790
- const replace = (value) => {
2791
- const updatedFieldArrayValues = convertToArrayPayload(cloneObject(value));
2792
- ids.current = updatedFieldArrayValues.map(generateId);
2793
- updateValues([...updatedFieldArrayValues]);
2794
- setFields([...updatedFieldArrayValues]);
2795
- control._setFieldArray(name, [...updatedFieldArrayValues], (data) => data, {}, true, false);
3032
+ const resetField = (name, options = {}) => {
3033
+ if (get(_fields, name)) {
3034
+ if (isUndefined(options.defaultValue)) {
3035
+ setValue(name, cloneObject(get(_defaultValues, name)));
3036
+ }
3037
+ else {
3038
+ setValue(name, options.defaultValue);
3039
+ set(_defaultValues, name, cloneObject(options.defaultValue));
3040
+ }
3041
+ if (!options.keepTouched) {
3042
+ unset(_formState.touchedFields, name);
3043
+ }
3044
+ if (!options.keepDirty) {
3045
+ unset(_formState.dirtyFields, name);
3046
+ _formState.isDirty = options.defaultValue
3047
+ ? _getDirty(name, cloneObject(get(_defaultValues, name)))
3048
+ : _getDirty();
3049
+ }
3050
+ if (!options.keepError) {
3051
+ unset(_formState.errors, name);
3052
+ _proxyFormState.isValid && _setValid();
3053
+ }
3054
+ _subjects.state.next({ ..._formState });
3055
+ }
2796
3056
  };
2797
- React.useEffect(() => {
2798
- control._state.action = false;
2799
- isWatched(name, control._names) &&
2800
- control._subjects.state.next({
2801
- ...control._formState,
2802
- });
2803
- if (_actioned.current &&
2804
- (!getValidationModes(control._options.mode).isOnSubmit ||
2805
- control._formState.isSubmitted) &&
2806
- !getValidationModes(control._options.reValidateMode).isOnSubmit) {
2807
- if (control._options.resolver) {
2808
- control._runSchema([name]).then((result) => {
2809
- control._updateIsValidating([name]);
2810
- const error = get(result.errors, name);
2811
- const existingError = get(control._formState.errors, name);
2812
- if (existingError
2813
- ? (!error && existingError.type) ||
2814
- (error &&
2815
- (existingError.type !== error.type ||
2816
- existingError.message !== error.message))
2817
- : error && error.type) {
2818
- error
2819
- ? set(control._formState.errors, name, error)
2820
- : unset(control._formState.errors, name);
2821
- control._subjects.state.next({
2822
- errors: control._formState.errors,
2823
- });
3057
+ const _reset = (formValues, keepStateOptions = {}) => {
3058
+ const updatedValues = formValues ? cloneObject(formValues) : _defaultValues;
3059
+ const cloneUpdatedValues = cloneObject(updatedValues);
3060
+ const isEmptyResetValues = isEmptyObject(formValues);
3061
+ const values = cloneUpdatedValues;
3062
+ const fieldRefs = _fields;
3063
+ if (!keepStateOptions.keepDefaultValues) {
3064
+ _defaultValues = updatedValues;
3065
+ }
3066
+ if (!keepStateOptions.keepValues) {
3067
+ if (keepStateOptions.keepDirtyValues) {
3068
+ const fieldsToCheck = new Set([
3069
+ ..._names.mount,
3070
+ ...Object.keys(getDirtyFields(_defaultValues, _formValues, undefined, fieldRefs)),
3071
+ ]);
3072
+ for (const fieldName of Array.from(fieldsToCheck)) {
3073
+ const isDirty = get(_formState.dirtyFields, fieldName);
3074
+ const existingValue = get(_formValues, fieldName);
3075
+ const newValue = get(values, fieldName);
3076
+ if (isDirty && !isUndefined(existingValue)) {
3077
+ set(values, fieldName, existingValue);
2824
3078
  }
2825
- });
3079
+ else if (!isDirty && !isUndefined(newValue)) {
3080
+ setValue(fieldName, newValue);
3081
+ }
3082
+ }
2826
3083
  }
2827
3084
  else {
2828
- const field = get(control._fields, name);
2829
- if (field &&
2830
- field._f &&
2831
- !(getValidationModes(control._options.reValidateMode).isOnSubmit &&
2832
- getValidationModes(control._options.mode).isOnSubmit)) {
2833
- validateField(field, control._names.disabled, control._formValues, control._options.criteriaMode === VALIDATION_MODE.all, control._options.shouldUseNativeValidation, true).then((error) => !isEmptyObject(error) &&
2834
- control._subjects.state.next({
2835
- errors: updateFieldArrayRootError(control._formState.errors, error, name),
2836
- }));
3085
+ if (isWeb && isUndefined(formValues)) {
3086
+ for (const name of _names.mount) {
3087
+ const field = get(_fields, name);
3088
+ if (field && field._f) {
3089
+ const fieldReference = Array.isArray(field._f.refs)
3090
+ ? field._f.refs[0]
3091
+ : field._f.ref;
3092
+ if (isHTMLElement(fieldReference)) {
3093
+ const form = fieldReference.closest('form');
3094
+ if (form) {
3095
+ form.reset();
3096
+ break;
3097
+ }
3098
+ }
3099
+ }
3100
+ }
3101
+ }
3102
+ if (keepStateOptions.keepFieldsRef) {
3103
+ for (const fieldName of _names.mount) {
3104
+ setValue(fieldName, get(values, fieldName));
3105
+ }
3106
+ }
3107
+ else {
3108
+ _fields = {};
2837
3109
  }
2838
3110
  }
2839
- }
2840
- control._subjects.state.next({
2841
- name,
2842
- values: cloneObject(control._formValues),
2843
- });
2844
- control._names.focus &&
2845
- iterateFieldsByAction(control._fields, (ref, key) => {
2846
- if (control._names.focus &&
2847
- key.startsWith(control._names.focus) &&
2848
- ref.focus) {
2849
- ref.focus();
2850
- return 1;
3111
+ if (_options.shouldUnregister) {
3112
+ _formValues = keepStateOptions.keepDefaultValues
3113
+ ? cloneObject(_defaultValues)
3114
+ : {};
3115
+ if (keepStateOptions.keepFieldsRef) {
3116
+ for (const fieldName of _names.mount) {
3117
+ set(_formValues, fieldName, get(values, fieldName));
3118
+ }
2851
3119
  }
2852
- return;
3120
+ }
3121
+ else {
3122
+ _formValues = cloneObject(values);
3123
+ }
3124
+ _subjects.array.next({
3125
+ values: { ...values },
2853
3126
  });
2854
- control._names.focus = '';
2855
- control._setValid();
2856
- _actioned.current = false;
2857
- }, [fields, name, control]);
2858
- React.useEffect(() => {
2859
- !get(control._formValues, name) && control._setFieldArray(name);
2860
- return () => {
2861
- const updateMounted = (name, value) => {
2862
- const field = get(control._fields, name);
2863
- if (field && field._f) {
2864
- field._f.mount = value;
2865
- }
2866
- };
2867
- control._options.shouldUnregister || shouldUnregister
2868
- ? control.unregister(name)
2869
- : updateMounted(name, false);
3127
+ _subjects.state.next({
3128
+ name: undefined,
3129
+ type: undefined,
3130
+ values: { ...values },
3131
+ });
3132
+ }
3133
+ _names = {
3134
+ mount: keepStateOptions.keepDirtyValues ? _names.mount : new Set(),
3135
+ unMount: new Set(),
3136
+ array: new Set(),
3137
+ registerName: new Set(),
3138
+ disabled: new Set(),
3139
+ watch: new Set(),
3140
+ watchAll: false,
3141
+ focus: '',
3142
+ };
3143
+ _state.mount =
3144
+ !_proxyFormState.isValid ||
3145
+ !!keepStateOptions.keepIsValid ||
3146
+ !!keepStateOptions.keepDirtyValues ||
3147
+ (!_options.shouldUnregister && !isEmptyObject(values));
3148
+ _state.watch = !!_options.shouldUnregister;
3149
+ _state.keepIsValid = !!keepStateOptions.keepIsValid;
3150
+ _state.action = false;
3151
+ if (!keepStateOptions.keepErrors) {
3152
+ _formState.errors = {};
3153
+ }
3154
+ _subjects.state.next({
3155
+ submitCount: keepStateOptions.keepSubmitCount
3156
+ ? _formState.submitCount
3157
+ : 0,
3158
+ isDirty: isEmptyResetValues
3159
+ ? false
3160
+ : keepStateOptions.keepDirty
3161
+ ? _formState.isDirty
3162
+ : keepStateOptions.keepValues
3163
+ ? _getDirty()
3164
+ : !!(keepStateOptions.keepDefaultValues &&
3165
+ !deepEqual(formValues, _defaultValues)),
3166
+ isSubmitted: keepStateOptions.keepIsSubmitted
3167
+ ? _formState.isSubmitted
3168
+ : false,
3169
+ dirtyFields: isEmptyResetValues
3170
+ ? {}
3171
+ : keepStateOptions.keepDirtyValues
3172
+ ? keepStateOptions.keepDefaultValues && _formValues
3173
+ ? getDirtyFields(_defaultValues, _formValues, undefined, fieldRefs)
3174
+ : _formState.dirtyFields
3175
+ : keepStateOptions.keepDefaultValues && formValues
3176
+ ? getDirtyFields(_defaultValues, formValues, undefined, fieldRefs)
3177
+ : keepStateOptions.keepDirty
3178
+ ? _formState.dirtyFields
3179
+ : {},
3180
+ touchedFields: keepStateOptions.keepTouched
3181
+ ? _formState.touchedFields
3182
+ : {},
3183
+ errors: keepStateOptions.keepErrors ? _formState.errors : {},
3184
+ isSubmitSuccessful: keepStateOptions.keepIsSubmitSuccessful
3185
+ ? _formState.isSubmitSuccessful
3186
+ : false,
3187
+ isSubmitting: false,
3188
+ defaultValues: _defaultValues,
3189
+ });
3190
+ };
3191
+ const reset = (formValues, keepStateOptions) => _reset(isFunction(formValues)
3192
+ ? formValues(_formValues)
3193
+ : formValues, { ..._options.resetOptions, ...keepStateOptions });
3194
+ const setFocus = (name, options = {}) => {
3195
+ const field = get(_fields, name);
3196
+ const fieldReference = field && field._f;
3197
+ if (fieldReference) {
3198
+ const fieldRef = fieldReference.refs
3199
+ ? fieldReference.refs[0]
3200
+ : fieldReference.ref;
3201
+ if (fieldRef.focus) {
3202
+ setTimeout(() => {
3203
+ fieldRef.focus();
3204
+ options.shouldSelect &&
3205
+ isFunction(fieldRef.select) &&
3206
+ fieldRef.select();
3207
+ });
3208
+ }
3209
+ }
3210
+ };
3211
+ const _setFormState = (updatedFormState) => {
3212
+ // `name`, `type`, and `values` describe the event that produced this
3213
+ // update, not the form's persisted state (they aren't part of
3214
+ // `FormState`). Merging them in would leak a stale `name`/`type` from
3215
+ // one event into a later, unrelated notification that doesn't specify
3216
+ // its own.
3217
+ const { name, type, values, ...formState } = updatedFormState;
3218
+ _formState = {
3219
+ ..._formState,
3220
+ ...formState,
2870
3221
  };
2871
- }, [name, control, keyName, shouldUnregister]);
3222
+ };
3223
+ const _resetDefaultValues = () => isFunction(_options.defaultValues) &&
3224
+ _options.defaultValues().then((values) => {
3225
+ reset(values, _options.resetOptions);
3226
+ _subjects.state.next({
3227
+ isLoading: false,
3228
+ });
3229
+ });
3230
+ const resetDefaultValues = (values, options = {}) => {
3231
+ _defaultValues = cloneObject(values);
3232
+ if (!options.keepDirty) {
3233
+ const newDirtyFields = getDirtyFields(_defaultValues, _formValues, undefined, _fields);
3234
+ _formState.dirtyFields = newDirtyFields;
3235
+ _formState.isDirty = !isEmptyObject(newDirtyFields);
3236
+ }
3237
+ if (!options.keepIsValid) {
3238
+ _setValid();
3239
+ }
3240
+ _subjects.state.next({
3241
+ ..._formState,
3242
+ defaultValues: _defaultValues,
3243
+ });
3244
+ };
3245
+ const methods = {
3246
+ control: {
3247
+ register,
3248
+ unregister,
3249
+ getFieldState,
3250
+ handleSubmit,
3251
+ setError,
3252
+ _subscribe,
3253
+ _runSchema,
3254
+ _updateIsValidating,
3255
+ _focusError,
3256
+ _getWatch,
3257
+ _getDirty,
3258
+ _setValid,
3259
+ _setFieldArray,
3260
+ _setDisabledField,
3261
+ _setErrors,
3262
+ _getFieldArray,
3263
+ _reset,
3264
+ _resetDefaultValues,
3265
+ _removeUnmounted,
3266
+ _disableForm,
3267
+ _subjects,
3268
+ _proxyFormState,
3269
+ get _fields() {
3270
+ return _fields;
3271
+ },
3272
+ get _formValues() {
3273
+ return _formValues;
3274
+ },
3275
+ get _state() {
3276
+ return _state;
3277
+ },
3278
+ set _state(value) {
3279
+ _state = value;
3280
+ },
3281
+ get _defaultValues() {
3282
+ return _defaultValues;
3283
+ },
3284
+ get _names() {
3285
+ return _names;
3286
+ },
3287
+ set _names(value) {
3288
+ _names = value;
3289
+ },
3290
+ get _formState() {
3291
+ return _formState;
3292
+ },
3293
+ get _options() {
3294
+ return _options;
3295
+ },
3296
+ set _options(value) {
3297
+ _options = {
3298
+ ..._options,
3299
+ ...value,
3300
+ };
3301
+ _validationModeBeforeSubmit = getValidationModes(_options.mode);
3302
+ _validationModeAfterSubmit = getValidationModes(_options.reValidateMode);
3303
+ },
3304
+ },
3305
+ subscribe,
3306
+ trigger,
3307
+ register,
3308
+ handleSubmit,
3309
+ watch,
3310
+ setValue,
3311
+ setValues,
3312
+ getValues,
3313
+ reset,
3314
+ resetField,
3315
+ resetDefaultValues,
3316
+ clearErrors,
3317
+ unregister,
3318
+ setError,
3319
+ setFocus,
3320
+ getFieldState,
3321
+ };
2872
3322
  return {
2873
- swap: React.useCallback(swap, [updateValues, name, control]),
2874
- move: React.useCallback(move, [updateValues, name, control]),
2875
- prepend: React.useCallback(prepend, [updateValues, name, control]),
2876
- append: React.useCallback(append, [updateValues, name, control]),
2877
- remove: React.useCallback(remove, [updateValues, name, control]),
2878
- insert: React.useCallback(insert$1, [updateValues, name, control]),
2879
- update: React.useCallback(update, [updateValues, name, control]),
2880
- replace: React.useCallback(replace, [updateValues, name, control]),
2881
- fields: React.useMemo(() => fields.map((field, index) => ({
2882
- ...field,
2883
- [keyName]: ids.current[index] || generateId(),
2884
- })), [fields, keyName]),
3323
+ ...methods,
3324
+ formControl: methods,
2885
3325
  };
2886
3326
  }
2887
3327
 
@@ -2917,26 +3357,19 @@ function useFieldArray(props) {
2917
3357
  function useForm(props = {}) {
2918
3358
  const _formControl = React.useRef(undefined);
2919
3359
  const _values = React.useRef(undefined);
2920
- const [formState, updateFormState] = React.useState({
2921
- isDirty: false,
2922
- isValidating: false,
3360
+ const _formControlProp = React.useRef(props.formControl);
3361
+ const [formState, updateFormState] = React.useState(() => ({
3362
+ ...cloneObject(DEFAULT_FORM_STATE),
2923
3363
  isLoading: isFunction(props.defaultValues),
2924
- isSubmitted: false,
2925
- isSubmitting: false,
2926
- isSubmitSuccessful: false,
2927
- isValid: false,
2928
- submitCount: 0,
2929
- dirtyFields: {},
2930
- touchedFields: {},
2931
- validatingFields: {},
2932
3364
  errors: props.errors || {},
2933
3365
  disabled: props.disabled || false,
2934
- isReady: false,
2935
3366
  defaultValues: isFunction(props.defaultValues)
2936
3367
  ? undefined
2937
3368
  : props.defaultValues,
2938
- });
2939
- if (!_formControl.current) {
3369
+ }));
3370
+ if (!_formControl.current ||
3371
+ (props.formControl && _formControlProp.current !== props.formControl)) {
3372
+ _formControlProp.current = props.formControl;
2940
3373
  if (props.formControl) {
2941
3374
  _formControl.current = {
2942
3375
  ...props.formControl,
@@ -2959,7 +3392,10 @@ function useForm(props = {}) {
2959
3392
  useIsomorphicLayoutEffect(() => {
2960
3393
  const sub = control._subscribe({
2961
3394
  formState: control._proxyFormState,
2962
- callback: () => updateFormState({ ...control._formState }),
3395
+ callback: () => updateFormState({
3396
+ ...control._formState,
3397
+ defaultValues: control._defaultValues,
3398
+ }),
2963
3399
  reRenderRoot: true,
2964
3400
  });
2965
3401
  updateFormState((data) => ({
@@ -3060,5 +3496,5 @@ function useForm(props = {}) {
3060
3496
  */
3061
3497
  const Watch = (props) => props.render(useWatch({ name: props.names, ...props }));
3062
3498
 
3063
- export { Controller, Form, FormProvider, FormStateSubscribe, Watch, appendErrors, createFormControl, get, set, useController, useFieldArray, useForm, useFormContext, useFormState, useWatch };
3499
+ export { Controller, FieldArray, Form, FormProvider, FormStateSubscribe, Watch, appendErrors, createFormControl, get, set, useController, useFieldArray, useForm, useFormContext, useFormState, useWatch };
3064
3500
  //# sourceMappingURL=index.esm.mjs.map