@rezi-ui/core 0.1.0-alpha.60 → 0.1.0-alpha.63

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 (345) hide show
  1. package/dist/app/createApp/breadcrumbs.d.ts +38 -0
  2. package/dist/app/createApp/breadcrumbs.d.ts.map +1 -0
  3. package/dist/app/createApp/breadcrumbs.js +65 -0
  4. package/dist/app/createApp/breadcrumbs.js.map +1 -0
  5. package/dist/app/createApp/config.d.ts +25 -0
  6. package/dist/app/createApp/config.d.ts.map +1 -0
  7. package/dist/app/createApp/config.js +130 -0
  8. package/dist/app/createApp/config.js.map +1 -0
  9. package/dist/app/createApp/eventLoop.d.ts +95 -0
  10. package/dist/app/createApp/eventLoop.d.ts.map +1 -0
  11. package/dist/app/createApp/eventLoop.js +384 -0
  12. package/dist/app/createApp/eventLoop.js.map +1 -0
  13. package/dist/app/createApp/guards.d.ts +21 -0
  14. package/dist/app/createApp/guards.d.ts.map +1 -0
  15. package/dist/app/createApp/guards.js +54 -0
  16. package/dist/app/createApp/guards.js.map +1 -0
  17. package/dist/app/createApp/keybindings.d.ts +28 -0
  18. package/dist/app/createApp/keybindings.d.ts.map +1 -0
  19. package/dist/app/createApp/keybindings.js +113 -0
  20. package/dist/app/createApp/keybindings.js.map +1 -0
  21. package/dist/app/createApp/renderLoop.d.ts +64 -0
  22. package/dist/app/createApp/renderLoop.d.ts.map +1 -0
  23. package/dist/app/createApp/renderLoop.js +305 -0
  24. package/dist/app/createApp/renderLoop.js.map +1 -0
  25. package/dist/app/createApp.d.ts +3 -39
  26. package/dist/app/createApp.d.ts.map +1 -1
  27. package/dist/app/createApp.js +403 -1205
  28. package/dist/app/createApp.js.map +1 -1
  29. package/dist/app/widgetRenderer/constraintState.d.ts +98 -0
  30. package/dist/app/widgetRenderer/constraintState.d.ts.map +1 -0
  31. package/dist/app/widgetRenderer/constraintState.js +563 -0
  32. package/dist/app/widgetRenderer/constraintState.js.map +1 -0
  33. package/dist/app/widgetRenderer/fileNodeCache.d.ts +2 -0
  34. package/dist/app/widgetRenderer/fileNodeCache.d.ts.map +1 -1
  35. package/dist/app/widgetRenderer/fileNodeCache.js +31 -0
  36. package/dist/app/widgetRenderer/fileNodeCache.js.map +1 -1
  37. package/dist/app/widgetRenderer/filePickerRouting.d.ts +12 -1
  38. package/dist/app/widgetRenderer/filePickerRouting.d.ts.map +1 -1
  39. package/dist/app/widgetRenderer/filePickerRouting.js +63 -14
  40. package/dist/app/widgetRenderer/filePickerRouting.js.map +1 -1
  41. package/dist/app/widgetRenderer/focusState.d.ts +46 -0
  42. package/dist/app/widgetRenderer/focusState.d.ts.map +1 -0
  43. package/dist/app/widgetRenderer/focusState.js +122 -0
  44. package/dist/app/widgetRenderer/focusState.js.map +1 -0
  45. package/dist/app/widgetRenderer/keyboardRouting.d.ts.map +1 -1
  46. package/dist/app/widgetRenderer/keyboardRouting.js.map +1 -1
  47. package/dist/app/widgetRenderer/mouseRouting.d.ts +5 -0
  48. package/dist/app/widgetRenderer/mouseRouting.d.ts.map +1 -1
  49. package/dist/app/widgetRenderer/mouseRouting.js +78 -8
  50. package/dist/app/widgetRenderer/mouseRouting.js.map +1 -1
  51. package/dist/app/widgetRenderer/overlayShortcuts.d.ts.map +1 -1
  52. package/dist/app/widgetRenderer/overlayShortcuts.js +14 -4
  53. package/dist/app/widgetRenderer/overlayShortcuts.js.map +1 -1
  54. package/dist/app/widgetRenderer/overlayState.d.ts +198 -0
  55. package/dist/app/widgetRenderer/overlayState.d.ts.map +1 -0
  56. package/dist/app/widgetRenderer/overlayState.js +590 -0
  57. package/dist/app/widgetRenderer/overlayState.js.map +1 -0
  58. package/dist/app/widgetRenderer/routeEngineEvent.d.ts +189 -0
  59. package/dist/app/widgetRenderer/routeEngineEvent.d.ts.map +1 -0
  60. package/dist/app/widgetRenderer/routeEngineEvent.js +527 -0
  61. package/dist/app/widgetRenderer/routeEngineEvent.js.map +1 -0
  62. package/dist/app/widgetRenderer.d.ts +2 -1
  63. package/dist/app/widgetRenderer.d.ts.map +1 -1
  64. package/dist/app/widgetRenderer.js +334 -1707
  65. package/dist/app/widgetRenderer.js.map +1 -1
  66. package/dist/forms/internal/arrayState.d.ts +35 -0
  67. package/dist/forms/internal/arrayState.d.ts.map +1 -0
  68. package/dist/forms/internal/arrayState.js +238 -0
  69. package/dist/forms/internal/arrayState.js.map +1 -0
  70. package/dist/forms/internal/bindings.d.ts +46 -0
  71. package/dist/forms/internal/bindings.d.ts.map +1 -0
  72. package/dist/forms/internal/bindings.js +161 -0
  73. package/dist/forms/internal/bindings.js.map +1 -0
  74. package/dist/forms/internal/dev.d.ts +4 -0
  75. package/dist/forms/internal/dev.d.ts.map +1 -0
  76. package/dist/forms/internal/dev.js +21 -0
  77. package/dist/forms/internal/dev.js.map +1 -0
  78. package/dist/forms/internal/state.d.ts +52 -0
  79. package/dist/forms/internal/state.d.ts.map +1 -0
  80. package/dist/forms/internal/state.js +240 -0
  81. package/dist/forms/internal/state.js.map +1 -0
  82. package/dist/forms/internal/submit.d.ts +43 -0
  83. package/dist/forms/internal/submit.d.ts.map +1 -0
  84. package/dist/forms/internal/submit.js +165 -0
  85. package/dist/forms/internal/submit.js.map +1 -0
  86. package/dist/forms/internal/wizard.d.ts +53 -0
  87. package/dist/forms/internal/wizard.d.ts.map +1 -0
  88. package/dist/forms/internal/wizard.js +311 -0
  89. package/dist/forms/internal/wizard.js.map +1 -0
  90. package/dist/forms/useForm.d.ts.map +1 -1
  91. package/dist/forms/useForm.js +90 -1117
  92. package/dist/forms/useForm.js.map +1 -1
  93. package/dist/index.d.ts +1 -1
  94. package/dist/index.d.ts.map +1 -1
  95. package/dist/index.js +1 -1
  96. package/dist/index.js.map +1 -1
  97. package/dist/keybindings/manager.d.ts.map +1 -1
  98. package/dist/keybindings/manager.js.map +1 -1
  99. package/dist/keybindings/parser.d.ts.map +1 -1
  100. package/dist/keybindings/parser.js +10 -5
  101. package/dist/keybindings/parser.js.map +1 -1
  102. package/dist/layout/dropdownGeometry.d.ts +8 -0
  103. package/dist/layout/dropdownGeometry.d.ts.map +1 -1
  104. package/dist/layout/dropdownGeometry.js +40 -0
  105. package/dist/layout/dropdownGeometry.js.map +1 -1
  106. package/dist/layout/engine/layoutEngine.js +1 -1
  107. package/dist/layout/engine/layoutEngine.js.map +1 -1
  108. package/dist/layout/kinds/overlays.d.ts.map +1 -1
  109. package/dist/layout/kinds/stack.d.ts +1 -3
  110. package/dist/layout/kinds/stack.d.ts.map +1 -1
  111. package/dist/layout/kinds/stack.js +11 -1523
  112. package/dist/layout/kinds/stack.js.map +1 -1
  113. package/dist/layout/kinds/stackParts/axis.d.ts +32 -0
  114. package/dist/layout/kinds/stackParts/axis.d.ts.map +1 -0
  115. package/dist/layout/kinds/stackParts/axis.js +61 -0
  116. package/dist/layout/kinds/stackParts/axis.js.map +1 -0
  117. package/dist/layout/kinds/stackParts/constraintPlan.d.ts +18 -0
  118. package/dist/layout/kinds/stackParts/constraintPlan.d.ts.map +1 -0
  119. package/dist/layout/kinds/stackParts/constraintPlan.js +434 -0
  120. package/dist/layout/kinds/stackParts/constraintPlan.js.map +1 -0
  121. package/dist/layout/kinds/stackParts/layout.d.ts +6 -0
  122. package/dist/layout/kinds/stackParts/layout.d.ts.map +1 -0
  123. package/dist/layout/kinds/stackParts/layout.js +376 -0
  124. package/dist/layout/kinds/stackParts/layout.js.map +1 -0
  125. package/dist/layout/kinds/stackParts/measure.d.ts +6 -0
  126. package/dist/layout/kinds/stackParts/measure.d.ts.map +1 -0
  127. package/dist/layout/kinds/stackParts/measure.js +212 -0
  128. package/dist/layout/kinds/stackParts/measure.js.map +1 -0
  129. package/dist/layout/kinds/stackParts/shared.d.ts +31 -0
  130. package/dist/layout/kinds/stackParts/shared.d.ts.map +1 -0
  131. package/dist/layout/kinds/stackParts/shared.js +94 -0
  132. package/dist/layout/kinds/stackParts/shared.js.map +1 -0
  133. package/dist/layout/kinds/stackParts/wrap.d.ts +26 -0
  134. package/dist/layout/kinds/stackParts/wrap.d.ts.map +1 -0
  135. package/dist/layout/kinds/stackParts/wrap.js +374 -0
  136. package/dist/layout/kinds/stackParts/wrap.js.map +1 -0
  137. package/dist/layout/validate/interactive.d.ts +106 -0
  138. package/dist/layout/validate/interactive.d.ts.map +1 -0
  139. package/dist/layout/validate/interactive.js +430 -0
  140. package/dist/layout/validate/interactive.js.map +1 -0
  141. package/dist/layout/validate/layoutConstraints.d.ts +51 -0
  142. package/dist/layout/validate/layoutConstraints.d.ts.map +1 -0
  143. package/dist/layout/validate/layoutConstraints.js +100 -0
  144. package/dist/layout/validate/layoutConstraints.js.map +1 -0
  145. package/dist/layout/validate/primitives.d.ts +31 -0
  146. package/dist/layout/validate/primitives.d.ts.map +1 -0
  147. package/dist/layout/validate/primitives.js +299 -0
  148. package/dist/layout/validate/primitives.js.map +1 -0
  149. package/dist/layout/validate/shared.d.ts +23 -0
  150. package/dist/layout/validate/shared.d.ts.map +1 -0
  151. package/dist/layout/validate/shared.js +32 -0
  152. package/dist/layout/validate/shared.js.map +1 -0
  153. package/dist/layout/validate/spacing.d.ts +21 -0
  154. package/dist/layout/validate/spacing.d.ts.map +1 -0
  155. package/dist/layout/validate/spacing.js +33 -0
  156. package/dist/layout/validate/spacing.js.map +1 -0
  157. package/dist/layout/validateProps.d.ts +5 -159
  158. package/dist/layout/validateProps.d.ts.map +1 -1
  159. package/dist/layout/validateProps.js +1 -832
  160. package/dist/layout/validateProps.js.map +1 -1
  161. package/dist/pipeline.js +1 -1
  162. package/dist/pipeline.js.map +1 -1
  163. package/dist/renderer/renderToDrawlist/renderTree.d.ts +1 -1
  164. package/dist/renderer/renderToDrawlist/renderTree.d.ts.map +1 -1
  165. package/dist/renderer/renderToDrawlist/renderTree.js +3 -3
  166. package/dist/renderer/renderToDrawlist/renderTree.js.map +1 -1
  167. package/dist/renderer/renderToDrawlist/types.d.ts +2 -0
  168. package/dist/renderer/renderToDrawlist/types.d.ts.map +1 -1
  169. package/dist/renderer/renderToDrawlist/widgets/containers.d.ts.map +1 -1
  170. package/dist/renderer/renderToDrawlist/widgets/containers.js +1 -1
  171. package/dist/renderer/renderToDrawlist/widgets/containers.js.map +1 -1
  172. package/dist/renderer/renderToDrawlist/widgets/files.d.ts +2 -1
  173. package/dist/renderer/renderToDrawlist/widgets/files.d.ts.map +1 -1
  174. package/dist/renderer/renderToDrawlist/widgets/files.js +30 -3
  175. package/dist/renderer/renderToDrawlist/widgets/files.js.map +1 -1
  176. package/dist/renderer/renderToDrawlist/widgets/overlays.d.ts +1 -1
  177. package/dist/renderer/renderToDrawlist/widgets/overlays.d.ts.map +1 -1
  178. package/dist/renderer/renderToDrawlist/widgets/overlays.js +26 -6
  179. package/dist/renderer/renderToDrawlist/widgets/overlays.js.map +1 -1
  180. package/dist/renderer/renderToDrawlist/widgets/renderFormWidgets.d.ts.map +1 -1
  181. package/dist/renderer/renderToDrawlist/widgets/renderFormWidgets.js +52 -18
  182. package/dist/renderer/renderToDrawlist/widgets/renderFormWidgets.js.map +1 -1
  183. package/dist/renderer/renderToDrawlist.d.ts +0 -8
  184. package/dist/renderer/renderToDrawlist.d.ts.map +1 -1
  185. package/dist/renderer/renderToDrawlist.js +1 -9
  186. package/dist/renderer/renderToDrawlist.js.map +1 -1
  187. package/dist/runtime/commit/composite.d.ts +11 -0
  188. package/dist/runtime/commit/composite.d.ts.map +1 -0
  189. package/dist/runtime/commit/composite.js +238 -0
  190. package/dist/runtime/commit/composite.js.map +1 -0
  191. package/dist/runtime/commit/container.d.ts +7 -0
  192. package/dist/runtime/commit/container.d.ts.map +1 -0
  193. package/dist/runtime/commit/container.js +350 -0
  194. package/dist/runtime/commit/container.js.map +1 -0
  195. package/dist/runtime/commit/equality.d.ts +20 -0
  196. package/dist/runtime/commit/equality.d.ts.map +1 -0
  197. package/dist/runtime/commit/equality.js +436 -0
  198. package/dist/runtime/commit/equality.js.map +1 -0
  199. package/dist/runtime/commit/errorBoundary.d.ts +7 -0
  200. package/dist/runtime/commit/errorBoundary.d.ts.map +1 -0
  201. package/dist/runtime/commit/errorBoundary.js +53 -0
  202. package/dist/runtime/commit/errorBoundary.js.map +1 -0
  203. package/dist/runtime/commit/shared.d.ts +138 -0
  204. package/dist/runtime/commit/shared.d.ts.map +1 -0
  205. package/dist/runtime/commit/shared.js +11 -0
  206. package/dist/runtime/commit/shared.js.map +1 -0
  207. package/dist/runtime/commit/transitions.d.ts +9 -0
  208. package/dist/runtime/commit/transitions.d.ts.map +1 -0
  209. package/dist/runtime/commit/transitions.js +93 -0
  210. package/dist/runtime/commit/transitions.js.map +1 -0
  211. package/dist/runtime/commit/validation.d.ts +16 -0
  212. package/dist/runtime/commit/validation.d.ts.map +1 -0
  213. package/dist/runtime/commit/validation.js +157 -0
  214. package/dist/runtime/commit/validation.js.map +1 -0
  215. package/dist/runtime/commit.d.ts +7 -117
  216. package/dist/runtime/commit.d.ts.map +1 -1
  217. package/dist/runtime/commit.js +13 -1394
  218. package/dist/runtime/commit.js.map +1 -1
  219. package/dist/runtime/localState.d.ts +4 -0
  220. package/dist/runtime/localState.d.ts.map +1 -1
  221. package/dist/runtime/localState.js.map +1 -1
  222. package/dist/runtime/widgetMeta/collector.d.ts +77 -0
  223. package/dist/runtime/widgetMeta/collector.d.ts.map +1 -0
  224. package/dist/runtime/widgetMeta/collector.js +293 -0
  225. package/dist/runtime/widgetMeta/collector.js.map +1 -0
  226. package/dist/runtime/widgetMeta/focusContainers.d.ts +44 -0
  227. package/dist/runtime/widgetMeta/focusContainers.d.ts.map +1 -0
  228. package/dist/runtime/widgetMeta/focusContainers.js +190 -0
  229. package/dist/runtime/widgetMeta/focusContainers.js.map +1 -0
  230. package/dist/runtime/widgetMeta/focusInfo.d.ts +19 -0
  231. package/dist/runtime/widgetMeta/focusInfo.d.ts.map +1 -0
  232. package/dist/runtime/widgetMeta/focusInfo.js +172 -0
  233. package/dist/runtime/widgetMeta/focusInfo.js.map +1 -0
  234. package/dist/runtime/widgetMeta/helpers.d.ts +47 -0
  235. package/dist/runtime/widgetMeta/helpers.d.ts.map +1 -0
  236. package/dist/runtime/widgetMeta/helpers.js +182 -0
  237. package/dist/runtime/widgetMeta/helpers.js.map +1 -0
  238. package/dist/runtime/widgetMeta.d.ts +12 -175
  239. package/dist/runtime/widgetMeta.d.ts.map +1 -1
  240. package/dist/runtime/widgetMeta.js +6 -847
  241. package/dist/runtime/widgetMeta.js.map +1 -1
  242. package/dist/ui/capabilities.d.ts.map +1 -1
  243. package/dist/ui/designTokens.d.ts.map +1 -1
  244. package/dist/widgets/accordion.d.ts.map +1 -1
  245. package/dist/widgets/accordion.js +8 -13
  246. package/dist/widgets/accordion.js.map +1 -1
  247. package/dist/widgets/factories/advanced.d.ts +20 -0
  248. package/dist/widgets/factories/advanced.d.ts.map +1 -0
  249. package/dist/widgets/factories/advanced.js +75 -0
  250. package/dist/widgets/factories/advanced.js.map +1 -0
  251. package/dist/widgets/factories/basic.d.ts +14 -0
  252. package/dist/widgets/factories/basic.d.ts.map +1 -0
  253. package/dist/widgets/factories/basic.js +44 -0
  254. package/dist/widgets/factories/basic.js.map +1 -0
  255. package/dist/widgets/factories/feedback.d.ts +20 -0
  256. package/dist/widgets/factories/feedback.d.ts.map +1 -0
  257. package/dist/widgets/factories/feedback.js +102 -0
  258. package/dist/widgets/factories/feedback.js.map +1 -0
  259. package/dist/widgets/factories/helpers.d.ts +41 -0
  260. package/dist/widgets/factories/helpers.d.ts.map +1 -0
  261. package/dist/widgets/factories/helpers.js +72 -0
  262. package/dist/widgets/factories/helpers.js.map +1 -0
  263. package/dist/widgets/factories/interactive.d.ts +15 -0
  264. package/dist/widgets/factories/interactive.d.ts.map +1 -0
  265. package/dist/widgets/factories/interactive.js +46 -0
  266. package/dist/widgets/factories/interactive.js.map +1 -0
  267. package/dist/widgets/factories/layoutShell.d.ts +22 -0
  268. package/dist/widgets/factories/layoutShell.d.ts.map +1 -0
  269. package/dist/widgets/factories/layoutShell.js +190 -0
  270. package/dist/widgets/factories/layoutShell.js.map +1 -0
  271. package/dist/widgets/factories/media.d.ts +14 -0
  272. package/dist/widgets/factories/media.d.ts.map +1 -0
  273. package/dist/widgets/factories/media.js +25 -0
  274. package/dist/widgets/factories/media.js.map +1 -0
  275. package/dist/widgets/factories/navigation.d.ts +10 -0
  276. package/dist/widgets/factories/navigation.d.ts.map +1 -0
  277. package/dist/widgets/factories/navigation.js +24 -0
  278. package/dist/widgets/factories/navigation.js.map +1 -0
  279. package/dist/widgets/field.d.ts +6 -1
  280. package/dist/widgets/field.d.ts.map +1 -1
  281. package/dist/widgets/field.js +8 -2
  282. package/dist/widgets/field.js.map +1 -1
  283. package/dist/widgets/filePicker.d.ts +5 -0
  284. package/dist/widgets/filePicker.d.ts.map +1 -0
  285. package/dist/widgets/filePicker.js +136 -0
  286. package/dist/widgets/filePicker.js.map +1 -0
  287. package/dist/widgets/protocol.d.ts +0 -6
  288. package/dist/widgets/protocol.d.ts.map +1 -1
  289. package/dist/widgets/protocol.js +0 -6
  290. package/dist/widgets/protocol.js.map +1 -1
  291. package/dist/widgets/select.js +1 -1
  292. package/dist/widgets/select.js.map +1 -1
  293. package/dist/widgets/splitPane.d.ts.map +1 -1
  294. package/dist/widgets/splitPane.js.map +1 -1
  295. package/dist/widgets/table.d.ts.map +1 -1
  296. package/dist/widgets/table.js +43 -1
  297. package/dist/widgets/table.js.map +1 -1
  298. package/dist/widgets/tree.d.ts.map +1 -1
  299. package/dist/widgets/types/advanced.d.ts +611 -0
  300. package/dist/widgets/types/advanced.d.ts.map +1 -0
  301. package/dist/widgets/types/advanced.js +2 -0
  302. package/dist/widgets/types/advanced.js.map +1 -0
  303. package/dist/widgets/types/base.d.ts +933 -0
  304. package/dist/widgets/types/base.d.ts.map +1 -0
  305. package/dist/widgets/types/base.js +2 -0
  306. package/dist/widgets/types/base.js.map +1 -0
  307. package/dist/widgets/types/forms.d.ts +136 -0
  308. package/dist/widgets/types/forms.d.ts.map +1 -0
  309. package/dist/widgets/types/forms.js +2 -0
  310. package/dist/widgets/types/forms.js.map +1 -0
  311. package/dist/widgets/types/navigation.d.ts +83 -0
  312. package/dist/widgets/types/navigation.d.ts.map +1 -0
  313. package/dist/widgets/types/navigation.js +2 -0
  314. package/dist/widgets/types/navigation.js.map +1 -0
  315. package/dist/widgets/types/overlaysShell.d.ts +223 -0
  316. package/dist/widgets/types/overlaysShell.d.ts.map +1 -0
  317. package/dist/widgets/types/overlaysShell.js +2 -0
  318. package/dist/widgets/types/overlaysShell.js.map +1 -0
  319. package/dist/widgets/types/table.d.ts +104 -0
  320. package/dist/widgets/types/table.d.ts.map +1 -0
  321. package/dist/widgets/types/table.js +2 -0
  322. package/dist/widgets/types/table.js.map +1 -0
  323. package/dist/widgets/types/tree.d.ts +64 -0
  324. package/dist/widgets/types/tree.d.ts.map +1 -0
  325. package/dist/widgets/types/tree.js +2 -0
  326. package/dist/widgets/types/tree.js.map +1 -0
  327. package/dist/widgets/types.d.ts +14 -2123
  328. package/dist/widgets/types.d.ts.map +1 -1
  329. package/dist/widgets/ui.d.ts +37 -843
  330. package/dist/widgets/ui.d.ts.map +1 -1
  331. package/dist/widgets/ui.js +37 -1262
  332. package/dist/widgets/ui.js.map +1 -1
  333. package/package.json +2 -2
  334. package/dist/constraints/aggregation.d.ts +0 -17
  335. package/dist/constraints/aggregation.d.ts.map +0 -1
  336. package/dist/constraints/aggregation.js +0 -59
  337. package/dist/constraints/aggregation.js.map +0 -1
  338. package/dist/renderer/renderToDrawlist/overflowCulling.d.ts +0 -3
  339. package/dist/renderer/renderToDrawlist/overflowCulling.d.ts.map +0 -1
  340. package/dist/renderer/renderToDrawlist/overflowCulling.js +0 -81
  341. package/dist/renderer/renderToDrawlist/overflowCulling.js.map +0 -1
  342. package/dist/widgets/tests/protocol.test.d.ts +0 -2
  343. package/dist/widgets/tests/protocol.test.d.ts.map +0 -1
  344. package/dist/widgets/tests/protocol.test.js +0 -120
  345. package/dist/widgets/tests/protocol.test.js.map +0 -1
@@ -7,312 +7,27 @@
7
7
  *
8
8
  * @see docs/recipes/form-validation.md (GitHub issue #119)
9
9
  */
10
- import { ui } from "../widgets/ui.js";
11
- import { DEFAULT_ASYNC_DEBOUNCE_MS, createDebouncedAsyncValidator, isValidationClean, mergeValidationErrors, runAsyncValidation, runFieldValidation, runSyncValidation, } from "./validation.js";
12
- const NODE_ENV = globalThis.process?.env?.NODE_ENV ??
13
- "development";
14
- const DEV_MODE = NODE_ENV !== "production";
15
- function warnDev(message) {
16
- if (!DEV_MODE)
17
- return;
18
- const c = globalThis.console;
19
- c?.warn?.(message);
20
- }
21
- function formatErrorForDev(error) {
22
- if (error instanceof Error) {
23
- return `${error.name}: ${error.message}`;
24
- }
25
- try {
26
- return String(error);
27
- }
28
- catch {
29
- return "[unstringifiable thrown value]";
30
- }
31
- }
32
- function cloneInitialValues(values) {
33
- return structuredClone(values);
34
- }
35
- /**
36
- * Clamp step index to available wizard range.
37
- */
38
- function clampStepIndex(stepIndex, stepCount) {
39
- if (stepCount <= 0) {
40
- return 0;
41
- }
42
- if (stepIndex < 0) {
43
- return 0;
44
- }
45
- if (stepIndex >= stepCount) {
46
- return stepCount - 1;
47
- }
48
- return stepIndex;
49
- }
50
- /**
51
- * Create initial form state from options.
52
- */
53
- function createInitialState(options) {
54
- const stepCount = options.wizard?.steps.length ?? 0;
55
- const initialStep = clampStepIndex(options.wizard?.initialStep ?? 0, stepCount);
56
- if (DEV_MODE) {
57
- const valueKeys = new Set(Object.keys(options.initialValues));
58
- if (options.fieldDisabled) {
59
- for (const key of Object.keys(options.fieldDisabled)) {
60
- if (!valueKeys.has(key)) {
61
- warnDev(`[rezi] useForm: fieldDisabled key "${key}" does not exist in initialValues`);
62
- }
63
- }
64
- }
65
- if (options.fieldReadOnly) {
66
- for (const key of Object.keys(options.fieldReadOnly)) {
67
- if (!valueKeys.has(key)) {
68
- warnDev(`[rezi] useForm: fieldReadOnly key "${key}" does not exist in initialValues`);
69
- }
70
- }
71
- }
72
- }
73
- return {
74
- values: cloneInitialValues(options.initialValues),
75
- errors: {},
76
- touched: {},
77
- dirty: {},
78
- isSubmitting: false,
79
- submitError: undefined,
80
- submitCount: 0,
81
- disabled: options.disabled ?? false,
82
- readOnly: options.readOnly ?? false,
83
- fieldDisabled: {
84
- ...(options.fieldDisabled ?? {}),
85
- },
86
- fieldReadOnly: {
87
- ...(options.fieldReadOnly ?? {}),
88
- },
89
- currentStep: initialStep,
90
- };
91
- }
92
- /**
93
- * Compute dirty array flags by position.
94
- */
95
- function computeArrayFieldDirty(currentValue, initialValue) {
96
- if (currentValue.length !== initialValue.length) {
97
- return true;
98
- }
99
- const dirty = [];
100
- for (let i = 0; i < currentValue.length; i++) {
101
- dirty.push(!Object.is(currentValue[i], initialValue[i]));
102
- }
103
- return dirty;
104
- }
105
- /**
106
- * Compute dirty status for a field by comparing current value to initial.
107
- */
108
- function computeFieldDirty(field, currentValue, initialValues) {
109
- const initialValue = initialValues[field];
110
- if (Array.isArray(currentValue) && Array.isArray(initialValue)) {
111
- return computeArrayFieldDirty(currentValue, initialValue);
112
- }
113
- return !Object.is(currentValue, initialValue);
114
- }
115
- /**
116
- * Check if a field-level dirty/touched flag contains any true value.
117
- */
118
- function hasTruthyBooleanValue(value) {
119
- if (value === true) {
120
- return true;
121
- }
122
- if (!Array.isArray(value)) {
123
- return false;
124
- }
125
- for (const item of value) {
126
- if (item === true) {
127
- return true;
128
- }
129
- }
130
- return false;
131
- }
132
- function toInputValue(value) {
133
- if (value === null || value === undefined) {
134
- return "";
135
- }
136
- return String(value);
137
- }
138
- function isTextBindableValue(value) {
139
- return value === null || value === undefined || typeof value === "string";
140
- }
141
- function toFieldErrorString(value) {
142
- if (typeof value === "string") {
143
- return value.length > 0 ? value : undefined;
144
- }
145
- if (!Array.isArray(value)) {
146
- return undefined;
147
- }
148
- for (const item of value) {
149
- if (item !== undefined && item.length > 0) {
150
- return item;
151
- }
152
- }
153
- return undefined;
154
- }
155
- function isPromiseLike(value) {
156
- return (typeof value === "object" &&
157
- value !== null &&
158
- "then" in value &&
159
- typeof value.then === "function");
160
- }
161
- /**
162
- * Compute overall dirty status from dirty map.
163
- */
164
- function computeIsDirty(dirty) {
165
- const keys = Object.keys(dirty);
166
- for (const key of keys) {
167
- if (hasTruthyBooleanValue(dirty[key])) {
168
- return true;
169
- }
170
- }
171
- return false;
172
- }
173
- /**
174
- * Normalize per-field boolean map value to an array.
175
- */
176
- function normalizeBooleanArray(value, size, defaultValue) {
177
- if (Array.isArray(value)) {
178
- const next = value.slice(0, size);
179
- while (next.length < size) {
180
- next.push(defaultValue);
181
- }
182
- return next;
183
- }
184
- if (value === true || value === false) {
185
- return Array.from({ length: size }, () => value);
186
- }
187
- return Array.from({ length: size }, () => defaultValue);
188
- }
189
- /**
190
- * Normalize per-field error map value to an array.
191
- */
192
- function normalizeErrorArray(value, size) {
193
- if (Array.isArray(value)) {
194
- const next = value.slice(0, size);
195
- while (next.length < size) {
196
- next.push(undefined);
197
- }
198
- return next;
199
- }
200
- return Array.from({ length: size }, () => undefined);
201
- }
202
- function removeAtIndex(value, index) {
203
- const next = [...value];
204
- next.splice(index, 1);
205
- return next;
206
- }
207
- function moveIndex(value, from, to) {
208
- const next = [...value];
209
- const [moved] = next.splice(from, 1);
210
- if (moved === undefined) {
211
- return next;
212
- }
213
- next.splice(to, 0, moved);
214
- return next;
215
- }
216
- /**
217
- * Merge per-step errors into global error state.
218
- */
219
- function mergeStepErrors(prevErrors, stepFields, stepErrors) {
220
- const nextErrors = { ...prevErrors };
221
- for (const field of stepFields) {
222
- nextErrors[field] = undefined;
223
- }
224
- const stepErrorKeys = Object.keys(stepErrors);
225
- for (const field of stepErrorKeys) {
226
- nextErrors[field] = stepErrors[field];
227
- }
228
- return nextErrors;
229
- }
230
- /**
231
- * Pick a subset of validation errors by field list.
232
- */
233
- function pickValidationFields(errors, fields) {
234
- const selected = {};
235
- for (const field of fields) {
236
- const value = errors[field];
237
- if (value !== undefined) {
238
- selected[field] = value;
239
- }
240
- }
241
- return selected;
242
- }
243
- function clearValidationFields(errors, fields) {
244
- if (fields.length === 0) {
245
- return errors;
246
- }
247
- const nextErrors = { ...errors };
248
- for (const field of fields) {
249
- nextErrors[field] = undefined;
250
- }
251
- return nextErrors;
252
- }
253
- function resolveFieldOverride(field, formFlag, fieldOverrides) {
254
- const override = fieldOverrides[field];
255
- if (override === undefined) {
256
- return formFlag;
257
- }
258
- return override;
259
- }
260
- function setFieldOverride(fieldOverrides, field, value) {
261
- const next = { ...fieldOverrides };
262
- if (value === undefined) {
263
- delete next[field];
264
- }
265
- else {
266
- next[field] = value;
267
- }
268
- return next;
269
- }
270
- function markFieldsTouched(prevTouched, values, fields) {
271
- const nextTouched = {
272
- ...prevTouched,
273
- };
274
- for (const field of fields) {
275
- const value = values[field];
276
- if (Array.isArray(value)) {
277
- nextTouched[field] = value.map(() => true);
278
- }
279
- else {
280
- nextTouched[field] = true;
281
- }
282
- }
283
- return nextTouched;
284
- }
285
- function getArrayFieldValues(values, field) {
286
- const raw = values[field];
287
- if (!Array.isArray(raw)) {
288
- return [];
289
- }
290
- return [...raw];
291
- }
292
- function nextFieldArrayKey(field, counterRef) {
293
- const next = counterRef.current;
294
- counterRef.current += 1;
295
- return `${field}_${next}`;
296
- }
10
+ import { createFieldArrayApi } from "./internal/arrayState.js";
11
+ import { createFieldBindings } from "./internal/bindings.js";
12
+ import { cloneInitialValues, computeIsDirty, createFormFlagActions, createFormStateAccessors, createInitialState, } from "./internal/state.js";
13
+ import { createResetAction, createSubmitAction } from "./internal/submit.js";
14
+ import { clampStepIndex, createWizardActions, runWizardStepValidation } from "./internal/wizard.js";
15
+ import { DEFAULT_ASYNC_DEBOUNCE_MS, createDebouncedAsyncValidator, isValidationClean, mergeValidationErrors, } from "./validation.js";
297
16
  /**
298
17
  * Form management hook for Rezi widgets.
299
18
  */
300
19
  export function useForm(ctx, options) {
301
- // Store form state using widget's useState hook
302
20
  const [state, setState] = ctx.useState(() => createInitialState(options));
303
21
  const stateRef = ctx.useRef(state);
304
22
  stateRef.current = state;
305
- // Store initial values in a ref for dirty comparison
306
23
  const initialValuesRef = ctx.useRef(cloneInitialValues(options.initialValues));
307
- // Store async validator reference
308
24
  const asyncValidatorRef = ctx.useRef(undefined);
309
- // Ref to safely pass values from setState callback to async validation
310
25
  const pendingAsyncValuesRef = ctx.useRef(null);
311
26
  const submittingRef = ctx.useRef(false);
27
+ const submitAttemptRef = ctx.useRef(0);
312
28
  const validateRef = ctx.useRef(options.validate);
313
29
  validateRef.current = options.validate;
314
30
  const nonTextBindingWarningsRef = ctx.useRef(new Set());
315
- // Stable key tracking for array fields
316
31
  const fieldArrayKeysRef = ctx.useRef({});
317
32
  const fieldArrayKeyCounterRef = ctx.useRef(0);
318
33
  const updateFormState = (nextState) => {
@@ -330,128 +45,21 @@ export function useForm(ctx, options) {
330
45
  const currentStep = hasWizard ? clampStepIndex(state.currentStep, stepCount) : 0;
331
46
  const isFirstStep = !hasWizard || currentStep === 0;
332
47
  const isLastStep = !hasWizard || currentStep === stepCount - 1;
333
- const isFieldDisabledInternal = (field, source = stateRef.current) => resolveFieldOverride(field, source.disabled, source.fieldDisabled);
334
- const isFieldReadOnlyInternal = (field, source = stateRef.current) => resolveFieldOverride(field, source.readOnly, source.fieldReadOnly);
335
- const isFieldEditableInternal = (field, source = stateRef.current) => !isFieldDisabledInternal(field, source) && !isFieldReadOnlyInternal(field, source);
336
- const filterDisabledValidationErrors = (errors, source = stateRef.current) => {
337
- const keys = Object.keys(errors);
338
- if (keys.length === 0) {
339
- return errors;
340
- }
341
- const nextErrors = { ...errors };
342
- for (const key of keys) {
343
- if (isFieldDisabledInternal(key, source)) {
344
- nextErrors[key] = undefined;
345
- }
346
- }
347
- return nextErrors;
348
- };
349
- const runSyncValidationFiltered = (values, source = stateRef.current) => filterDisabledValidationErrors(runSyncValidation(values, validateRef.current), source);
350
- const runAsyncValidationFiltered = async (values, source = stateRef.current) => filterDisabledValidationErrors(await runAsyncValidation(values, options.validateAsync), source);
351
- const getStep = (stepIndex) => {
352
- if (!hasWizard) {
353
- return undefined;
354
- }
355
- const resolvedStep = clampStepIndex(stepIndex, stepCount);
356
- return wizardSteps[resolvedStep];
357
- };
358
- const getStepFields = (step, values) => {
359
- if (step?.fields && step.fields.length > 0) {
360
- return [...step.fields];
361
- }
362
- return Object.keys(values);
363
- };
364
- const getWizardTransitionSteps = (fromStep, toStepExclusive, values) => {
365
- const steps = [];
366
- for (let stepIndex = fromStep; stepIndex < toStepExclusive; stepIndex++) {
367
- steps.push(Object.freeze({
368
- stepIndex,
369
- fields: getStepFields(getStep(stepIndex), values),
370
- }));
371
- }
372
- return Object.freeze(steps);
373
- };
374
- const runWizardStepValidation = (values, stepIndex, source = stateRef.current) => {
375
- const step = getStep(stepIndex);
376
- if (!step) {
377
- return {};
378
- }
379
- const stepFields = getStepFields(step, values);
380
- const syncStepErrors = pickValidationFields(runSyncValidationFiltered(values, source), stepFields);
381
- if (!step.validate) {
382
- return mergeValidationErrors(syncStepErrors, pickValidationFields(filterDisabledValidationErrors(source.errors, source), stepFields));
383
- }
384
- const customStepErrors = filterDisabledValidationErrors(pickValidationFields(step.validate(values), stepFields), source);
385
- return mergeValidationErrors(mergeValidationErrors(syncStepErrors, customStepErrors), pickValidationFields(filterDisabledValidationErrors(source.errors, source), stepFields));
386
- };
387
- const resolveWizardTransition = (values, transitionSteps, source, asyncErrors) => {
388
- let mergedErrors = source.errors;
389
- for (const transitionStep of transitionSteps) {
390
- const baseStepErrors = runWizardStepValidation(values, transitionStep.stepIndex, {
391
- ...source,
392
- errors: mergedErrors,
393
- });
394
- const stepErrors = asyncErrors === undefined
395
- ? baseStepErrors
396
- : mergeValidationErrors(baseStepErrors, pickValidationFields(asyncErrors, transitionStep.fields));
397
- if (!isValidationClean(stepErrors)) {
398
- return Object.freeze({
399
- blockedFields: transitionStep.fields,
400
- mergedErrors: mergeStepErrors(mergedErrors, transitionStep.fields, stepErrors),
401
- touched: markFieldsTouched(source.touched, values, transitionStep.fields),
402
- });
403
- }
404
- mergedErrors = clearValidationFields(mergedErrors, transitionStep.fields);
405
- }
406
- return null;
407
- };
408
- const warnUnsupportedTextBinding = (field) => {
409
- if (!DEV_MODE)
410
- return;
411
- const fieldKey = String(field);
412
- if (nonTextBindingWarningsRef.current.has(fieldKey))
413
- return;
414
- nonTextBindingWarningsRef.current.add(fieldKey);
415
- warnDev(`[rezi] useForm: bind/field only support string-compatible fields; "${fieldKey}" is not safely bindable to ui.input().`);
416
- };
417
- const canBindFieldAsText = (field, values) => isTextBindableValue(values[field]) && isTextBindableValue(initialValuesRef.current[field]);
418
- const ensureFieldArrayKeys = (field, length) => {
419
- const existing = [...(fieldArrayKeysRef.current[field] ?? [])];
420
- if (existing.length > length) {
421
- existing.length = length;
422
- }
423
- while (existing.length < length) {
424
- existing.push(nextFieldArrayKey(String(field), fieldArrayKeyCounterRef));
425
- }
426
- fieldArrayKeysRef.current[field] = existing;
427
- return existing;
428
- };
429
- const appendFieldArrayKey = (field) => {
430
- const existing = [...(fieldArrayKeysRef.current[field] ?? [])];
431
- existing.push(nextFieldArrayKey(String(field), fieldArrayKeyCounterRef));
432
- fieldArrayKeysRef.current[field] = existing;
433
- };
434
- const removeFieldArrayKey = (field, index) => {
435
- const existing = [...(fieldArrayKeysRef.current[field] ?? [])];
436
- if (index < 0 || index >= existing.length) {
437
- return;
438
- }
439
- existing.splice(index, 1);
440
- fieldArrayKeysRef.current[field] = existing;
441
- };
442
- const moveFieldArrayKey = (field, from, to) => {
443
- const existing = [...(fieldArrayKeysRef.current[field] ?? [])];
444
- if (from < 0 || to < 0 || from >= existing.length || to >= existing.length || from === to) {
445
- return;
446
- }
447
- const [moved] = existing.splice(from, 1);
448
- if (moved === undefined) {
449
- return;
450
- }
451
- existing.splice(to, 0, moved);
452
- fieldArrayKeysRef.current[field] = existing;
453
- };
454
- // Initialize or update async validator when options change
48
+ const { isFieldDisabledInternal, isFieldReadOnlyInternal, isFieldEditableInternal, filterDisabledValidationErrors, runSyncValidationFiltered, runAsyncValidationFiltered, warnUnsupportedTextBinding, canBindFieldAsText, } = createFormStateAccessors({
49
+ stateRef,
50
+ initialValuesRef,
51
+ validateRef,
52
+ validateAsync: options.validateAsync,
53
+ nonTextBindingWarningsRef,
54
+ });
55
+ const runWizardStepValidationForState = (values, stepIndex, source = stateRef.current) => runWizardStepValidation({
56
+ values,
57
+ stepIndex,
58
+ wizardSteps,
59
+ source,
60
+ runSyncValidationFiltered,
61
+ filterDisabledValidationErrors,
62
+ });
455
63
  ctx.useEffect(() => {
456
64
  if (options.validateAsync) {
457
65
  asyncValidatorRef.current = createDebouncedAsyncValidator(options.validateAsync, options.validateAsyncDebounce ?? DEFAULT_ASYNC_DEBOUNCE_MS, (asyncErrors) => {
@@ -466,709 +74,74 @@ export function useForm(ctx, options) {
466
74
  }
467
75
  return undefined;
468
76
  }, [options.validateAsync, options.validateAsyncDebounce]);
469
- // Compute derived state
470
77
  const isValid = isValidationClean(state.errors);
471
78
  const isDirty = computeIsDirty(state.dirty);
472
- /**
473
- * Validate form and update errors.
474
- */
475
- const validateForm = () => {
476
- const snapshot = stateRef.current;
477
- const errors = runSyncValidationFiltered(snapshot.values, snapshot);
478
- updateFormState((prev) => ({
479
- ...prev,
480
- errors,
481
- }));
482
- return errors;
483
- };
484
- /**
485
- * Validate a single field.
486
- */
487
- const validateField = (field) => {
488
- const snapshot = stateRef.current;
489
- if (isFieldDisabledInternal(field, snapshot)) {
490
- updateFormState((prev) => ({
491
- ...prev,
492
- errors: {
493
- ...prev.errors,
494
- [field]: undefined,
495
- },
496
- }));
497
- return undefined;
498
- }
499
- const error = runFieldValidation(snapshot.values, field, options.validate);
500
- updateFormState((prev) => ({
501
- ...prev,
502
- errors: {
503
- ...prev.errors,
504
- [field]: error,
505
- },
506
- }));
507
- return error;
508
- };
509
- /**
510
- * Set a specific field's value.
511
- */
512
- const setFieldValue = (field, value) => {
513
- pendingAsyncValuesRef.current = null;
514
- const newDirty = computeFieldDirty(field, value, initialValuesRef.current);
515
- updateFormState((prev) => {
516
- if (prev.isSubmitting || !isFieldEditableInternal(field, prev)) {
517
- return prev;
518
- }
519
- const newValues = { ...prev.values, [field]: value };
520
- // Store in ref for async validation (safe handoff from callback)
521
- pendingAsyncValuesRef.current = newValues;
522
- let newErrors = prev.errors;
523
- // Run validation on change if enabled
524
- if (options.validateOnChange) {
525
- newErrors = runSyncValidationFiltered(newValues, prev);
526
- }
527
- return {
528
- ...prev,
529
- values: newValues,
530
- errors: newErrors,
531
- submitError: undefined,
532
- dirty: {
533
- ...prev.dirty,
534
- [field]: newDirty,
535
- },
536
- };
537
- });
538
- // Trigger async validation if configured
539
- const asyncValues = pendingAsyncValuesRef.current;
540
- pendingAsyncValuesRef.current = null; // Clear to avoid stale data
541
- if (options.validateOnChange && asyncValidatorRef.current && asyncValues) {
542
- asyncValidatorRef.current.run(asyncValues);
543
- }
544
- };
545
- /**
546
- * Set a specific field's error.
547
- */
548
- const setFieldError = (field, error) => {
549
- updateFormState((prev) => ({
550
- ...prev,
551
- errors: {
552
- ...prev.errors,
553
- [field]: error,
554
- },
555
- }));
556
- };
557
- /**
558
- * Mark a field as touched.
559
- */
560
- const setFieldTouched = (field, touched) => {
561
- updateFormState((prev) => ({
562
- ...prev,
563
- touched: {
564
- ...prev.touched,
565
- [field]: touched,
566
- },
567
- }));
568
- };
569
- /**
570
- * Handle change for a specific field.
571
- */
572
- const handleChange = (field) => (value) => {
573
- setFieldValue(field, value);
574
- };
575
- /**
576
- * Handle blur for a specific field.
577
- */
578
- const handleBlur = (field) => () => {
579
- const snapshot = stateRef.current;
580
- if (isFieldDisabledInternal(field, snapshot)) {
581
- return;
582
- }
583
- // Run validation on blur if enabled (default: true)
584
- const validateOnBlur = options.validateOnBlur ?? true;
585
- if (!validateOnBlur) {
586
- setFieldTouched(field, true);
587
- return;
588
- }
589
- const errors = runSyncValidationFiltered(snapshot.values, snapshot);
590
- updateFormState((prev) => ({
591
- ...prev,
592
- touched: {
593
- ...prev.touched,
594
- [field]: true,
595
- },
596
- errors,
597
- }));
598
- if (asyncValidatorRef.current) {
599
- asyncValidatorRef.current.run(snapshot.values);
600
- }
601
- };
602
- const bind = (field, options) => {
603
- const snapshot = stateRef.current;
604
- const disabled = isFieldDisabledInternal(field, snapshot);
605
- const readOnly = !disabled && isFieldReadOnlyInternal(field, snapshot);
606
- const textBindable = canBindFieldAsText(field, snapshot.values);
607
- if (!textBindable) {
608
- warnUnsupportedTextBinding(field);
609
- }
610
- return {
611
- id: options?.id ?? ctx.id(String(field)),
612
- value: toInputValue(snapshot.values[field]),
613
- disabled,
614
- readOnly,
615
- onInput: (value) => {
616
- if (!textBindable)
617
- return;
618
- setFieldValue(field, value);
619
- },
620
- onBlur: handleBlur(field),
621
- };
622
- };
623
- const field = (fieldName, options) => {
624
- const { key, label, required, hint, error, ...inputOverrides } = options ?? {};
625
- const inputBinding = bind(fieldName, inputOverrides.id === undefined ? undefined : { id: inputOverrides.id });
626
- const touched = hasTruthyBooleanValue(state.touched[fieldName]);
627
- const derivedError = touched ? toFieldErrorString(state.errors[fieldName]) : undefined;
628
- const resolvedError = error ?? derivedError;
629
- return ui.field({
630
- ...(key !== undefined ? { key } : {}),
631
- label: label ?? String(fieldName),
632
- ...(required !== undefined ? { required } : {}),
633
- ...(hint !== undefined ? { hint } : {}),
634
- ...(resolvedError !== undefined ? { error: resolvedError } : {}),
635
- children: ui.input({
636
- ...inputBinding,
637
- ...inputOverrides,
638
- }),
639
- });
640
- };
641
- /**
642
- * Set or clear form-level disabled state.
643
- */
644
- const setDisabled = (disabled) => {
645
- updateFormState((prev) => {
646
- const nextState = {
647
- ...prev,
648
- disabled,
649
- };
650
- return {
651
- ...nextState,
652
- errors: filterDisabledValidationErrors(prev.errors, nextState),
653
- };
654
- });
655
- };
656
- /**
657
- * Set or clear form-level readOnly state.
658
- */
659
- const setReadOnly = (readOnly) => {
660
- updateFormState((prev) => ({
661
- ...prev,
662
- readOnly,
663
- }));
664
- };
665
- /**
666
- * Set or clear field-level disabled override.
667
- */
668
- const setFieldDisabled = (field, disabled) => {
669
- updateFormState((prev) => {
670
- const nextState = {
671
- ...prev,
672
- fieldDisabled: setFieldOverride(prev.fieldDisabled, field, disabled),
673
- };
674
- return {
675
- ...nextState,
676
- errors: filterDisabledValidationErrors(prev.errors, nextState),
677
- };
678
- });
679
- };
680
- /**
681
- * Set or clear field-level readOnly override.
682
- */
683
- const setFieldReadOnly = (field, readOnly) => {
684
- updateFormState((prev) => ({
685
- ...prev,
686
- fieldReadOnly: setFieldOverride(prev.fieldReadOnly, field, readOnly),
687
- }));
688
- };
689
- /**
690
- * Dynamic array helper for array-valued fields.
691
- */
692
- const useFieldArray = (field) => {
693
- const fieldKey = field;
694
- const values = getArrayFieldValues(state.values, field);
695
- const keys = ensureFieldArrayKeys(fieldKey, values.length);
696
- const append = (item) => {
697
- pendingAsyncValuesRef.current = null;
698
- updateFormState((prev) => {
699
- if (prev.isSubmitting || !isFieldEditableInternal(fieldKey, prev)) {
700
- return prev;
701
- }
702
- const currentValues = getArrayFieldValues(prev.values, field);
703
- const nextValuesArray = [...currentValues, item];
704
- const nextValues = {
705
- ...prev.values,
706
- [field]: nextValuesArray,
707
- };
708
- pendingAsyncValuesRef.current = nextValues;
709
- const nextTouched = [
710
- ...normalizeBooleanArray(prev.touched[fieldKey], currentValues.length, false),
711
- false,
712
- ];
713
- const previousDirty = normalizeBooleanArray(prev.dirty[fieldKey], currentValues.length, false);
714
- const initialArray = Array.isArray(initialValuesRef.current[fieldKey])
715
- ? initialValuesRef.current[fieldKey]
716
- : [];
717
- const appendedDirty = !Object.is(item, initialArray[nextValuesArray.length - 1]);
718
- const nextDirty = [...previousDirty, appendedDirty];
719
- let nextErrors = prev.errors;
720
- if (options.validateOnChange) {
721
- nextErrors = runSyncValidationFiltered(nextValues, prev);
722
- }
723
- else {
724
- const currentErrors = normalizeErrorArray(prev.errors[fieldKey], currentValues.length);
725
- nextErrors = {
726
- ...prev.errors,
727
- [fieldKey]: [...currentErrors, undefined],
728
- };
729
- }
730
- appendFieldArrayKey(fieldKey);
731
- return {
732
- ...prev,
733
- values: nextValues,
734
- errors: nextErrors,
735
- submitError: undefined,
736
- touched: {
737
- ...prev.touched,
738
- [fieldKey]: nextTouched,
739
- },
740
- dirty: {
741
- ...prev.dirty,
742
- [fieldKey]: nextDirty,
743
- },
744
- };
745
- });
746
- const asyncValues = pendingAsyncValuesRef.current;
747
- pendingAsyncValuesRef.current = null;
748
- if (options.validateOnChange && asyncValidatorRef.current && asyncValues) {
749
- asyncValidatorRef.current.run(asyncValues);
750
- }
751
- };
752
- const remove = (index) => {
753
- pendingAsyncValuesRef.current = null;
754
- updateFormState((prev) => {
755
- if (prev.isSubmitting || !isFieldEditableInternal(fieldKey, prev)) {
756
- return prev;
757
- }
758
- const currentValues = getArrayFieldValues(prev.values, field);
759
- if (index < 0 || index >= currentValues.length) {
760
- return prev;
761
- }
762
- const nextValuesArray = removeAtIndex(currentValues, index);
763
- const nextValues = {
764
- ...prev.values,
765
- [field]: nextValuesArray,
766
- };
767
- pendingAsyncValuesRef.current = nextValues;
768
- const nextTouched = removeAtIndex(normalizeBooleanArray(prev.touched[fieldKey], currentValues.length, false), index);
769
- const nextDirty = removeAtIndex(normalizeBooleanArray(prev.dirty[fieldKey], currentValues.length, false), index);
770
- let nextErrors = prev.errors;
771
- if (options.validateOnChange) {
772
- nextErrors = runSyncValidationFiltered(nextValues, prev);
773
- }
774
- else {
775
- const nextErrorArray = removeAtIndex(normalizeErrorArray(prev.errors[fieldKey], currentValues.length), index);
776
- nextErrors = {
777
- ...prev.errors,
778
- [fieldKey]: nextErrorArray,
779
- };
780
- }
781
- removeFieldArrayKey(fieldKey, index);
782
- return {
783
- ...prev,
784
- values: nextValues,
785
- errors: nextErrors,
786
- submitError: undefined,
787
- touched: {
788
- ...prev.touched,
789
- [fieldKey]: nextTouched,
790
- },
791
- dirty: {
792
- ...prev.dirty,
793
- [fieldKey]: nextDirty,
794
- },
795
- };
796
- });
797
- const asyncValues = pendingAsyncValuesRef.current;
798
- pendingAsyncValuesRef.current = null;
799
- if (options.validateOnChange && asyncValidatorRef.current && asyncValues) {
800
- asyncValidatorRef.current.run(asyncValues);
801
- }
802
- };
803
- const move = (from, to) => {
804
- pendingAsyncValuesRef.current = null;
805
- updateFormState((prev) => {
806
- if (prev.isSubmitting || !isFieldEditableInternal(fieldKey, prev)) {
807
- return prev;
808
- }
809
- const currentValues = getArrayFieldValues(prev.values, field);
810
- if (from < 0 ||
811
- to < 0 ||
812
- from >= currentValues.length ||
813
- to >= currentValues.length ||
814
- from === to) {
815
- return prev;
816
- }
817
- const nextValuesArray = moveIndex(currentValues, from, to);
818
- const nextValues = {
819
- ...prev.values,
820
- [field]: nextValuesArray,
821
- };
822
- pendingAsyncValuesRef.current = nextValues;
823
- const nextTouched = moveIndex(normalizeBooleanArray(prev.touched[fieldKey], currentValues.length, false), from, to);
824
- const nextDirty = moveIndex(normalizeBooleanArray(prev.dirty[fieldKey], currentValues.length, false), from, to);
825
- const nextErrorArray = moveIndex(normalizeErrorArray(prev.errors[fieldKey], currentValues.length), from, to);
826
- let nextErrors = {
827
- ...prev.errors,
828
- [fieldKey]: nextErrorArray,
829
- };
830
- if (options.validateOnChange) {
831
- nextErrors = runSyncValidationFiltered(nextValues, prev);
832
- }
833
- moveFieldArrayKey(fieldKey, from, to);
834
- return {
835
- ...prev,
836
- values: nextValues,
837
- errors: nextErrors,
838
- submitError: undefined,
839
- touched: {
840
- ...prev.touched,
841
- [fieldKey]: nextTouched,
842
- },
843
- dirty: {
844
- ...prev.dirty,
845
- [fieldKey]: nextDirty,
846
- },
847
- };
848
- });
849
- const asyncValues = pendingAsyncValuesRef.current;
850
- pendingAsyncValuesRef.current = null;
851
- if (options.validateOnChange && asyncValidatorRef.current && asyncValues) {
852
- asyncValidatorRef.current.run(asyncValues);
853
- }
854
- };
855
- return Object.freeze({
856
- values,
857
- keys,
858
- append,
859
- remove,
860
- move,
861
- });
862
- };
863
- /**
864
- * Advance wizard by one step when current step validates cleanly.
865
- */
866
- const nextStep = () => {
867
- if (!hasWizard) {
868
- return true;
869
- }
870
- const snapshot = stateRef.current;
871
- const currentStepIndex = clampStepIndex(snapshot.currentStep, stepCount);
872
- if (currentStepIndex >= stepCount - 1) {
873
- return true;
874
- }
875
- const targetStep = clampStepIndex(currentStepIndex + 1, stepCount);
876
- const transitionSteps = getWizardTransitionSteps(currentStepIndex, targetStep, snapshot.values);
877
- const blocked = resolveWizardTransition(snapshot.values, transitionSteps, snapshot);
878
- if (blocked) {
879
- updateFormState((prev) => ({
880
- ...prev,
881
- touched: blocked.touched,
882
- errors: blocked.mergedErrors,
883
- }));
884
- return false;
885
- }
886
- if (!options.validateAsync) {
887
- const traversedFields = transitionSteps.flatMap((step) => step.fields);
888
- updateFormState((prev) => ({
889
- ...prev,
890
- currentStep: targetStep,
891
- errors: clearValidationFields(prev.errors, traversedFields),
892
- }));
893
- return true;
894
- }
895
- void (async () => {
896
- let asyncErrors;
897
- try {
898
- asyncErrors = await runAsyncValidationFiltered(snapshot.values, snapshot);
899
- }
900
- catch (error) {
901
- if (stateRef.current.values !== snapshot.values ||
902
- clampStepIndex(stateRef.current.currentStep, stepCount) !== currentStepIndex) {
903
- return;
904
- }
905
- updateFormState((prev) => ({
906
- ...prev,
907
- submitError: error,
908
- }));
909
- return;
910
- }
911
- if (stateRef.current.values !== snapshot.values ||
912
- clampStepIndex(stateRef.current.currentStep, stepCount) !== currentStepIndex) {
913
- return;
914
- }
915
- const asyncBlocked = resolveWizardTransition(snapshot.values, transitionSteps, stateRef.current, asyncErrors);
916
- if (asyncBlocked) {
917
- updateFormState((prev) => ({
918
- ...prev,
919
- touched: asyncBlocked.touched,
920
- errors: asyncBlocked.mergedErrors,
921
- submitError: undefined,
922
- }));
923
- return;
924
- }
925
- const traversedFields = transitionSteps.flatMap((step) => step.fields);
926
- updateFormState((prev) => ({
927
- ...prev,
928
- currentStep: targetStep,
929
- errors: clearValidationFields(prev.errors, traversedFields),
930
- submitError: undefined,
931
- }));
932
- })();
933
- return false;
934
- };
935
- /**
936
- * Navigate to previous wizard step without validation.
937
- */
938
- const previousStep = () => {
939
- if (!hasWizard) {
940
- return;
941
- }
942
- updateFormState((prev) => ({
943
- ...prev,
944
- currentStep: clampStepIndex(prev.currentStep - 1, stepCount),
945
- }));
946
- };
947
- /**
948
- * Navigate to a specific wizard step with validation gates on forward moves.
949
- */
950
- const goToStep = (stepIndex) => {
951
- if (!hasWizard) {
952
- return false;
953
- }
954
- const snapshot = stateRef.current;
955
- const currentStepIndex = clampStepIndex(snapshot.currentStep, stepCount);
956
- const targetStep = clampStepIndex(stepIndex, stepCount);
957
- if (targetStep === currentStepIndex) {
958
- return true;
959
- }
960
- if (targetStep < currentStepIndex) {
961
- updateFormState((prev) => ({
962
- ...prev,
963
- currentStep: targetStep,
964
- }));
965
- return true;
966
- }
967
- const transitionSteps = getWizardTransitionSteps(currentStepIndex, targetStep, snapshot.values);
968
- const blocked = resolveWizardTransition(snapshot.values, transitionSteps, snapshot);
969
- if (blocked) {
970
- updateFormState((prev) => ({
971
- ...prev,
972
- touched: blocked.touched,
973
- errors: blocked.mergedErrors,
974
- }));
975
- return false;
976
- }
977
- if (!options.validateAsync) {
978
- const traversedFields = transitionSteps.flatMap((step) => step.fields);
979
- updateFormState((prev) => ({
980
- ...prev,
981
- currentStep: targetStep,
982
- errors: clearValidationFields(prev.errors, traversedFields),
983
- }));
984
- return true;
985
- }
986
- void (async () => {
987
- let asyncErrors;
988
- try {
989
- asyncErrors = await runAsyncValidationFiltered(snapshot.values, snapshot);
990
- }
991
- catch (error) {
992
- if (stateRef.current.values !== snapshot.values ||
993
- clampStepIndex(stateRef.current.currentStep, stepCount) !== currentStepIndex) {
994
- return;
995
- }
996
- updateFormState((prev) => ({
997
- ...prev,
998
- submitError: error,
999
- }));
1000
- return;
1001
- }
1002
- if (stateRef.current.values !== snapshot.values ||
1003
- clampStepIndex(stateRef.current.currentStep, stepCount) !== currentStepIndex) {
1004
- return;
1005
- }
1006
- const asyncBlocked = resolveWizardTransition(snapshot.values, transitionSteps, stateRef.current, asyncErrors);
1007
- if (asyncBlocked) {
1008
- updateFormState((prev) => ({
1009
- ...prev,
1010
- touched: asyncBlocked.touched,
1011
- errors: asyncBlocked.mergedErrors,
1012
- submitError: undefined,
1013
- }));
1014
- return;
1015
- }
1016
- const traversedFields = transitionSteps.flatMap((step) => step.fields);
1017
- updateFormState((prev) => ({
1018
- ...prev,
1019
- currentStep: targetStep,
1020
- errors: clearValidationFields(prev.errors, traversedFields),
1021
- submitError: undefined,
1022
- }));
1023
- })();
1024
- return false;
1025
- };
1026
- /**
1027
- * Reset form to initial state.
1028
- */
1029
- const reset = () => {
1030
- submittingRef.current = false;
1031
- asyncValidatorRef.current?.cancel();
1032
- fieldArrayKeysRef.current = {};
1033
- updateFormState(createInitialState(options));
1034
- };
1035
- /**
1036
- * Handle form submission.
1037
- */
1038
- const handleSubmit = () => {
1039
- const snapshot = stateRef.current;
1040
- // Don't submit if disabled or already submitting
1041
- if (snapshot.disabled || snapshot.isSubmitting || submittingRef.current) {
1042
- return;
1043
- }
1044
- // In wizard mode, submit action advances steps until the last step.
1045
- const submitStepIndex = hasWizard ? clampStepIndex(snapshot.currentStep, stepCount) : 0;
1046
- const submitIsLastStep = !hasWizard || submitStepIndex === stepCount - 1;
1047
- if (hasWizard && !submitIsLastStep) {
1048
- nextStep();
1049
- return;
1050
- }
1051
- asyncValidatorRef.current?.cancel();
1052
- // Mark all fields as touched
1053
- const allTouched = {};
1054
- const keys = Object.keys(snapshot.values);
1055
- for (const key of keys) {
1056
- const value = snapshot.values[key];
1057
- allTouched[key] = Array.isArray(value) ? value.map(() => true) : true;
1058
- }
1059
- // Run sync validation
1060
- const syncErrors = runSyncValidationFiltered(snapshot.values, snapshot);
1061
- // Update state with touched and sync errors
1062
- updateFormState((prev) => ({
1063
- ...prev,
1064
- touched: allTouched,
1065
- errors: syncErrors,
1066
- submitError: undefined,
1067
- submitCount: prev.submitCount + 1,
1068
- }));
1069
- // If sync validation fails, don't submit
1070
- if (!isValidationClean(syncErrors)) {
1071
- submittingRef.current = false;
1072
- return;
1073
- }
1074
- const submitValues = cloneInitialValues(snapshot.values);
1075
- const failSubmit = (error) => {
1076
- if (typeof options.onSubmitError === "function") {
1077
- try {
1078
- options.onSubmitError(error);
1079
- }
1080
- catch (callbackError) {
1081
- warnDev(`[rezi] useForm: onSubmitError callback threw: ${formatErrorForDev(callbackError)}`);
1082
- }
1083
- }
1084
- else {
1085
- warnDev(`[rezi] useForm: submit failed: ${formatErrorForDev(error)}`);
1086
- }
1087
- updateFormState((prev) => ({
1088
- ...prev,
1089
- isSubmitting: false,
1090
- submitError: error,
1091
- }));
1092
- };
1093
- const finishSuccessfulSubmit = () => {
1094
- if (options.resetOnSubmit) {
1095
- reset();
1096
- return;
1097
- }
1098
- updateFormState((prev) => ({
1099
- ...prev,
1100
- isSubmitting: false,
1101
- submitError: undefined,
1102
- }));
1103
- };
1104
- const runSubmitCallback = async () => {
1105
- let submitResult;
1106
- try {
1107
- submitResult = options.onSubmit(submitValues);
1108
- }
1109
- catch (error) {
1110
- submittingRef.current = false;
1111
- failSubmit(error);
1112
- return;
1113
- }
1114
- if (!isPromiseLike(submitResult)) {
1115
- submittingRef.current = false;
1116
- finishSuccessfulSubmit();
1117
- return;
1118
- }
1119
- submittingRef.current = true;
1120
- if (!stateRef.current.isSubmitting) {
1121
- updateFormState((prev) => ({
1122
- ...prev,
1123
- isSubmitting: true,
1124
- }));
1125
- }
1126
- try {
1127
- await submitResult;
1128
- }
1129
- catch (error) {
1130
- submittingRef.current = false;
1131
- failSubmit(error);
1132
- return;
1133
- }
1134
- submittingRef.current = false;
1135
- finishSuccessfulSubmit();
1136
- };
1137
- if (!options.validateAsync) {
1138
- void runSubmitCallback();
1139
- return;
1140
- }
1141
- submittingRef.current = true;
1142
- updateFormState((prev) => ({
1143
- ...prev,
1144
- isSubmitting: true,
1145
- }));
1146
- void (async () => {
1147
- try {
1148
- const asyncErrors = await runAsyncValidationFiltered(submitValues, snapshot);
1149
- const allErrors = mergeValidationErrors(syncErrors, asyncErrors);
1150
- if (!isValidationClean(allErrors)) {
1151
- submittingRef.current = false;
1152
- updateFormState((prev) => ({
1153
- ...prev,
1154
- isSubmitting: false,
1155
- errors: allErrors,
1156
- submitError: undefined,
1157
- }));
1158
- return;
1159
- }
1160
- await runSubmitCallback();
1161
- }
1162
- catch (error) {
1163
- submittingRef.current = false;
1164
- updateFormState((prev) => ({
1165
- ...prev,
1166
- isSubmitting: false,
1167
- submitError: error,
1168
- }));
1169
- }
1170
- })();
1171
- };
79
+ const { validateForm, validateField, setFieldValue, setFieldError, setFieldTouched, handleChange, handleBlur, bind, field, } = createFieldBindings({
80
+ ctx,
81
+ state,
82
+ stateRef,
83
+ initialValuesRef,
84
+ pendingAsyncValuesRef,
85
+ asyncValidatorRef,
86
+ validate: options.validate,
87
+ validateOnBlur: options.validateOnBlur,
88
+ validateOnChange: options.validateOnChange,
89
+ updateFormState,
90
+ isFieldDisabledInternal,
91
+ isFieldReadOnlyInternal,
92
+ isFieldEditableInternal,
93
+ runSyncValidationFiltered,
94
+ canBindFieldAsText,
95
+ warnUnsupportedTextBinding,
96
+ });
97
+ const { setDisabled, setReadOnly, setFieldDisabled, setFieldReadOnly } = createFormFlagActions({
98
+ updateFormState,
99
+ filterDisabledValidationErrors,
100
+ });
101
+ const { useFieldArray } = createFieldArrayApi({
102
+ state,
103
+ validateOnChange: options.validateOnChange,
104
+ initialValuesRef,
105
+ fieldArrayKeysRef,
106
+ fieldArrayKeyCounterRef,
107
+ pendingAsyncValuesRef,
108
+ asyncValidatorRef,
109
+ updateFormState,
110
+ isFieldEditableInternal,
111
+ runSyncValidationFiltered,
112
+ });
113
+ const { nextStep, previousStep, goToStep } = createWizardActions({
114
+ hasWizard,
115
+ stepCount,
116
+ wizardSteps,
117
+ validateAsync: options.validateAsync,
118
+ stateRef,
119
+ updateFormState,
120
+ runAsyncValidationFiltered,
121
+ runWizardStepValidation: runWizardStepValidationForState,
122
+ });
123
+ const reset = createResetAction({
124
+ formOptions: options,
125
+ asyncValidatorRef,
126
+ attemptRef: submitAttemptRef,
127
+ submittingRef,
128
+ fieldArrayKeysRef,
129
+ updateFormState,
130
+ });
131
+ const handleSubmit = createSubmitAction({
132
+ formOptions: options,
133
+ hasWizard,
134
+ stepCount,
135
+ stateRef,
136
+ submittingRef,
137
+ asyncValidatorRef,
138
+ attemptRef: submitAttemptRef,
139
+ updateFormState,
140
+ runSyncValidationFiltered,
141
+ runAsyncValidationFiltered,
142
+ nextStep,
143
+ reset,
144
+ });
1172
145
  return Object.freeze({
1173
146
  values: state.values,
1174
147
  errors: state.errors,
@@ -1201,8 +174,8 @@ export function useForm(ctx, options) {
1201
174
  setReadOnly,
1202
175
  setFieldDisabled,
1203
176
  setFieldReadOnly,
1204
- isFieldDisabled: (field) => isFieldDisabledInternal(field, stateRef.current),
1205
- isFieldReadOnly: (field) => isFieldReadOnlyInternal(field, stateRef.current),
177
+ isFieldDisabled: (fieldName) => isFieldDisabledInternal(fieldName, stateRef.current),
178
+ isFieldReadOnly: (fieldName) => isFieldReadOnlyInternal(fieldName, stateRef.current),
1206
179
  useFieldArray,
1207
180
  nextStep,
1208
181
  previousStep,