@10x-media/form-builder 0.1.0-beta.1 → 0.1.0-beta.11

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 (556) hide show
  1. package/CHANGELOG.md +304 -0
  2. package/README.md +6 -4
  3. package/dist/actions/assertNoBlockCollision.js +18 -0
  4. package/dist/actions/assertNoBlockCollision.js.map +1 -0
  5. package/dist/actions/body/converters.d.ts +20 -0
  6. package/dist/actions/body/converters.js +57 -0
  7. package/dist/actions/body/converters.js.map +1 -0
  8. package/dist/actions/body/escapeHtml.d.ts +6 -0
  9. package/dist/actions/body/escapeHtml.js +14 -0
  10. package/dist/actions/body/escapeHtml.js.map +1 -0
  11. package/dist/actions/body/serializeBody.d.ts +55 -0
  12. package/dist/actions/body/serializeBody.js +78 -0
  13. package/dist/actions/body/serializeBody.js.map +1 -0
  14. package/dist/actions/body/serializeSlate.js +31 -0
  15. package/dist/actions/body/serializeSlate.js.map +1 -0
  16. package/dist/actions/body/textOfBody.d.ts +13 -0
  17. package/dist/actions/body/textOfBody.js +35 -0
  18. package/dist/actions/body/textOfBody.js.map +1 -0
  19. package/dist/actions/body/wildcards.d.ts +10 -0
  20. package/dist/actions/body/wildcards.js +33 -0
  21. package/dist/actions/body/wildcards.js.map +1 -0
  22. package/dist/actions/buildActionBlocks.js +12 -9
  23. package/dist/actions/buildActionBlocks.js.map +1 -1
  24. package/dist/actions/builtin/confirmation.js +47 -43
  25. package/dist/actions/builtin/confirmation.js.map +1 -1
  26. package/dist/actions/builtin/emailAction.d.ts +19 -0
  27. package/dist/actions/builtin/emailAction.js +114 -0
  28. package/dist/actions/builtin/emailAction.js.map +1 -0
  29. package/dist/actions/builtin/emailTeam.js +20 -38
  30. package/dist/actions/builtin/emailTeam.js.map +1 -1
  31. package/dist/actions/builtin/index.d.ts +16 -1
  32. package/dist/actions/builtin/index.js +21 -7
  33. package/dist/actions/builtin/index.js.map +1 -1
  34. package/dist/actions/builtin/signedWebhook.js +6 -2
  35. package/dist/actions/builtin/signedWebhook.js.map +1 -1
  36. package/dist/actions/defineAction.d.ts +8 -5
  37. package/dist/actions/defineAction.js.map +1 -1
  38. package/dist/actions/dispatch.js +3 -2
  39. package/dist/actions/dispatch.js.map +1 -1
  40. package/dist/actions/emailRecipients.d.ts +12 -0
  41. package/dist/actions/emailRecipients.js +143 -0
  42. package/dist/actions/emailRecipients.js.map +1 -0
  43. package/dist/actions/fromAddresses.d.ts +21 -0
  44. package/dist/actions/fromAddresses.js +74 -0
  45. package/dist/actions/fromAddresses.js.map +1 -0
  46. package/dist/actions/recipientSources.d.ts +34 -0
  47. package/dist/actions/recipientSources.js +11 -0
  48. package/dist/actions/recipientSources.js.map +1 -0
  49. package/dist/actions/registry.d.ts +2 -1
  50. package/dist/actions/registry.js +2 -6
  51. package/dist/actions/registry.js.map +1 -1
  52. package/dist/actions/runActions.js +10 -1
  53. package/dist/actions/runActions.js.map +1 -1
  54. package/dist/actions/task.js +40 -15
  55. package/dist/actions/task.js.map +1 -1
  56. package/dist/aggregation/aggregateResponses.d.ts +9 -0
  57. package/dist/aggregation/aggregateResponses.js +8 -14
  58. package/dist/aggregation/aggregateResponses.js.map +1 -1
  59. package/dist/aggregation/resolveResultsRequest.d.ts +35 -6
  60. package/dist/aggregation/resolveResultsRequest.js +68 -11
  61. package/dist/aggregation/resolveResultsRequest.js.map +1 -1
  62. package/dist/calc/computeCalcFields.js +2 -1
  63. package/dist/calc/computeCalcFields.js.map +1 -1
  64. package/dist/calc/evaluate.js +1 -2
  65. package/dist/calc/evaluate.js.map +1 -1
  66. package/dist/calc/normalizeCalc.js +6 -19
  67. package/dist/calc/normalizeCalc.js.map +1 -1
  68. package/dist/calc/types.d.ts +8 -2
  69. package/dist/calc/types.js +22 -0
  70. package/dist/calc/types.js.map +1 -0
  71. package/dist/client/ByteSizeField.d.ts +29 -0
  72. package/dist/client/ByteSizeField.js +58 -0
  73. package/dist/client/ByteSizeField.js.map +1 -0
  74. package/dist/client/ClosePollButton.d.ts +15 -0
  75. package/dist/client/ClosePollButton.js +80 -0
  76. package/dist/client/ClosePollButton.js.map +1 -0
  77. package/dist/client/CondensedArray.d.ts +15 -0
  78. package/dist/client/CondensedArray.js +97 -0
  79. package/dist/client/CondensedArray.js.map +1 -0
  80. package/dist/client/ConditionBuilder.js +2 -1
  81. package/dist/client/ConditionBuilder.js.map +1 -1
  82. package/dist/client/ConsentBlockLabel.d.ts +15 -0
  83. package/dist/client/ConsentBlockLabel.js +71 -0
  84. package/dist/client/ConsentBlockLabel.js.map +1 -0
  85. package/dist/client/ConsentSourceRowLabel.d.ts +9 -0
  86. package/dist/client/ConsentSourceRowLabel.js +21 -0
  87. package/dist/client/ConsentSourceRowLabel.js.map +1 -0
  88. package/dist/client/EndpointOptionsSelect.d.ts +46 -0
  89. package/dist/client/EndpointOptionsSelect.js +106 -0
  90. package/dist/client/EndpointOptionsSelect.js.map +1 -0
  91. package/dist/client/FieldBlockLabel.d.ts +18 -0
  92. package/dist/client/FieldBlockLabel.js +34 -0
  93. package/dist/client/FieldBlockLabel.js.map +1 -0
  94. package/dist/client/FieldNameSelect.d.ts +37 -0
  95. package/dist/client/FieldNameSelect.js +72 -0
  96. package/dist/client/FieldNameSelect.js.map +1 -0
  97. package/dist/client/FlowBuilder.d.ts +2 -2
  98. package/dist/client/FlowBuilder.js +137 -88
  99. package/dist/client/FlowBuilder.js.map +1 -1
  100. package/dist/client/FormConditionField.js +1 -4
  101. package/dist/client/FormConditionField.js.map +1 -1
  102. package/dist/client/RecipientsSelect.d.ts +35 -0
  103. package/dist/client/RecipientsSelect.js +193 -0
  104. package/dist/client/RecipientsSelect.js.map +1 -0
  105. package/dist/client/RuleDescription.d.ts +21 -0
  106. package/dist/client/RuleDescription.js +19 -0
  107. package/dist/client/RuleDescription.js.map +1 -0
  108. package/dist/client/admin.css +275 -0
  109. package/dist/client/endpointOptions.js +29 -0
  110. package/dist/client/endpointOptions.js.map +1 -0
  111. package/dist/client/flowAuthoring.js +142 -0
  112. package/dist/client/flowAuthoring.js.map +1 -0
  113. package/dist/client/synthesizeClientField.js +21 -10
  114. package/dist/client/synthesizeClientField.js.map +1 -1
  115. package/dist/client/toStaticLabel.js +13 -0
  116. package/dist/client/toStaticLabel.js.map +1 -0
  117. package/dist/collections/buttonFields.d.ts +34 -0
  118. package/dist/collections/buttonFields.js +35 -0
  119. package/dist/collections/buttonFields.js.map +1 -0
  120. package/dist/collections/cells/FieldCountCell.d.ts +15 -0
  121. package/dist/collections/cells/FieldCountCell.js +18 -0
  122. package/dist/collections/cells/FieldCountCell.js.map +1 -0
  123. package/dist/collections/cells/FlowStepsCell.d.ts +14 -0
  124. package/dist/collections/cells/FlowStepsCell.js +17 -0
  125. package/dist/collections/cells/FlowStepsCell.js.map +1 -0
  126. package/dist/collections/formSubmissions.js +133 -47
  127. package/dist/collections/formSubmissions.js.map +1 -1
  128. package/dist/collections/forms.js +416 -114
  129. package/dist/collections/forms.js.map +1 -1
  130. package/dist/collections/formsEndpoints.js +101 -0
  131. package/dist/collections/formsEndpoints.js.map +1 -0
  132. package/dist/collections/redirectFields.d.ts +29 -0
  133. package/dist/conditions/conditionType.js +9 -2
  134. package/dist/conditions/conditionType.js.map +1 -1
  135. package/dist/conditions/evaluate.js +1 -1
  136. package/dist/conditions/evaluate.js.map +1 -1
  137. package/dist/conditions/fieldTypes.d.ts +3 -1
  138. package/dist/conditions/fieldTypes.js +4 -1
  139. package/dist/conditions/fieldTypes.js.map +1 -1
  140. package/dist/conditions/normalizeConditions.js +20 -6
  141. package/dist/conditions/normalizeConditions.js.map +1 -1
  142. package/dist/consent/applyConsentStatements.d.ts +14 -0
  143. package/dist/consent/applyConsentStatements.js +17 -0
  144. package/dist/consent/applyConsentStatements.js.map +1 -0
  145. package/dist/consent/captureConsent.d.ts +38 -11
  146. package/dist/consent/captureConsent.js +60 -13
  147. package/dist/consent/captureConsent.js.map +1 -1
  148. package/dist/consent/consentSourcesField.d.ts +66 -0
  149. package/dist/consent/consentSourcesField.js +90 -0
  150. package/dist/consent/consentSourcesField.js.map +1 -0
  151. package/dist/consent/resolveConsentEntries.d.ts +24 -0
  152. package/dist/consent/resolveConsentEntries.js +40 -0
  153. package/dist/consent/resolveConsentEntries.js.map +1 -0
  154. package/dist/consent/resolveConsentSourcesRequest.d.ts +37 -0
  155. package/dist/consent/resolveConsentSourcesRequest.js +54 -0
  156. package/dist/consent/resolveConsentSourcesRequest.js.map +1 -0
  157. package/dist/consent/resolveConsentStatements.d.ts +45 -0
  158. package/dist/consent/resolveConsentStatements.js +44 -0
  159. package/dist/consent/resolveConsentStatements.js.map +1 -0
  160. package/dist/consent/resolvePublishedVersionRef.d.ts +17 -11
  161. package/dist/consent/resolvePublishedVersionRef.js +13 -10
  162. package/dist/consent/resolvePublishedVersionRef.js.map +1 -1
  163. package/dist/consent/types.d.ts +61 -0
  164. package/dist/context/formContext.d.ts +30 -0
  165. package/dist/context/formContext.js +54 -0
  166. package/dist/context/formContext.js.map +1 -0
  167. package/dist/email/departments.d.ts +59 -0
  168. package/dist/email/departments.js +87 -0
  169. package/dist/email/departments.js.map +1 -0
  170. package/dist/email/departmentsField.d.ts +53 -0
  171. package/dist/email/departmentsField.js +73 -0
  172. package/dist/email/departmentsField.js.map +1 -0
  173. package/dist/exports/client.d.ts +13 -1
  174. package/dist/exports/client.js +13 -1
  175. package/dist/exports/i18n.d.ts +5 -2
  176. package/dist/exports/i18n.js +5 -2
  177. package/dist/exports/react.d.ts +26 -8
  178. package/dist/exports/react.js +19 -3
  179. package/dist/exports/rsc.d.ts +9 -1
  180. package/dist/exports/rsc.js +9 -1
  181. package/dist/exports/types.d.ts +19 -10
  182. package/dist/fields/buildFieldBlocks.js +53 -19
  183. package/dist/fields/buildFieldBlocks.js.map +1 -1
  184. package/dist/fields/builtin/calculation.js +122 -2
  185. package/dist/fields/builtin/calculation.js.map +1 -1
  186. package/dist/fields/builtin/checkbox.js +8 -0
  187. package/dist/fields/builtin/checkbox.js.map +1 -1
  188. package/dist/fields/builtin/consent.js +30 -15
  189. package/dist/fields/builtin/consent.js.map +1 -1
  190. package/dist/fields/builtin/country.d.ts +13 -0
  191. package/dist/fields/builtin/country.js +30 -0
  192. package/dist/fields/builtin/country.js.map +1 -0
  193. package/dist/fields/builtin/date.js +31 -0
  194. package/dist/fields/builtin/date.js.map +1 -0
  195. package/dist/fields/builtin/email.js +1 -1
  196. package/dist/fields/builtin/email.js.map +1 -1
  197. package/dist/fields/builtin/file.d.ts +15 -0
  198. package/dist/fields/builtin/file.js +95 -8
  199. package/dist/fields/builtin/file.js.map +1 -1
  200. package/dist/fields/builtin/index.d.ts +26 -0
  201. package/dist/fields/builtin/index.js +30 -6
  202. package/dist/fields/builtin/index.js.map +1 -1
  203. package/dist/fields/builtin/message.js +30 -0
  204. package/dist/fields/builtin/message.js.map +1 -0
  205. package/dist/fields/builtin/repeater.js +49 -0
  206. package/dist/fields/builtin/repeater.js.map +1 -0
  207. package/dist/fields/builtin/select.js +8 -3
  208. package/dist/fields/builtin/select.js.map +1 -1
  209. package/dist/fields/builtin/state.d.ts +13 -0
  210. package/dist/fields/builtin/state.js +30 -0
  211. package/dist/fields/builtin/state.js.map +1 -0
  212. package/dist/fields/data/regions.d.ts +21 -0
  213. package/dist/fields/data/regions.js +1238 -0
  214. package/dist/fields/data/regions.js.map +1 -0
  215. package/dist/fields/fieldKey.d.ts +15 -0
  216. package/dist/fields/fieldKey.js +16 -0
  217. package/dist/fields/fieldKey.js.map +1 -0
  218. package/dist/fields/fieldNamesOfType.js +30 -0
  219. package/dist/fields/fieldNamesOfType.js.map +1 -0
  220. package/dist/fields/instanceOptions.js +20 -0
  221. package/dist/fields/instanceOptions.js.map +1 -0
  222. package/dist/fields/localizedIf.d.ts +13 -0
  223. package/dist/fields/localizedIf.js +12 -0
  224. package/dist/fields/localizedIf.js.map +1 -0
  225. package/dist/fields/registry.d.ts +3 -1
  226. package/dist/fields/registry.js +23 -8
  227. package/dist/fields/registry.js.map +1 -1
  228. package/dist/fields/sharedConfig.js +120 -58
  229. package/dist/fields/sharedConfig.js.map +1 -1
  230. package/dist/fields/types.d.ts +71 -7
  231. package/dist/flow/engine.d.ts +6 -4
  232. package/dist/flow/engine.js +11 -6
  233. package/dist/flow/engine.js.map +1 -1
  234. package/dist/flow/normalizeFlow.js +28 -9
  235. package/dist/flow/normalizeFlow.js.map +1 -1
  236. package/dist/flow/stepLabel.js +15 -0
  237. package/dist/flow/stepLabel.js.map +1 -0
  238. package/dist/flow/types.d.ts +12 -3
  239. package/dist/flow/types.js +11 -0
  240. package/dist/flow/types.js.map +1 -0
  241. package/dist/form/pollState.d.ts +22 -0
  242. package/dist/form/pollState.js +17 -0
  243. package/dist/form/pollState.js.map +1 -0
  244. package/dist/form/toFormDocument.d.ts +102 -0
  245. package/dist/form/toFormDocument.js +87 -0
  246. package/dist/form/toFormDocument.js.map +1 -0
  247. package/dist/form/types.d.ts +65 -0
  248. package/dist/index.d.ts +55 -39
  249. package/dist/index.js +89 -23
  250. package/dist/index.js.map +1 -1
  251. package/dist/options.d.ts +236 -0
  252. package/dist/plugin/applyRegistryConfig.d.ts +11 -0
  253. package/dist/plugin/applyRegistryConfig.js +20 -0
  254. package/dist/plugin/applyRegistryConfig.js.map +1 -0
  255. package/dist/plugin/collectionOverrides.d.ts +22 -0
  256. package/dist/plugin/customState.js +26 -0
  257. package/dist/plugin/customState.js.map +1 -0
  258. package/dist/plugin/registerCollections.js +40 -20
  259. package/dist/plugin/registerCollections.js.map +1 -1
  260. package/dist/plugin/uploadsCollection.d.ts +16 -0
  261. package/dist/plugin/uploadsCollection.js +53 -0
  262. package/dist/plugin/uploadsCollection.js.map +1 -0
  263. package/dist/poll/applyPollOptions.js +18 -0
  264. package/dist/poll/applyPollOptions.js.map +1 -0
  265. package/dist/poll/buildPollOptionSourceFields.js +50 -0
  266. package/dist/poll/buildPollOptionSourceFields.js.map +1 -0
  267. package/dist/poll/closeJob.d.ts +52 -0
  268. package/dist/poll/closeJob.js +119 -0
  269. package/dist/poll/closeJob.js.map +1 -0
  270. package/dist/poll/definePollOptionSource.d.ts +44 -0
  271. package/dist/poll/definePollOptionSource.js +6 -0
  272. package/dist/poll/definePollOptionSource.js.map +1 -0
  273. package/dist/poll/definePollType.d.ts +34 -0
  274. package/dist/poll/definePollType.js +6 -0
  275. package/dist/poll/definePollType.js.map +1 -0
  276. package/dist/poll/effectivePollOptions.d.ts +38 -0
  277. package/dist/poll/effectivePollOptions.js +64 -0
  278. package/dist/poll/effectivePollOptions.js.map +1 -0
  279. package/dist/poll/mostVoted.d.ts +21 -0
  280. package/dist/poll/mostVoted.js +32 -0
  281. package/dist/poll/mostVoted.js.map +1 -0
  282. package/dist/poll/outcomeBeforeChange.js +91 -0
  283. package/dist/poll/outcomeBeforeChange.js.map +1 -0
  284. package/dist/poll/outcomeFields.d.ts +38 -0
  285. package/dist/poll/outcomeFields.js +52 -0
  286. package/dist/poll/outcomeFields.js.map +1 -0
  287. package/dist/poll/pollTypeRegistry.d.ts +34 -0
  288. package/dist/poll/pollTypeRegistry.js +69 -0
  289. package/dist/poll/pollTypeRegistry.js.map +1 -0
  290. package/dist/poll/registry.d.ts +17 -0
  291. package/dist/poll/registry.js +12 -0
  292. package/dist/poll/registry.js.map +1 -0
  293. package/dist/poll/resolvePollCloseRequest.js +105 -0
  294. package/dist/poll/resolvePollCloseRequest.js.map +1 -0
  295. package/dist/poll/resolvePollOptions.d.ts +29 -0
  296. package/dist/poll/resolvePollOptions.js +52 -0
  297. package/dist/poll/resolvePollOptions.js.map +1 -0
  298. package/dist/poll/resolvePollOptionsRequest.js +50 -0
  299. package/dist/poll/resolvePollOptionsRequest.js.map +1 -0
  300. package/dist/poll/resolvePollOutcome.d.ts +34 -0
  301. package/dist/poll/resolvePollOutcome.js +76 -0
  302. package/dist/poll/resolvePollOutcome.js.map +1 -0
  303. package/dist/poll/resultsField.js +21 -0
  304. package/dist/poll/resultsField.js.map +1 -0
  305. package/dist/prefill/valuesFromSearchParams.js +5 -9
  306. package/dist/prefill/valuesFromSearchParams.js.map +1 -1
  307. package/dist/presentations/types.d.ts +3 -2
  308. package/dist/react/Form.d.ts +74 -20
  309. package/dist/react/Form.js +346 -180
  310. package/dist/react/Form.js.map +1 -1
  311. package/dist/react/FormContext.d.ts +44 -1
  312. package/dist/react/FormContext.js.map +1 -1
  313. package/dist/react/FormControls.d.ts +55 -0
  314. package/dist/react/FormControls.js +56 -0
  315. package/dist/react/FormControls.js.map +1 -0
  316. package/dist/react/FormFields.d.ts +18 -0
  317. package/dist/react/FormFields.js +114 -0
  318. package/dist/react/FormFields.js.map +1 -0
  319. package/dist/react/FormLayout.d.ts +4 -2
  320. package/dist/react/FormLayout.js +3 -2
  321. package/dist/react/FormLayout.js.map +1 -1
  322. package/dist/react/FormResults.d.ts +6 -3
  323. package/dist/react/FormResults.js +37 -29
  324. package/dist/react/FormResults.js.map +1 -1
  325. package/dist/react/FormSteps.d.ts +17 -0
  326. package/dist/react/FormSteps.js +35 -0
  327. package/dist/react/FormSteps.js.map +1 -0
  328. package/dist/react/Poll.d.ts +17 -6
  329. package/dist/react/Poll.js +79 -21
  330. package/dist/react/Poll.js.map +1 -1
  331. package/dist/react/captcha/HcaptchaCaptcha.d.ts +28 -0
  332. package/dist/react/captcha/HcaptchaCaptcha.js +53 -0
  333. package/dist/react/captcha/HcaptchaCaptcha.js.map +1 -0
  334. package/dist/react/captcha/RecaptchaCaptcha.d.ts +41 -0
  335. package/dist/react/captcha/RecaptchaCaptcha.js +93 -0
  336. package/dist/react/captcha/RecaptchaCaptcha.js.map +1 -0
  337. package/dist/react/captcha/TurnstileCaptcha.d.ts +28 -0
  338. package/dist/react/captcha/TurnstileCaptcha.js +53 -0
  339. package/dist/react/captcha/TurnstileCaptcha.js.map +1 -0
  340. package/dist/react/captcha/types.d.ts +8 -0
  341. package/dist/react/captcha/useCaptchaScript.js +45 -0
  342. package/dist/react/captcha/useCaptchaScript.js.map +1 -0
  343. package/dist/react/captcha/vendors.js +8 -0
  344. package/dist/react/captcha/vendors.js.map +1 -0
  345. package/dist/react/contract.d.ts +2 -3
  346. package/dist/react/contract.js.map +1 -1
  347. package/dist/react/fetchResults.d.ts +1 -1
  348. package/dist/react/fetchResults.js +1 -1
  349. package/dist/react/fetchResults.js.map +1 -1
  350. package/dist/react/presentation/DialogSurface.js +1 -4
  351. package/dist/react/presentation/DialogSurface.js.map +1 -1
  352. package/dist/react/primitives/Checkbox.d.ts +4 -2
  353. package/dist/react/primitives/Checkbox.js +2 -1
  354. package/dist/react/primitives/Checkbox.js.map +1 -1
  355. package/dist/react/primitives/FieldShell.d.ts +2 -4
  356. package/dist/react/primitives/FieldShell.js +12 -19
  357. package/dist/react/primitives/FieldShell.js.map +1 -1
  358. package/dist/react/primitives/Input.d.ts +1 -1
  359. package/dist/react/primitives/Input.js.map +1 -1
  360. package/dist/react/renderers/calculation.js +1 -4
  361. package/dist/react/renderers/calculation.js.map +1 -1
  362. package/dist/react/renderers/checkbox.js +1 -4
  363. package/dist/react/renderers/checkbox.js.map +1 -1
  364. package/dist/react/renderers/consent.js +78 -35
  365. package/dist/react/renderers/consent.js.map +1 -1
  366. package/dist/react/renderers/date.js +33 -0
  367. package/dist/react/renderers/date.js.map +1 -0
  368. package/dist/react/renderers/email.js +1 -4
  369. package/dist/react/renderers/email.js.map +1 -1
  370. package/dist/react/renderers/file.js +29 -14
  371. package/dist/react/renderers/file.js.map +1 -1
  372. package/dist/react/renderers/index.js +9 -0
  373. package/dist/react/renderers/index.js.map +1 -1
  374. package/dist/react/renderers/message.js +41 -0
  375. package/dist/react/renderers/message.js.map +1 -0
  376. package/dist/react/renderers/number.js +1 -4
  377. package/dist/react/renderers/number.js.map +1 -1
  378. package/dist/react/renderers/region.js +43 -0
  379. package/dist/react/renderers/region.js.map +1 -0
  380. package/dist/react/renderers/repeater.js +131 -0
  381. package/dist/react/renderers/repeater.js.map +1 -0
  382. package/dist/react/renderers/select.js +1 -4
  383. package/dist/react/renderers/select.js.map +1 -1
  384. package/dist/react/renderers/text.js +1 -4
  385. package/dist/react/renderers/text.js.map +1 -1
  386. package/dist/react/renderers/textarea.js +1 -4
  387. package/dist/react/renderers/textarea.js.map +1 -1
  388. package/dist/react/state.d.ts +40 -3
  389. package/dist/react/state.js +64 -9
  390. package/dist/react/state.js.map +1 -1
  391. package/dist/react/uploadFile.d.ts +2 -2
  392. package/dist/react/uploadFile.js +1 -1
  393. package/dist/react/uploadFile.js.map +1 -1
  394. package/dist/react/useField.d.ts +0 -1
  395. package/dist/react/useField.js +6 -6
  396. package/dist/react/useField.js.map +1 -1
  397. package/dist/react/useFormState.d.ts +1 -1
  398. package/dist/react/useFormState.js +1 -1
  399. package/dist/react/useFormState.js.map +1 -1
  400. package/dist/react/validateField.js +3 -6
  401. package/dist/react/validateField.js.map +1 -1
  402. package/dist/recall/interpolate.d.ts +4 -3
  403. package/dist/recall/interpolate.js +5 -4
  404. package/dist/recall/interpolate.js.map +1 -1
  405. package/dist/recall/resolver.d.ts +1 -1
  406. package/dist/recall/resolver.js +14 -2
  407. package/dist/recall/resolver.js.map +1 -1
  408. package/dist/spam/captcha.d.ts +4 -3
  409. package/dist/spam/captcha.js +4 -3
  410. package/dist/spam/captcha.js.map +1 -1
  411. package/dist/spam/clientIp.js +9 -0
  412. package/dist/spam/clientIp.js.map +1 -0
  413. package/dist/spam/constants.js +13 -1
  414. package/dist/spam/constants.js.map +1 -1
  415. package/dist/spam/identify.js +3 -6
  416. package/dist/spam/identify.js.map +1 -1
  417. package/dist/spam/providers/hcaptcha.d.ts +17 -0
  418. package/dist/spam/providers/hcaptcha.js +18 -0
  419. package/dist/spam/providers/hcaptcha.js.map +1 -0
  420. package/dist/spam/providers/recaptcha.d.ts +23 -0
  421. package/dist/spam/providers/recaptcha.js +23 -0
  422. package/dist/spam/providers/recaptcha.js.map +1 -0
  423. package/dist/spam/providers/siteverify.js +34 -0
  424. package/dist/spam/providers/siteverify.js.map +1 -0
  425. package/dist/spam/providers/turnstile.d.ts +17 -0
  426. package/dist/spam/providers/turnstile.js +18 -0
  427. package/dist/spam/providers/turnstile.js.map +1 -0
  428. package/dist/spam/resolveSpam.js +2 -1
  429. package/dist/spam/resolveSpam.js.map +1 -1
  430. package/dist/spam/spamGuard.js +23 -10
  431. package/dist/spam/spamGuard.js.map +1 -1
  432. package/dist/spam/types.d.ts +19 -4
  433. package/dist/submissions/SubmissionAnswers.d.ts +2 -4
  434. package/dist/submissions/SubmissionAnswers.js +114 -34
  435. package/dist/submissions/SubmissionAnswers.js.map +1 -1
  436. package/dist/submissions/SubmissionAnswersClient.js +178 -0
  437. package/dist/submissions/SubmissionAnswersClient.js.map +1 -0
  438. package/dist/submissions/coerceBoolean.js +14 -0
  439. package/dist/submissions/coerceBoolean.js.map +1 -0
  440. package/dist/submissions/createSubmission.d.ts +36 -0
  441. package/dist/submissions/createSubmission.js +26 -0
  442. package/dist/submissions/createSubmission.js.map +1 -0
  443. package/dist/submissions/runSubmission.d.ts +10 -0
  444. package/dist/submissions/runSubmission.js +128 -27
  445. package/dist/submissions/runSubmission.js.map +1 -1
  446. package/dist/submissions/types.d.ts +12 -4
  447. package/dist/submissions/validateSubmission.js +62 -11
  448. package/dist/submissions/validateSubmission.js.map +1 -1
  449. package/dist/submissions/verifyContext.js +35 -0
  450. package/dist/submissions/verifyContext.js.map +1 -0
  451. package/dist/submissions/votedCookie.d.ts +13 -0
  452. package/dist/submissions/votedCookie.js +27 -0
  453. package/dist/submissions/votedCookie.js.map +1 -0
  454. package/dist/translations/clientRuntimeKeys.d.ts +17 -0
  455. package/dist/translations/clientRuntimeKeys.js +46 -0
  456. package/dist/translations/clientRuntimeKeys.js.map +1 -0
  457. package/dist/translations/de.d.ts +12 -0
  458. package/dist/translations/de.js +313 -0
  459. package/dist/translations/de.js.map +1 -0
  460. package/dist/translations/en.js +207 -27
  461. package/dist/translations/en.js.map +1 -1
  462. package/dist/translations/index.d.ts +14 -5
  463. package/dist/translations/index.js +14 -3
  464. package/dist/translations/index.js.map +1 -1
  465. package/dist/translations/keys.d.ts +203 -23
  466. package/dist/translations/keys.js +204 -24
  467. package/dist/translations/keys.js.map +1 -1
  468. package/dist/translations/makeTranslate.d.ts +7 -3
  469. package/dist/translations/makeTranslate.js +12 -3
  470. package/dist/translations/makeTranslate.js.map +1 -1
  471. package/dist/translations/server.js +8 -1
  472. package/dist/translations/server.js.map +1 -1
  473. package/dist/uploads/captureFileRef.d.ts +10 -3
  474. package/dist/uploads/captureFileRef.js +18 -9
  475. package/dist/uploads/captureFileRef.js.map +1 -1
  476. package/dist/uploads/formatBytes.d.ts +9 -0
  477. package/dist/uploads/formatBytes.js +25 -0
  478. package/dist/uploads/formatBytes.js.map +1 -0
  479. package/dist/uploads/resolveFileRef.js +3 -2
  480. package/dist/uploads/resolveFileRef.js.map +1 -1
  481. package/dist/uploads/types.d.ts +1 -2
  482. package/dist/validation/buildRuleBlocks.js +18 -17
  483. package/dist/validation/buildRuleBlocks.js.map +1 -1
  484. package/dist/validation/builtin/email.js +2 -1
  485. package/dist/validation/builtin/email.js.map +1 -1
  486. package/dist/validation/builtin/index.d.ts +14 -0
  487. package/dist/validation/builtin/index.js +12 -1
  488. package/dist/validation/builtin/index.js.map +1 -1
  489. package/dist/validation/builtin/matchesField.js +3 -7
  490. package/dist/validation/builtin/matchesField.js.map +1 -1
  491. package/dist/validation/builtin/max.js +1 -0
  492. package/dist/validation/builtin/max.js.map +1 -1
  493. package/dist/validation/builtin/maxDate.js +24 -0
  494. package/dist/validation/builtin/maxDate.js.map +1 -0
  495. package/dist/validation/builtin/maxLength.js +1 -0
  496. package/dist/validation/builtin/maxLength.js.map +1 -1
  497. package/dist/validation/builtin/min.js +1 -0
  498. package/dist/validation/builtin/min.js.map +1 -1
  499. package/dist/validation/builtin/minDate.js +24 -0
  500. package/dist/validation/builtin/minDate.js.map +1 -0
  501. package/dist/validation/builtin/minLength.js +1 -0
  502. package/dist/validation/builtin/minLength.js.map +1 -1
  503. package/dist/validation/builtin/notAlreadySubmitted.js +2 -0
  504. package/dist/validation/builtin/notAlreadySubmitted.js.map +1 -1
  505. package/dist/validation/builtin/oneOf.js +1 -0
  506. package/dist/validation/builtin/oneOf.js.map +1 -1
  507. package/dist/validation/builtin/pattern.js +11 -2
  508. package/dist/validation/builtin/pattern.js.map +1 -1
  509. package/dist/validation/builtin/url.js +1 -0
  510. package/dist/validation/builtin/url.js.map +1 -1
  511. package/dist/validation/builtin/validateDateBound.js +18 -0
  512. package/dist/validation/builtin/validateDateBound.js.map +1 -0
  513. package/dist/validation/builtin/validateRegexParams.js +44 -0
  514. package/dist/validation/builtin/validateRegexParams.js.map +1 -0
  515. package/dist/validation/emailPattern.js +10 -0
  516. package/dist/validation/emailPattern.js.map +1 -0
  517. package/dist/validation/fieldTargetParam.d.ts +22 -0
  518. package/dist/validation/fieldTargetParam.js +38 -0
  519. package/dist/validation/fieldTargetParam.js.map +1 -0
  520. package/dist/validation/registry.d.ts +2 -1
  521. package/dist/validation/registry.js +2 -9
  522. package/dist/validation/registry.js.map +1 -1
  523. package/dist/validation/runValidation.js +9 -30
  524. package/dist/validation/runValidation.js.map +1 -1
  525. package/dist/validation/types.d.ts +5 -11
  526. package/dist/validation/validateUrl.js +22 -0
  527. package/dist/validation/validateUrl.js.map +1 -0
  528. package/package.json +7 -5
  529. package/styles/form-builder.css +10 -190
  530. package/dist/collections/uploads.d.ts +0 -29
  531. package/dist/collections/uploads.js +0 -46
  532. package/dist/collections/uploads.js.map +0 -1
  533. package/dist/consent/buildConsentSourceConfig.js +0 -49
  534. package/dist/consent/buildConsentSourceConfig.js.map +0 -1
  535. package/dist/consent/builtin/index.d.ts +0 -7
  536. package/dist/consent/builtin/index.js +0 -11
  537. package/dist/consent/builtin/index.js.map +0 -1
  538. package/dist/consent/builtin/pageReference.js +0 -75
  539. package/dist/consent/builtin/pageReference.js.map +0 -1
  540. package/dist/consent/builtin/static.js +0 -44
  541. package/dist/consent/builtin/static.js.map +0 -1
  542. package/dist/consent/defineConsentSource.d.ts +0 -35
  543. package/dist/consent/defineConsentSource.js +0 -6
  544. package/dist/consent/defineConsentSource.js.map +0 -1
  545. package/dist/consent/registry.d.ts +0 -16
  546. package/dist/consent/registry.js +0 -16
  547. package/dist/consent/registry.js.map +0 -1
  548. package/dist/consent/resolveConsentLinks.d.ts +0 -19
  549. package/dist/consent/resolveConsentLinks.js +0 -26
  550. package/dist/consent/resolveConsentLinks.js.map +0 -1
  551. package/dist/presentations/registry.d.ts +0 -15
  552. package/dist/presentations/registry.js +0 -15
  553. package/dist/presentations/registry.js.map +0 -1
  554. package/dist/react/toFormDocument.d.ts +0 -24
  555. package/dist/react/toFormDocument.js +0 -22
  556. package/dist/react/toFormDocument.js.map +0 -1
@@ -1,90 +1,95 @@
1
1
  "use client";
2
+ import { keys } from "../translations/keys.js";
2
3
  import { interpolate } from "../recall/interpolate.js";
4
+ import { serializeBody } from "../actions/body/serializeBody.js";
3
5
  import { noopEventSink } from "../events/noopSink.js";
4
- import { CAPTCHA_TOKEN_KEY } from "../spam/constants.js";
5
- import { defaultPresentationDescriptors } from "../presentations/defaults.js";
6
+ import { CAPTCHA_TOKEN_KEY, CONTEXT_KEY, HONEYPOT_VALUE_KEY } from "../spam/constants.js";
7
+ import { fieldKey, isNamedField } from "../fields/fieldKey.js";
6
8
  import { calcExpressionOf, computeCalcFields } from "../calc/computeCalcFields.js";
7
9
  import { evaluateCondition } from "../conditions/evaluate.js";
10
+ import { resolveMessage } from "../validation/message.js";
8
11
  import { en } from "../translations/en.js";
9
- import { buildRecallResolver } from "../recall/resolver.js";
12
+ import { defaultPresentationDescriptors } from "../presentations/defaults.js";
13
+ import { buildRecallResolver, descriptorsFor } from "../recall/resolver.js";
10
14
  import { firstStepId, isTerminalStepId, resolveNextStepId, stepFieldNames } from "../flow/engine.js";
11
15
  import { cn } from "./cn.js";
12
16
  import { makeTranslate } from "../translations/makeTranslate.js";
13
17
  import { emitFormEvent } from "./events.js";
14
18
  import { FormContext } from "./FormContext.js";
15
- import { FormLayout, widthProps } from "./FormLayout.js";
19
+ import { FormControls } from "./FormControls.js";
20
+ import { DEFAULT_STEP_ID, formReducer, initialFormState, seedFieldValues } from "./state.js";
21
+ import { FormFields } from "./FormFields.js";
16
22
  import { Honeypot } from "./Honeypot.js";
17
23
  import { defaultPresentations } from "./presentation/presentations.js";
18
24
  import { resolvePresentations } from "./presentation/registry.js";
19
- import { applyRecall } from "./recall.js";
20
25
  import { resolveRenderers } from "./registry.js";
21
26
  import { defaultRenderers } from "./renderers/index.js";
22
27
  import { buildFieldTypeRegistry, buildValidationRuleRegistry, visibleFields } from "./resolveForm.js";
23
- import { formReducer, initialFormState } from "./state.js";
24
28
  import { submitForm } from "./submitForm.js";
25
- import { useField } from "./useField.js";
26
29
  import { validateFieldValue } from "./validateField.js";
27
- import { createElement, useCallback, useEffect, useId, useMemo, useReducer, useRef, useState } from "react";
28
- import { jsx, jsxs } from "react/jsx-runtime";
30
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
31
+ import { useCallback, useEffect, useMemo, useReducer, useRef, useState } from "react";
29
32
  //#region src/react/Form.tsx
30
33
  const isEmpty = (value) => value == null || value === "" || Array.isArray(value) && value.length === 0;
31
- const FIELD_WIDTHS = new Set([
32
- "full",
33
- "half",
34
- "third",
35
- "twoThirds"
36
- ]);
37
- const FieldHost = ({ field, renderer, locale, t }) => {
38
- const id = useId();
39
- const { value, errors, warnings, setValue, onBlur } = useField(field.name);
40
- return createElement(renderer, {
41
- field,
42
- id,
43
- name: field.name,
44
- value,
45
- onChange: setValue,
46
- onBlur,
47
- errors,
48
- warnings,
49
- required: Boolean(field.required),
50
- locale,
51
- t
52
- });
34
+ /** Visually hidden but screen-reader-announced, for the "Step X of Y" live region (no host CSS required). */
35
+ const SR_ONLY = {
36
+ position: "absolute",
37
+ width: 1,
38
+ height: 1,
39
+ padding: 0,
40
+ margin: -1,
41
+ overflow: "hidden",
42
+ clip: "rect(0, 0, 0, 0)",
43
+ whiteSpace: "nowrap",
44
+ border: 0
53
45
  };
54
- /** Hosts a derived (calc) field: read-only, value supplied from `effectiveValues`, never bound via `useField`. */
55
- const CalcFieldHost = ({ field, renderer, value, locale, t }) => {
56
- return createElement(renderer, {
57
- field,
58
- id: useId(),
59
- name: field.name,
60
- value,
61
- onChange: () => {},
62
- onBlur: () => {},
63
- errors: [],
64
- warnings: [],
65
- required: false,
66
- disabled: true,
67
- locale,
68
- t
69
- });
46
+ /** The base field name of an error key: the part before a repeater composite suffix (`name[0].sub`). */
47
+ const baseFieldKey = (key) => {
48
+ const bracket = key.indexOf("[");
49
+ return bracket === -1 ? key : key.slice(0, bracket);
50
+ };
51
+ /** The id of the first flow step (in order) that owns an errored field, or undefined when none does. */
52
+ const firstStepWithError = (flow, errors) => {
53
+ const errored = new Set(Object.keys(errors).map(baseFieldKey));
54
+ return flow.steps.find((flowStep) => flowStep.fields.some((key) => errored.has(key)))?.id;
55
+ };
56
+ /** The first focusable element under `root` that a step transition should land on (skips hidden/honeypot). */
57
+ const focusFirstIn = (root, selector) => {
58
+ (root?.querySelector(selector))?.focus();
70
59
  };
60
+ /** A stored button label counts only when it is a non-empty string; anything else falls through. */
61
+ const storedLabel = (value) => typeof value === "string" && value.length > 0 ? value : void 0;
71
62
  /** The headless form controller: state, progressive client validation, conditional visibility, submission, events. */
72
- const Form = ({ form, fieldTypes, rules, renderers, apiRoute, onSubmit, onSuccess, onError, events, t, locale = "en", layout, submitLabel = "Submit", nextLabel = "Next", backLabel = "Back", closeLabel = "Close", successMessage = "Thank you.", presentation, presentations, onClose, title, initialValues, honeypot, captchaToken, children, className }) => {
63
+ const Form = ({ form, fieldTypes, rules, renderers, apiRoute, onSubmit, onSuccess, onError, converters, successBehavior = "replace", events, t, locale = "en", layout, submitLabel, nextLabel, prevLabel, closeLabel, successMessage, presentation, presentations, onClose, title, initialValues, honeypot, captchaToken, context, children, header, className, renderSubmit, renderNext, renderBack, submitButtonClassName, nextButtonClassName, backButtonClassName }) => {
73
64
  const honeypotName = honeypot === false ? null : honeypot?.name ?? "website";
74
65
  const honeypotRef = useRef(null);
75
66
  const registry = useMemo(() => buildFieldTypeRegistry(fieldTypes), [fieldTypes]);
76
67
  const ruleRegistry = useMemo(() => buildValidationRuleRegistry(rules), [rules]);
77
68
  const rendererRegistry = useMemo(() => resolveRenderers(defaultRenderers, renderers), [renderers]);
78
69
  const presentationRegistry = useMemo(() => resolvePresentations(defaultPresentations, presentations), [presentations]);
79
- const activePresentation = typeof presentation === "object" ? presentation : presentationRegistry.get(presentation ?? form.defaultPresentation ?? "page") ?? presentationRegistry.get("page") ?? defaultPresentationDescriptors.page;
80
- const fieldsByName = useMemo(() => new Map(form.fields.map((field) => [field.name, field])), [form.fields]);
70
+ const activePresentation = typeof presentation === "object" ? presentation : presentationRegistry.get(presentation ?? "page") ?? presentationRegistry.get("page") ?? defaultPresentationDescriptors.page;
71
+ const fieldsByName = useMemo(() => new Map(form.fields.filter(isNamedField).map((field) => [field.name, field])), [form.fields]);
81
72
  const translate = useMemo(() => t ?? makeTranslate(en), [t]);
73
+ const resolvedCloseLabel = closeLabel ?? translate(keys.formClose);
74
+ const resolvedSuccessMessage = successMessage ?? translate(keys.formSuccess);
75
+ const docButtons = form.buttons;
76
+ const labels = useMemo(() => ({
77
+ prev: prevLabel ?? storedLabel(docButtons?.prevLabel) ?? translate(keys.formBack),
78
+ next: nextLabel ?? storedLabel(docButtons?.nextLabel) ?? translate(keys.formNext),
79
+ submit: submitLabel ?? storedLabel(docButtons?.submitLabel) ?? translate(keys.formSubmit)
80
+ }), [
81
+ prevLabel,
82
+ nextLabel,
83
+ submitLabel,
84
+ docButtons,
85
+ translate
86
+ ]);
82
87
  const sinkRef = useRef(noopEventSink);
83
88
  sinkRef.current = events ?? noopEventSink;
84
89
  const formIdRef = useRef("");
85
90
  formIdRef.current = String(form.id);
86
91
  const [state, rawDispatch] = useReducer(formReducer, form.fields, (fields) => initialFormState({
87
- ...Object.fromEntries(fields.map((field) => [field.name, void 0])),
92
+ ...seedFieldValues(fields),
88
93
  ...initialValues ?? {}
89
94
  }));
90
95
  const effectiveValues = useMemo(() => computeCalcFields(form.fields, state.values), [form.fields, state.values]);
@@ -101,14 +106,28 @@ const Form = ({ form, fieldTypes, rules, renderers, apiRoute, onSubmit, onSucces
101
106
  locale,
102
107
  translate
103
108
  ]);
104
- const flow = form.flow && form.flow.steps.length >= 2 ? form.flow : void 0;
109
+ const flow = form.multistep === true && form.flow && form.flow.steps.length >= 2 ? form.flow : void 0;
105
110
  const [currentStepId, setCurrentStepId] = useState(() => flow ? firstStepId(flow) : void 0);
106
111
  const [history, setHistory] = useState([]);
107
112
  const startedRef = useRef(false);
108
113
  const submittedRef = useRef(false);
109
114
  const submittingRef = useRef(false);
115
+ const advancingRef = useRef(false);
110
116
  const flowRef = useRef(flow);
111
117
  flowRef.current = flow;
118
+ const stepIdOfField = useMemo(() => {
119
+ const map = /* @__PURE__ */ new Map();
120
+ if (flow) for (const flowStep of flow.steps) for (const key of flowStep.fields) map.set(key, flowStep.id);
121
+ return (fieldKey) => map.get(fieldKey) ?? "__form__";
122
+ }, [flow]);
123
+ const allStepIds = useMemo(() => flow ? flow.steps.map((flowStep) => flowStep.id) : [DEFAULT_STEP_ID], [flow]);
124
+ const formRef = useRef(null);
125
+ const pendingFocusRef = useRef(null);
126
+ const [focusNonce, setFocusNonce] = useState(0);
127
+ const requestFocus = (intent) => {
128
+ pendingFocusRef.current = intent;
129
+ setFocusNonce((nonce) => nonce + 1);
130
+ };
112
131
  const dispatch = useCallback((action) => {
113
132
  if (action.type === "SET_VALUE" && !startedRef.current) {
114
133
  startedRef.current = true;
@@ -127,8 +146,7 @@ const Form = ({ form, fieldTypes, rules, renderers, apiRoute, onSubmit, onSucces
127
146
  rawDispatch({
128
147
  type: "SET_FIELD_ISSUES",
129
148
  name,
130
- errors: [],
131
- warnings: []
149
+ errors: []
132
150
  });
133
151
  return;
134
152
  }
@@ -140,12 +158,11 @@ const Form = ({ form, fieldTypes, rules, renderers, apiRoute, onSubmit, onSucces
140
158
  answers,
141
159
  locale,
142
160
  t: translate
143
- }).then(({ errors, warnings }) => {
161
+ }).then(({ errors }) => {
144
162
  rawDispatch({
145
163
  type: "SET_FIELD_ISSUES",
146
164
  name,
147
- errors,
148
- warnings
165
+ errors
149
166
  });
150
167
  const [firstError] = errors;
151
168
  if (firstError !== void 0) emitFormEvent(sinkRef.current, formIdRef.current, {
@@ -163,59 +180,169 @@ const Form = ({ form, fieldTypes, rules, renderers, apiRoute, onSubmit, onSucces
163
180
  translate
164
181
  ]);
165
182
  const visible = visibleFields(form.fields, effectiveValues);
166
- const stepVisible = (flow && currentStepId ? stepFieldNames(flow, currentStepId) : []).map((name) => visible.find((field) => field.name === name)).filter((field) => Boolean(field));
183
+ /** Visible, answered named fields. Display-only ('none' kind) and nameless (bare) fields never contribute. */
184
+ const answerableFields = () => visibleFields(form.fields, effectiveValues).filter((field) => registry.get(field.blockType)?.value !== "none").filter(isNamedField).filter((field) => !isEmpty(effectiveValues[field.name]));
185
+ /** Answered visible fields as raw submission values, sent to the server on submit. */
186
+ const answeredValues = () => answerableFields().map((field) => ({
187
+ field: field.name,
188
+ value: effectiveValues[field.name]
189
+ }));
190
+ /**
191
+ * Same fields, formatted via `recall` (option labels, Yes/No, localized dates): recall-fidelity
192
+ * values for client-rendered templates, matching what the server gives email-team's body.
193
+ */
194
+ const formattedValues = () => answerableFields().map((field) => ({
195
+ field: field.name,
196
+ value: recall(field.name)
197
+ }));
198
+ /**
199
+ * The recall-resolved success response: a redirect's url, or the response message serialized with
200
+ * the active `converters` (so host blocks survive). Shared by the success screen and the value
201
+ * handed to `onSuccess`, so both stay identical.
202
+ */
203
+ const resolveSuccessResponse = () => {
204
+ const response = form.response;
205
+ if (response?.type === "redirect") return {
206
+ type: "redirect",
207
+ url: response.redirect?.url ?? void 0
208
+ };
209
+ const message = response?.type === "message" || response?.type == null ? response?.message : void 0;
210
+ if (!message) return;
211
+ return {
212
+ type: "message",
213
+ html: serializeBody(message, {
214
+ values: formattedValues(),
215
+ descriptors: descriptorsFor(answerableFields()),
216
+ converters
217
+ })
218
+ };
219
+ };
220
+ const stepKeys = flow && currentStepId ? stepFieldNames(flow, currentStepId) : [];
221
+ const stepKeySet = new Set(stepKeys);
222
+ const stepVisible = visible.filter((field) => stepKeySet.has(fieldKey(field)));
223
+ const validateRepeaterSubFields = async (repeaters) => {
224
+ const errors = {};
225
+ for (const field of repeaters.filter((f) => f.blockType === "repeater" && isNamedField(f))) {
226
+ const rows = Array.isArray(effectiveValues[field.name]) ? effectiveValues[field.name] : [];
227
+ const subFields = (Array.isArray(field.subFields) ? field.subFields : []).filter(isNamedField);
228
+ for (let rowIndex = 0; rowIndex < rows.length; rowIndex++) {
229
+ const row = rows[rowIndex] ?? {};
230
+ for (const subField of subFields) {
231
+ if (!evaluateCondition(subField.visibleWhen, row)) continue;
232
+ if (!evaluateCondition(subField.validateWhen, row)) continue;
233
+ const subResult = await validateFieldValue({
234
+ field: subField,
235
+ value: row[subField.name],
236
+ registry,
237
+ ruleRegistry,
238
+ answers: row,
239
+ locale,
240
+ t: translate
241
+ });
242
+ const compositeKey = `${field.name}[${rowIndex}].${subField.name}`;
243
+ if (subResult.errors.length > 0) errors[compositeKey] = subResult.errors;
244
+ }
245
+ }
246
+ }
247
+ return errors;
248
+ };
167
249
  const goNext = async () => {
168
- if (!flow || !currentStepId) return;
169
- const results = await Promise.all(stepVisible.filter((field) => !calcExpressionOf(field)).filter((field) => evaluateCondition(field.validateWhen, effectiveValues)).map(async (field) => ({
170
- field,
171
- ...await validateFieldValue({
250
+ if (!flow || !currentStepId || advancingRef.current) return;
251
+ advancingRef.current = true;
252
+ try {
253
+ const results = await Promise.all(stepVisible.filter((field) => !calcExpressionOf(field)).filter((field) => registry.get(field.blockType)?.value !== "none").filter(isNamedField).filter((field) => evaluateCondition(field.validateWhen, effectiveValues)).map(async (field) => ({
172
254
  field,
173
- value: effectiveValues[field.name],
174
- registry,
175
- ruleRegistry,
176
- answers: effectiveValues,
177
- locale,
178
- t: translate
179
- })
180
- })));
181
- let hasError = false;
182
- for (const result of results) {
183
- rawDispatch({
184
- type: "TOUCH",
185
- name: result.field.name
255
+ ...await validateFieldValue({
256
+ field,
257
+ value: effectiveValues[field.name],
258
+ registry,
259
+ ruleRegistry,
260
+ answers: effectiveValues,
261
+ locale,
262
+ t: translate
263
+ })
264
+ })));
265
+ let hasError = false;
266
+ for (const result of results) {
267
+ rawDispatch({
268
+ type: "TOUCH",
269
+ name: result.field.name
270
+ });
271
+ rawDispatch({
272
+ type: "SET_FIELD_ISSUES",
273
+ name: result.field.name,
274
+ errors: result.errors
275
+ });
276
+ if (result.errors.length > 0) hasError = true;
277
+ }
278
+ const repeaterErrors = await validateRepeaterSubFields(stepVisible);
279
+ for (const [compositeKey, errs] of Object.entries(repeaterErrors)) {
280
+ rawDispatch({
281
+ type: "SET_FIELD_ISSUES",
282
+ name: compositeKey,
283
+ errors: errs
284
+ });
285
+ hasError = true;
286
+ }
287
+ if (hasError) {
288
+ rawDispatch({
289
+ type: "MARK_STEP_ATTEMPTED",
290
+ stepId: currentStepId
291
+ });
292
+ requestFocus("firstInvalid");
293
+ return;
294
+ }
295
+ const next = resolveNextStepId(flow, currentStepId, effectiveValues);
296
+ if (!next) return;
297
+ emitFormEvent(sinkRef.current, formIdRef.current, {
298
+ type: "step.completed",
299
+ stepId: currentStepId
186
300
  });
187
- rawDispatch({
188
- type: "SET_FIELD_ISSUES",
189
- name: result.field.name,
190
- errors: result.errors,
191
- warnings: result.warnings
301
+ setHistory((prev) => [...prev, currentStepId]);
302
+ setCurrentStepId(next);
303
+ requestFocus("stepStart");
304
+ emitFormEvent(sinkRef.current, formIdRef.current, {
305
+ type: "step.viewed",
306
+ stepId: next
192
307
  });
193
- if (result.errors.length > 0) hasError = true;
308
+ } finally {
309
+ advancingRef.current = false;
194
310
  }
195
- if (hasError) return;
196
- const next = resolveNextStepId(flow, currentStepId, state.values);
197
- if (!next) return;
198
- emitFormEvent(sinkRef.current, formIdRef.current, {
199
- type: "step.completed",
200
- stepId: currentStepId
201
- });
202
- setHistory((prev) => [...prev, currentStepId]);
203
- setCurrentStepId(next);
204
- emitFormEvent(sinkRef.current, formIdRef.current, {
205
- type: "step.viewed",
206
- stepId: next
207
- });
208
311
  };
209
312
  const goBack = () => {
210
313
  const prev = history[history.length - 1];
211
314
  if (prev === void 0) return;
212
315
  setHistory((entries) => entries.slice(0, -1));
213
316
  setCurrentStepId(prev);
317
+ requestFocus("stepStart");
214
318
  emitFormEvent(sinkRef.current, formIdRef.current, {
215
319
  type: "step.viewed",
216
320
  stepId: prev
217
321
  });
218
322
  };
323
+ const navigateToStep = (stepId) => {
324
+ if (!flow || stepId === currentStepId) return;
325
+ const idx = flow.steps.findIndex((flowStep) => flowStep.id === stepId);
326
+ if (idx < 0) return;
327
+ setHistory(flow.steps.slice(0, idx).map((flowStep) => flowStep.id));
328
+ setCurrentStepId(stepId);
329
+ emitFormEvent(sinkRef.current, formIdRef.current, {
330
+ type: "step.viewed",
331
+ stepId
332
+ });
333
+ };
334
+ useEffect(() => {
335
+ const intent = pendingFocusRef.current;
336
+ if (!intent) return;
337
+ pendingFocusRef.current = null;
338
+ if (intent === "firstInvalid") {
339
+ focusFirstIn(formRef.current, "[aria-invalid=\"true\"]");
340
+ return;
341
+ }
342
+ const region = formRef.current?.querySelector("[data-fb-step-region]");
343
+ if (region) region.focus();
344
+ else focusFirstIn(formRef.current, "input:not([type=\"hidden\"]), select, textarea");
345
+ }, [currentStepId, focusNonce]);
219
346
  useEffect(() => {
220
347
  emitFormEvent(sinkRef.current, formIdRef.current, { type: "form.viewed" });
221
348
  const mountFlow = flowRef.current;
@@ -238,7 +365,7 @@ const Form = ({ form, fieldTypes, rules, renderers, apiRoute, onSubmit, onSucces
238
365
  if (submittingRef.current) return;
239
366
  submittingRef.current = true;
240
367
  const visible = visibleFields(form.fields, effectiveValues);
241
- const results = await Promise.all(visible.filter((field) => !calcExpressionOf(field)).filter((field) => evaluateCondition(field.validateWhen, effectiveValues)).map(async (field) => ({
368
+ const results = await Promise.all(visible.filter((field) => !calcExpressionOf(field)).filter((field) => registry.get(field.blockType)?.value !== "none").filter(isNamedField).filter((field) => evaluateCondition(field.validateWhen, effectiveValues)).map(async (field) => ({
242
369
  field,
243
370
  ...await validateFieldValue({
244
371
  field,
@@ -251,37 +378,37 @@ const Form = ({ form, fieldTypes, rules, renderers, apiRoute, onSubmit, onSucces
251
378
  })
252
379
  })));
253
380
  const errors = {};
254
- const warnings = {};
255
- for (const result of results) {
256
- if (result.errors.length > 0) {
257
- errors[result.field.name] = result.errors;
258
- const [firstError] = result.errors;
259
- if (firstError !== void 0) emitFormEvent(sinkRef.current, formIdRef.current, {
260
- type: "field.errored",
261
- field: result.field.name,
262
- message: firstError
263
- });
264
- }
265
- if (result.warnings.length > 0) warnings[result.field.name] = result.warnings;
381
+ for (const result of results) if (result.errors.length > 0) {
382
+ errors[result.field.name] = result.errors;
383
+ const [firstError] = result.errors;
384
+ if (firstError !== void 0) emitFormEvent(sinkRef.current, formIdRef.current, {
385
+ type: "field.errored",
386
+ field: result.field.name,
387
+ message: firstError
388
+ });
266
389
  }
390
+ Object.assign(errors, await validateRepeaterSubFields(visible));
391
+ const hasErrors = Object.keys(errors).length > 0;
267
392
  rawDispatch({
268
393
  type: "SET_ALL_ISSUES",
269
394
  errors,
270
- warnings
395
+ steps: hasErrors ? allStepIds : []
271
396
  });
272
- if (Object.keys(errors).length > 0) {
397
+ if (hasErrors) {
273
398
  submittingRef.current = false;
399
+ if (flow && currentStepId) {
400
+ const target = firstStepWithError(flow, errors);
401
+ if (target) navigateToStep(target);
402
+ }
403
+ requestFocus("firstInvalid");
274
404
  return;
275
405
  }
276
406
  rawDispatch({ type: "SUBMIT_START" });
277
- const values = visible.filter((field) => !isEmpty(effectiveValues[field.name])).map((field) => ({
278
- field: field.name,
279
- value: effectiveValues[field.name]
280
- }));
407
+ const values = answeredValues();
281
408
  if (honeypotName) {
282
409
  const decoy = honeypotRef.current?.value ?? "";
283
410
  if (decoy !== "") values.push({
284
- field: honeypotName,
411
+ field: HONEYPOT_VALUE_KEY,
285
412
  value: decoy
286
413
  });
287
414
  }
@@ -289,6 +416,10 @@ const Form = ({ form, fieldTypes, rules, renderers, apiRoute, onSubmit, onSucces
289
416
  field: CAPTCHA_TOKEN_KEY,
290
417
  value: captchaToken
291
418
  });
419
+ if (context) values.push({
420
+ field: CONTEXT_KEY,
421
+ value: context
422
+ });
292
423
  const result = onSubmit ? await onSubmit({
293
424
  formId: form.id,
294
425
  values
@@ -300,20 +431,37 @@ const Form = ({ form, fieldTypes, rules, renderers, apiRoute, onSubmit, onSucces
300
431
  submittingRef.current = false;
301
432
  if (result.ok) {
302
433
  submittedRef.current = true;
303
- rawDispatch({ type: "SUBMIT_SUCCESS" });
304
434
  emitFormEvent(sinkRef.current, formIdRef.current, {
305
435
  type: "submission.created",
306
436
  submissionId: result.submissionId
307
437
  });
308
- onSuccess?.(result.submissionId);
309
- if (activePresentation.dismissOnSuccess) handleClose();
438
+ onSuccess?.(result.submissionId, { response: resolveSuccessResponse() });
439
+ if (successBehavior === "reset") {
440
+ rawDispatch({
441
+ type: "RESET",
442
+ values: {
443
+ ...seedFieldValues(form.fields),
444
+ ...initialValues ?? {}
445
+ }
446
+ });
447
+ if (flow) {
448
+ setCurrentStepId(firstStepId(flow));
449
+ setHistory([]);
450
+ }
451
+ startedRef.current = false;
452
+ } else {
453
+ rawDispatch({ type: "SUBMIT_SUCCESS" });
454
+ if (activePresentation.dismissOnSuccess) handleClose();
455
+ }
456
+ const redirectUrl = form.response?.type === "redirect" ? form.response.redirect?.url : void 0;
457
+ if (typeof redirectUrl === "string" && redirectUrl.length > 0 && typeof window !== "undefined") window.location.assign(redirectUrl);
310
458
  } else {
311
459
  if (result.fieldErrors) rawDispatch({
312
460
  type: "SET_ALL_ISSUES",
313
461
  errors: result.fieldErrors,
314
- warnings: {}
462
+ steps: allStepIds
315
463
  });
316
- const message = result.message ?? "Submission failed";
464
+ const message = result.message ?? translate(keys.formSubmitFailed);
317
465
  rawDispatch({
318
466
  type: "SUBMIT_ERROR",
319
467
  message
@@ -321,13 +469,24 @@ const Form = ({ form, fieldTypes, rules, renderers, apiRoute, onSubmit, onSucces
321
469
  onError?.(message);
322
470
  }
323
471
  };
472
+ const isTerminalStep = flow && currentStepId ? isTerminalStepId(flow, currentStepId, effectiveValues) : true;
473
+ const handleKeyDown = (event) => {
474
+ if (!flow || event.key !== "Enter") return;
475
+ const target = event.target;
476
+ if (target instanceof HTMLTextAreaElement || target instanceof HTMLSelectElement || target instanceof HTMLButtonElement) return;
477
+ if (target instanceof HTMLInputElement && (target.type === "submit" || target.type === "button")) return;
478
+ if (!isTerminalStep) {
479
+ event.preventDefault();
480
+ goNext();
481
+ }
482
+ };
324
483
  const step = flow ? {
325
484
  flow,
326
485
  currentStepId,
327
486
  stepIndex: flow.steps.findIndex((s) => s.id === currentStepId),
328
487
  stepCount: flow.steps.length,
329
488
  isFirst: history.length === 0,
330
- isTerminal: currentStepId ? isTerminalStepId(flow, currentStepId, state.values) : true,
489
+ isTerminal: isTerminalStep,
331
490
  goNext: () => {
332
491
  goNext();
333
492
  },
@@ -340,12 +499,26 @@ const Form = ({ form, fieldTypes, rules, renderers, apiRoute, onSubmit, onSucces
340
499
  goNext: () => {},
341
500
  goBack: () => {}
342
501
  };
502
+ const stepStatusText = flow ? resolveMessage(translate(keys.formStepStatus), {
503
+ current: String(step.stepIndex + 1),
504
+ total: String(step.stepCount)
505
+ }) : "";
506
+ const currentStepHasError = flow != null && currentStepId != null && state.attemptedSteps.has(currentStepId) && Object.entries(state.errors).some(([key, errs]) => errs.length > 0 && stepIdOfField(baseFieldKey(key)) === currentStepId);
343
507
  const contextValue = {
508
+ form,
344
509
  state,
345
510
  dispatch,
346
511
  validateField,
347
512
  locale,
348
- step
513
+ step,
514
+ rendererRegistry,
515
+ labels,
516
+ t: translate,
517
+ effectiveValues,
518
+ recall,
519
+ renderedFields: (flow ? stepVisible : visible).filter((field) => field.hidden !== true && field.calcDisplay !== false),
520
+ converters,
521
+ stepIdOfField
349
522
  };
350
523
  const PresentationWrapper = activePresentation.Wrapper;
351
524
  const wrap = (content) => PresentationWrapper ? /* @__PURE__ */ jsx(PresentationWrapper, {
@@ -353,15 +526,17 @@ const Form = ({ form, fieldTypes, rules, renderers, apiRoute, onSubmit, onSucces
353
526
  open: true,
354
527
  onClose: handleClose,
355
528
  title,
356
- closeLabel,
529
+ closeLabel: resolvedCloseLabel,
357
530
  children: content
358
531
  }) : content;
359
532
  if (children !== void 0) return /* @__PURE__ */ jsx(FormContext.Provider, {
360
533
  value: contextValue,
361
534
  children: wrap(/* @__PURE__ */ jsxs("form", {
535
+ ref: formRef,
362
536
  className: cn("fb-form-root", className),
363
537
  noValidate: true,
364
538
  onSubmit: handleSubmit,
539
+ onKeyDown: handleKeyDown,
365
540
  "data-fb-presentation": activePresentation.name,
366
541
  "data-fb-density": activePresentation.density,
367
542
  children: [honeypotName ? /* @__PURE__ */ jsx(Honeypot, {
@@ -370,23 +545,34 @@ const Form = ({ form, fieldTypes, rules, renderers, apiRoute, onSubmit, onSucces
370
545
  }) : null, children]
371
546
  }))
372
547
  });
373
- if (state.submitted) return /* @__PURE__ */ jsx(FormContext.Provider, {
374
- value: contextValue,
375
- children: wrap(/* @__PURE__ */ jsx("p", {
376
- role: "status",
377
- className: cn("fb-form__success", className),
378
- "data-fb-presentation": activePresentation.name,
379
- "data-fb-density": activePresentation.density,
380
- children: interpolate(successMessage, recall)
381
- }))
382
- });
383
- const rendered = (flow ? stepVisible : visible).filter((field) => field.hidden !== true && field.calcDisplay !== false);
548
+ if (state.submitted) {
549
+ const successResponse = resolveSuccessResponse();
550
+ const responseHtml = successResponse?.type === "message" ? successResponse.html : void 0;
551
+ return /* @__PURE__ */ jsx(FormContext.Provider, {
552
+ value: contextValue,
553
+ children: wrap(responseHtml ? /* @__PURE__ */ jsx("div", {
554
+ role: "status",
555
+ className: cn("fb-form__success", className),
556
+ "data-fb-presentation": activePresentation.name,
557
+ "data-fb-density": activePresentation.density,
558
+ dangerouslySetInnerHTML: { __html: responseHtml }
559
+ }) : /* @__PURE__ */ jsx("p", {
560
+ role: "status",
561
+ className: cn("fb-form__success", className),
562
+ "data-fb-presentation": activePresentation.name,
563
+ "data-fb-density": activePresentation.density,
564
+ children: interpolate(resolvedSuccessMessage, recall)
565
+ }))
566
+ });
567
+ }
384
568
  return /* @__PURE__ */ jsx(FormContext.Provider, {
385
569
  value: contextValue,
386
570
  children: wrap(/* @__PURE__ */ jsxs("form", {
571
+ ref: formRef,
387
572
  className: cn("fb-form-root", className),
388
573
  noValidate: true,
389
574
  onSubmit: handleSubmit,
575
+ onKeyDown: handleKeyDown,
390
576
  "data-fb-presentation": activePresentation.name,
391
577
  "data-fb-density": activePresentation.density,
392
578
  children: [
@@ -394,58 +580,38 @@ const Form = ({ form, fieldTypes, rules, renderers, apiRoute, onSubmit, onSucces
394
580
  name: honeypotName,
395
581
  inputRef: honeypotRef
396
582
  }) : null,
397
- /* @__PURE__ */ jsx(FormLayout, {
398
- enabled: layout !== false,
399
- children: rendered.map((field) => {
400
- const renderer = rendererRegistry.get(field.blockType);
401
- if (!renderer) return null;
402
- const width = typeof field.width === "string" && FIELD_WIDTHS.has(field.width) ? field.width : void 0;
403
- const recalledField = applyRecall(field, recall);
404
- return /* @__PURE__ */ jsx("div", {
405
- ...widthProps(width),
406
- children: calcExpressionOf(field) ? /* @__PURE__ */ jsx(CalcFieldHost, {
407
- field: recalledField,
408
- renderer,
409
- value: effectiveValues[field.name],
410
- locale,
411
- t: translate
412
- }) : /* @__PURE__ */ jsx(FieldHost, {
413
- field: recalledField,
414
- renderer,
415
- locale,
416
- t: translate
417
- })
418
- }, field.name);
419
- })
420
- }),
583
+ header,
584
+ flow ? /* @__PURE__ */ jsxs(Fragment, { children: [
585
+ /* @__PURE__ */ jsx("div", {
586
+ "aria-live": "polite",
587
+ "aria-atomic": "true",
588
+ style: SR_ONLY,
589
+ children: stepStatusText
590
+ }),
591
+ /* @__PURE__ */ jsx("div", {
592
+ "data-fb-step-region": true,
593
+ tabIndex: -1,
594
+ className: "fb-form__step",
595
+ children: /* @__PURE__ */ jsx(FormFields, { layout })
596
+ }),
597
+ currentStepHasError ? /* @__PURE__ */ jsx("p", {
598
+ role: "alert",
599
+ className: "fb-form__step-error",
600
+ children: translate(keys.formStepInvalid)
601
+ }) : null
602
+ ] }) : /* @__PURE__ */ jsx(FormFields, { layout }),
421
603
  state.submitError ? /* @__PURE__ */ jsx("p", {
422
604
  role: "alert",
423
605
  className: "fb-form__submit-error",
424
606
  children: state.submitError
425
607
  }) : null,
426
- flow ? /* @__PURE__ */ jsxs("div", {
427
- className: "fb-form__controls",
428
- children: [!step.isFirst ? /* @__PURE__ */ jsx("button", {
429
- type: "button",
430
- onClick: goBack,
431
- disabled: state.submitting,
432
- children: backLabel
433
- }) : null, step.isTerminal ? /* @__PURE__ */ jsx("button", {
434
- type: "submit",
435
- disabled: state.submitting,
436
- children: submitLabel
437
- }) : /* @__PURE__ */ jsx("button", {
438
- type: "button",
439
- disabled: state.submitting,
440
- onClick: () => {
441
- goNext();
442
- },
443
- children: nextLabel
444
- })]
445
- }) : /* @__PURE__ */ jsx("button", {
446
- type: "submit",
447
- disabled: state.submitting,
448
- children: submitLabel
608
+ /* @__PURE__ */ jsx(FormControls, {
609
+ backButtonClassName,
610
+ nextButtonClassName,
611
+ submitButtonClassName,
612
+ renderBack,
613
+ renderNext,
614
+ renderSubmit
449
615
  })
450
616
  ]
451
617
  }))