@10x-media/form-builder 0.1.0-beta.3 → 0.1.0-beta.5

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 (406) hide show
  1. package/CHANGELOG.md +125 -0
  2. package/README.md +4 -4
  3. package/dist/actions/body/serializeBody.d.ts +22 -4
  4. package/dist/actions/body/serializeBody.js +3 -1
  5. package/dist/actions/body/serializeBody.js.map +1 -1
  6. package/dist/actions/body/textOfBody.d.ts +13 -0
  7. package/dist/actions/body/textOfBody.js +35 -0
  8. package/dist/actions/body/textOfBody.js.map +1 -0
  9. package/dist/actions/builtin/confirmation.js +51 -12
  10. package/dist/actions/builtin/confirmation.js.map +1 -1
  11. package/dist/actions/builtin/emailTeam.js +82 -34
  12. package/dist/actions/builtin/emailTeam.js.map +1 -1
  13. package/dist/actions/builtin/index.d.ts +18 -1
  14. package/dist/actions/builtin/index.js +21 -7
  15. package/dist/actions/builtin/index.js.map +1 -1
  16. package/dist/actions/builtin/signedWebhook.js +2 -16
  17. package/dist/actions/builtin/signedWebhook.js.map +1 -1
  18. package/dist/actions/defineAction.d.ts +1 -1
  19. package/dist/actions/fromAddresses.d.ts +21 -0
  20. package/dist/actions/fromAddresses.js +74 -0
  21. package/dist/actions/fromAddresses.js.map +1 -0
  22. package/dist/actions/runActions.js +2 -0
  23. package/dist/actions/runActions.js.map +1 -1
  24. package/dist/actions/task.js +9 -8
  25. package/dist/actions/task.js.map +1 -1
  26. package/dist/aggregation/aggregateResponses.d.ts +9 -0
  27. package/dist/aggregation/aggregateResponses.js +8 -14
  28. package/dist/aggregation/aggregateResponses.js.map +1 -1
  29. package/dist/aggregation/resolveResultsRequest.d.ts +35 -6
  30. package/dist/aggregation/resolveResultsRequest.js +68 -11
  31. package/dist/aggregation/resolveResultsRequest.js.map +1 -1
  32. package/dist/calc/computeCalcFields.js +2 -1
  33. package/dist/calc/computeCalcFields.js.map +1 -1
  34. package/dist/client/ByteSizeField.d.ts +8 -0
  35. package/dist/client/ByteSizeField.js +3 -1
  36. package/dist/client/ByteSizeField.js.map +1 -1
  37. package/dist/client/ClosePollButton.d.ts +15 -0
  38. package/dist/client/ClosePollButton.js +80 -0
  39. package/dist/client/ClosePollButton.js.map +1 -0
  40. package/dist/client/CondensedArray.d.ts +15 -0
  41. package/dist/client/CondensedArray.js +97 -0
  42. package/dist/client/CondensedArray.js.map +1 -0
  43. package/dist/client/EndpointOptionsSelect.d.ts +45 -0
  44. package/dist/client/EndpointOptionsSelect.js +103 -0
  45. package/dist/client/EndpointOptionsSelect.js.map +1 -0
  46. package/dist/client/FieldBlockLabel.d.ts +18 -0
  47. package/dist/client/FieldBlockLabel.js +34 -0
  48. package/dist/client/FieldBlockLabel.js.map +1 -0
  49. package/dist/client/FieldNameSelect.d.ts +20 -4
  50. package/dist/client/FieldNameSelect.js +25 -14
  51. package/dist/client/FieldNameSelect.js.map +1 -1
  52. package/dist/client/FlowBuilder.d.ts +2 -1
  53. package/dist/client/FlowBuilder.js +134 -83
  54. package/dist/client/FlowBuilder.js.map +1 -1
  55. package/dist/client/RuleDescription.d.ts +21 -0
  56. package/dist/client/RuleDescription.js +19 -0
  57. package/dist/client/RuleDescription.js.map +1 -0
  58. package/dist/client/admin.css +83 -5
  59. package/dist/client/endpointOptions.js +29 -0
  60. package/dist/client/endpointOptions.js.map +1 -0
  61. package/dist/client/flowAuthoring.js +142 -0
  62. package/dist/client/flowAuthoring.js.map +1 -0
  63. package/dist/client/synthesizeClientField.js +21 -10
  64. package/dist/client/synthesizeClientField.js.map +1 -1
  65. package/dist/collections/buttonFields.d.ts +34 -0
  66. package/dist/collections/buttonFields.js +35 -0
  67. package/dist/collections/buttonFields.js.map +1 -0
  68. package/dist/collections/cells/FieldCountCell.d.ts +15 -0
  69. package/dist/collections/cells/FieldCountCell.js +18 -0
  70. package/dist/collections/cells/FieldCountCell.js.map +1 -0
  71. package/dist/collections/cells/FlowStepsCell.d.ts +14 -0
  72. package/dist/collections/cells/FlowStepsCell.js +17 -0
  73. package/dist/collections/cells/FlowStepsCell.js.map +1 -0
  74. package/dist/collections/formSubmissions.js +55 -12
  75. package/dist/collections/formSubmissions.js.map +1 -1
  76. package/dist/collections/forms.js +376 -57
  77. package/dist/collections/forms.js.map +1 -1
  78. package/dist/collections/redirectFields.d.ts +29 -0
  79. package/dist/conditions/conditionType.js +9 -2
  80. package/dist/conditions/conditionType.js.map +1 -1
  81. package/dist/conditions/normalizeConditions.js +2 -1
  82. package/dist/conditions/normalizeConditions.js.map +1 -1
  83. package/dist/consent/applyConsentStatements.d.ts +14 -0
  84. package/dist/consent/applyConsentStatements.js +17 -0
  85. package/dist/consent/applyConsentStatements.js.map +1 -0
  86. package/dist/consent/captureConsent.d.ts +19 -8
  87. package/dist/consent/captureConsent.js +34 -11
  88. package/dist/consent/captureConsent.js.map +1 -1
  89. package/dist/consent/consentSourcesField.d.ts +58 -0
  90. package/dist/consent/consentSourcesField.js +79 -0
  91. package/dist/consent/consentSourcesField.js.map +1 -0
  92. package/dist/consent/resolveConsentEntries.d.ts +24 -0
  93. package/dist/consent/resolveConsentEntries.js +43 -0
  94. package/dist/consent/resolveConsentEntries.js.map +1 -0
  95. package/dist/consent/resolveConsentSourcesRequest.d.ts +37 -0
  96. package/dist/consent/resolveConsentSourcesRequest.js +55 -0
  97. package/dist/consent/resolveConsentSourcesRequest.js.map +1 -0
  98. package/dist/consent/resolveConsentStatements.d.ts +45 -0
  99. package/dist/consent/resolveConsentStatements.js +44 -0
  100. package/dist/consent/resolveConsentStatements.js.map +1 -0
  101. package/dist/consent/resolvePublishedVersionRef.d.ts +17 -11
  102. package/dist/consent/resolvePublishedVersionRef.js +13 -10
  103. package/dist/consent/resolvePublishedVersionRef.js.map +1 -1
  104. package/dist/consent/types.d.ts +49 -0
  105. package/dist/email/departments.d.ts +55 -0
  106. package/dist/email/departments.js +130 -0
  107. package/dist/email/departments.js.map +1 -0
  108. package/dist/email/departmentsField.d.ts +49 -0
  109. package/dist/email/departmentsField.js +69 -0
  110. package/dist/email/departmentsField.js.map +1 -0
  111. package/dist/exports/client.d.ts +8 -1
  112. package/dist/exports/client.js +8 -1
  113. package/dist/exports/react.d.ts +15 -6
  114. package/dist/exports/react.js +11 -3
  115. package/dist/exports/rsc.d.ts +8 -1
  116. package/dist/exports/rsc.js +8 -1
  117. package/dist/exports/types.d.ts +18 -10
  118. package/dist/fields/buildFieldBlocks.js +43 -19
  119. package/dist/fields/buildFieldBlocks.js.map +1 -1
  120. package/dist/fields/builtin/calculation.js +7 -0
  121. package/dist/fields/builtin/calculation.js.map +1 -1
  122. package/dist/fields/builtin/checkbox.js +8 -0
  123. package/dist/fields/builtin/checkbox.js.map +1 -1
  124. package/dist/fields/builtin/consent.js +25 -15
  125. package/dist/fields/builtin/consent.js.map +1 -1
  126. package/dist/fields/builtin/country.d.ts +13 -0
  127. package/dist/fields/builtin/country.js +30 -0
  128. package/dist/fields/builtin/country.js.map +1 -0
  129. package/dist/fields/builtin/date.js +2 -0
  130. package/dist/fields/builtin/date.js.map +1 -1
  131. package/dist/fields/builtin/file.js +13 -8
  132. package/dist/fields/builtin/file.js.map +1 -1
  133. package/dist/fields/builtin/index.d.ts +13 -1
  134. package/dist/fields/builtin/index.js +20 -7
  135. package/dist/fields/builtin/index.js.map +1 -1
  136. package/dist/fields/builtin/message.js +30 -0
  137. package/dist/fields/builtin/message.js.map +1 -0
  138. package/dist/fields/builtin/repeater.js +8 -3
  139. package/dist/fields/builtin/repeater.js.map +1 -1
  140. package/dist/fields/builtin/select.js +8 -3
  141. package/dist/fields/builtin/select.js.map +1 -1
  142. package/dist/fields/builtin/state.d.ts +13 -0
  143. package/dist/fields/builtin/state.js +30 -0
  144. package/dist/fields/builtin/state.js.map +1 -0
  145. package/dist/fields/data/regions.d.ts +21 -0
  146. package/dist/fields/data/regions.js +1238 -0
  147. package/dist/fields/data/regions.js.map +1 -0
  148. package/dist/fields/fieldKey.d.ts +15 -0
  149. package/dist/fields/fieldKey.js +16 -0
  150. package/dist/fields/fieldKey.js.map +1 -0
  151. package/dist/fields/fieldNamesOfType.js +13 -8
  152. package/dist/fields/fieldNamesOfType.js.map +1 -1
  153. package/dist/fields/instanceOptions.js +20 -0
  154. package/dist/fields/instanceOptions.js.map +1 -0
  155. package/dist/fields/localizedIf.d.ts +13 -0
  156. package/dist/fields/localizedIf.js +12 -0
  157. package/dist/fields/localizedIf.js.map +1 -0
  158. package/dist/fields/registry.d.ts +1 -0
  159. package/dist/fields/registry.js +21 -2
  160. package/dist/fields/registry.js.map +1 -1
  161. package/dist/fields/sharedConfig.js +101 -51
  162. package/dist/fields/sharedConfig.js.map +1 -1
  163. package/dist/fields/types.d.ts +61 -5
  164. package/dist/flow/engine.d.ts +6 -4
  165. package/dist/flow/engine.js +11 -6
  166. package/dist/flow/engine.js.map +1 -1
  167. package/dist/flow/normalizeFlow.js +22 -7
  168. package/dist/flow/normalizeFlow.js.map +1 -1
  169. package/dist/flow/stepLabel.js +15 -0
  170. package/dist/flow/stepLabel.js.map +1 -0
  171. package/dist/flow/types.d.ts +12 -3
  172. package/dist/flow/types.js +11 -0
  173. package/dist/flow/types.js.map +1 -0
  174. package/dist/form/pollState.d.ts +22 -0
  175. package/dist/form/pollState.js +17 -0
  176. package/dist/form/pollState.js.map +1 -0
  177. package/dist/form/toFormDocument.d.ts +85 -0
  178. package/dist/form/toFormDocument.js +75 -0
  179. package/dist/form/toFormDocument.js.map +1 -0
  180. package/dist/form/types.d.ts +65 -0
  181. package/dist/index.d.ts +193 -27
  182. package/dist/index.js +59 -19
  183. package/dist/index.js.map +1 -1
  184. package/dist/plugin/customState.js +26 -0
  185. package/dist/plugin/customState.js.map +1 -0
  186. package/dist/plugin/registerCollections.js +33 -44
  187. package/dist/plugin/registerCollections.js.map +1 -1
  188. package/dist/plugin/uploadsCollection.d.ts +13 -0
  189. package/dist/plugin/uploadsCollection.js +44 -0
  190. package/dist/plugin/uploadsCollection.js.map +1 -0
  191. package/dist/poll/applyPollOptions.js +18 -0
  192. package/dist/poll/applyPollOptions.js.map +1 -0
  193. package/dist/poll/buildPollOptionSourceFields.js +50 -0
  194. package/dist/poll/buildPollOptionSourceFields.js.map +1 -0
  195. package/dist/poll/closeJob.d.ts +52 -0
  196. package/dist/poll/closeJob.js +119 -0
  197. package/dist/poll/closeJob.js.map +1 -0
  198. package/dist/poll/definePollOptionSource.d.ts +44 -0
  199. package/dist/poll/definePollOptionSource.js +6 -0
  200. package/dist/poll/definePollOptionSource.js.map +1 -0
  201. package/dist/poll/definePollType.d.ts +34 -0
  202. package/dist/poll/definePollType.js +6 -0
  203. package/dist/poll/definePollType.js.map +1 -0
  204. package/dist/poll/effectivePollOptions.d.ts +38 -0
  205. package/dist/poll/effectivePollOptions.js +64 -0
  206. package/dist/poll/effectivePollOptions.js.map +1 -0
  207. package/dist/poll/mostVoted.d.ts +21 -0
  208. package/dist/poll/mostVoted.js +32 -0
  209. package/dist/poll/mostVoted.js.map +1 -0
  210. package/dist/poll/outcomeBeforeChange.js +91 -0
  211. package/dist/poll/outcomeBeforeChange.js.map +1 -0
  212. package/dist/poll/outcomeFields.d.ts +38 -0
  213. package/dist/poll/outcomeFields.js +52 -0
  214. package/dist/poll/outcomeFields.js.map +1 -0
  215. package/dist/poll/pollTypeRegistry.d.ts +34 -0
  216. package/dist/poll/pollTypeRegistry.js +71 -0
  217. package/dist/poll/pollTypeRegistry.js.map +1 -0
  218. package/dist/poll/registry.d.ts +16 -0
  219. package/dist/poll/registry.js +16 -0
  220. package/dist/poll/registry.js.map +1 -0
  221. package/dist/poll/resolvePollCloseRequest.js +105 -0
  222. package/dist/poll/resolvePollCloseRequest.js.map +1 -0
  223. package/dist/poll/resolvePollOptions.d.ts +29 -0
  224. package/dist/poll/resolvePollOptions.js +52 -0
  225. package/dist/poll/resolvePollOptions.js.map +1 -0
  226. package/dist/poll/resolvePollOptionsRequest.js +51 -0
  227. package/dist/poll/resolvePollOptionsRequest.js.map +1 -0
  228. package/dist/poll/resolvePollOutcome.d.ts +34 -0
  229. package/dist/poll/resolvePollOutcome.js +76 -0
  230. package/dist/poll/resolvePollOutcome.js.map +1 -0
  231. package/dist/poll/resultsField.js +21 -0
  232. package/dist/poll/resultsField.js.map +1 -0
  233. package/dist/prefill/valuesFromSearchParams.js +3 -2
  234. package/dist/prefill/valuesFromSearchParams.js.map +1 -1
  235. package/dist/presentations/types.d.ts +3 -2
  236. package/dist/react/Form.d.ts +15 -33
  237. package/dist/react/Form.js +144 -119
  238. package/dist/react/Form.js.map +1 -1
  239. package/dist/react/FormContext.d.ts +37 -1
  240. package/dist/react/FormContext.js.map +1 -1
  241. package/dist/react/FormControls.d.ts +55 -0
  242. package/dist/react/FormControls.js +56 -0
  243. package/dist/react/FormControls.js.map +1 -0
  244. package/dist/react/FormResults.d.ts +6 -3
  245. package/dist/react/FormResults.js +37 -29
  246. package/dist/react/FormResults.js.map +1 -1
  247. package/dist/react/FormSteps.d.ts +17 -0
  248. package/dist/react/FormSteps.js +35 -0
  249. package/dist/react/FormSteps.js.map +1 -0
  250. package/dist/react/Poll.d.ts +17 -6
  251. package/dist/react/Poll.js +66 -18
  252. package/dist/react/Poll.js.map +1 -1
  253. package/dist/react/contract.d.ts +2 -3
  254. package/dist/react/contract.js.map +1 -1
  255. package/dist/react/fetchResults.d.ts +1 -1
  256. package/dist/react/fetchResults.js +1 -1
  257. package/dist/react/fetchResults.js.map +1 -1
  258. package/dist/react/primitives/Checkbox.d.ts +4 -2
  259. package/dist/react/primitives/Checkbox.js +2 -1
  260. package/dist/react/primitives/Checkbox.js.map +1 -1
  261. package/dist/react/primitives/FieldShell.d.ts +2 -4
  262. package/dist/react/primitives/FieldShell.js +12 -19
  263. package/dist/react/primitives/FieldShell.js.map +1 -1
  264. package/dist/react/renderers/calculation.js +1 -2
  265. package/dist/react/renderers/calculation.js.map +1 -1
  266. package/dist/react/renderers/checkbox.js +1 -2
  267. package/dist/react/renderers/checkbox.js.map +1 -1
  268. package/dist/react/renderers/consent.js +78 -34
  269. package/dist/react/renderers/consent.js.map +1 -1
  270. package/dist/react/renderers/date.js +1 -3
  271. package/dist/react/renderers/date.js.map +1 -1
  272. package/dist/react/renderers/email.js +1 -2
  273. package/dist/react/renderers/email.js.map +1 -1
  274. package/dist/react/renderers/file.js +6 -3
  275. package/dist/react/renderers/file.js.map +1 -1
  276. package/dist/react/renderers/index.js +5 -0
  277. package/dist/react/renderers/index.js.map +1 -1
  278. package/dist/react/renderers/message.js +35 -0
  279. package/dist/react/renderers/message.js.map +1 -0
  280. package/dist/react/renderers/number.js +1 -2
  281. package/dist/react/renderers/number.js.map +1 -1
  282. package/dist/react/renderers/region.js +45 -0
  283. package/dist/react/renderers/region.js.map +1 -0
  284. package/dist/react/renderers/repeater.js +7 -10
  285. package/dist/react/renderers/repeater.js.map +1 -1
  286. package/dist/react/renderers/select.js +1 -2
  287. package/dist/react/renderers/select.js.map +1 -1
  288. package/dist/react/renderers/text.js +1 -2
  289. package/dist/react/renderers/text.js.map +1 -1
  290. package/dist/react/renderers/textarea.js +1 -2
  291. package/dist/react/renderers/textarea.js.map +1 -1
  292. package/dist/react/state.d.ts +23 -2
  293. package/dist/react/state.js +16 -7
  294. package/dist/react/state.js.map +1 -1
  295. package/dist/react/uploadFile.d.ts +2 -2
  296. package/dist/react/uploadFile.js +1 -1
  297. package/dist/react/uploadFile.js.map +1 -1
  298. package/dist/react/useField.d.ts +0 -1
  299. package/dist/react/useField.js +0 -1
  300. package/dist/react/useField.js.map +1 -1
  301. package/dist/react/useFormState.d.ts +1 -1
  302. package/dist/react/useFormState.js +1 -1
  303. package/dist/react/useFormState.js.map +1 -1
  304. package/dist/react/validateField.js +3 -6
  305. package/dist/react/validateField.js.map +1 -1
  306. package/dist/recall/interpolate.d.ts +4 -3
  307. package/dist/recall/interpolate.js +5 -4
  308. package/dist/recall/interpolate.js.map +1 -1
  309. package/dist/recall/resolver.d.ts +1 -1
  310. package/dist/recall/resolver.js +14 -2
  311. package/dist/recall/resolver.js.map +1 -1
  312. package/dist/spam/captcha.d.ts +1 -1
  313. package/dist/spam/captcha.js +1 -1
  314. package/dist/spam/captcha.js.map +1 -1
  315. package/dist/submissions/SubmissionAnswers.js +6 -2
  316. package/dist/submissions/SubmissionAnswers.js.map +1 -1
  317. package/dist/submissions/SubmissionAnswersClient.js +91 -62
  318. package/dist/submissions/SubmissionAnswersClient.js.map +1 -1
  319. package/dist/submissions/createSubmission.d.ts +36 -0
  320. package/dist/submissions/createSubmission.js +26 -0
  321. package/dist/submissions/createSubmission.js.map +1 -0
  322. package/dist/submissions/runSubmission.d.ts +10 -0
  323. package/dist/submissions/runSubmission.js +92 -44
  324. package/dist/submissions/runSubmission.js.map +1 -1
  325. package/dist/submissions/types.d.ts +11 -4
  326. package/dist/submissions/validateSubmission.js +59 -10
  327. package/dist/submissions/validateSubmission.js.map +1 -1
  328. package/dist/submissions/votedCookie.d.ts +13 -0
  329. package/dist/submissions/votedCookie.js +27 -0
  330. package/dist/submissions/votedCookie.js.map +1 -0
  331. package/dist/translations/de.js +295 -0
  332. package/dist/translations/de.js.map +1 -0
  333. package/dist/translations/en.js +138 -23
  334. package/dist/translations/en.js.map +1 -1
  335. package/dist/translations/index.d.ts +2 -1
  336. package/dist/translations/index.js +6 -2
  337. package/dist/translations/index.js.map +1 -1
  338. package/dist/translations/keys.d.ts +134 -19
  339. package/dist/translations/keys.js +135 -20
  340. package/dist/translations/keys.js.map +1 -1
  341. package/dist/uploads/types.d.ts +1 -2
  342. package/dist/validation/buildRuleBlocks.js +18 -17
  343. package/dist/validation/buildRuleBlocks.js.map +1 -1
  344. package/dist/validation/builtin/email.js +1 -0
  345. package/dist/validation/builtin/email.js.map +1 -1
  346. package/dist/validation/builtin/matchesField.js +3 -7
  347. package/dist/validation/builtin/matchesField.js.map +1 -1
  348. package/dist/validation/builtin/max.js +1 -0
  349. package/dist/validation/builtin/max.js.map +1 -1
  350. package/dist/validation/builtin/maxDate.js +1 -0
  351. package/dist/validation/builtin/maxDate.js.map +1 -1
  352. package/dist/validation/builtin/maxLength.js +1 -0
  353. package/dist/validation/builtin/maxLength.js.map +1 -1
  354. package/dist/validation/builtin/min.js +1 -0
  355. package/dist/validation/builtin/min.js.map +1 -1
  356. package/dist/validation/builtin/minDate.js +1 -0
  357. package/dist/validation/builtin/minDate.js.map +1 -1
  358. package/dist/validation/builtin/minLength.js +1 -0
  359. package/dist/validation/builtin/minLength.js.map +1 -1
  360. package/dist/validation/builtin/notAlreadySubmitted.js +1 -0
  361. package/dist/validation/builtin/notAlreadySubmitted.js.map +1 -1
  362. package/dist/validation/builtin/oneOf.js +1 -0
  363. package/dist/validation/builtin/oneOf.js.map +1 -1
  364. package/dist/validation/builtin/pattern.js +11 -2
  365. package/dist/validation/builtin/pattern.js.map +1 -1
  366. package/dist/validation/builtin/url.js +1 -0
  367. package/dist/validation/builtin/url.js.map +1 -1
  368. package/dist/validation/builtin/validateRegexParams.js +44 -0
  369. package/dist/validation/builtin/validateRegexParams.js.map +1 -0
  370. package/dist/validation/fieldTargetParam.d.ts +22 -0
  371. package/dist/validation/fieldTargetParam.js +38 -0
  372. package/dist/validation/fieldTargetParam.js.map +1 -0
  373. package/dist/validation/runValidation.js +8 -29
  374. package/dist/validation/runValidation.js.map +1 -1
  375. package/dist/validation/types.d.ts +5 -11
  376. package/dist/validation/validateUrl.js +22 -0
  377. package/dist/validation/validateUrl.js.map +1 -0
  378. package/package.json +7 -6
  379. package/styles/form-builder.css +10 -0
  380. package/dist/collections/uploads.d.ts +0 -30
  381. package/dist/collections/uploads.js +0 -55
  382. package/dist/collections/uploads.js.map +0 -1
  383. package/dist/consent/buildConsentSourceConfig.js +0 -49
  384. package/dist/consent/buildConsentSourceConfig.js.map +0 -1
  385. package/dist/consent/builtin/index.d.ts +0 -7
  386. package/dist/consent/builtin/index.js +0 -11
  387. package/dist/consent/builtin/index.js.map +0 -1
  388. package/dist/consent/builtin/pageReference.js +0 -75
  389. package/dist/consent/builtin/pageReference.js.map +0 -1
  390. package/dist/consent/builtin/static.js +0 -44
  391. package/dist/consent/builtin/static.js.map +0 -1
  392. package/dist/consent/defineConsentSource.d.ts +0 -35
  393. package/dist/consent/defineConsentSource.js +0 -6
  394. package/dist/consent/defineConsentSource.js.map +0 -1
  395. package/dist/consent/registry.d.ts +0 -16
  396. package/dist/consent/registry.js +0 -16
  397. package/dist/consent/registry.js.map +0 -1
  398. package/dist/consent/resolveConsentLinks.d.ts +0 -19
  399. package/dist/consent/resolveConsentLinks.js +0 -26
  400. package/dist/consent/resolveConsentLinks.js.map +0 -1
  401. package/dist/presentations/registry.d.ts +0 -15
  402. package/dist/presentations/registry.js +0 -15
  403. package/dist/presentations/registry.js.map +0 -1
  404. package/dist/react/toFormDocument.d.ts +0 -24
  405. package/dist/react/toFormDocument.js +0 -22
  406. package/dist/react/toFormDocument.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message.js","names":[],"sources":["../../../src/react/renderers/message.tsx"],"sourcesContent":["'use client'\n\nimport { useContext, useMemo } from 'react'\nimport { serializeBody } from '../../actions/body/serializeBody'\nimport type { SubmissionValue } from '../../submissions/types'\nimport { defineFieldRenderer } from '../contract'\nimport { FormContext } from '../FormContext'\n\n/**\n * Display-only renderer for a `message` field: serializes the authored `content` rich text to HTML\n * inline between fields. Recall tokens (`{{name}}`) resolve against the current answers (calc\n * values included). Never binds form state; the field writes nothing to submissions.\n */\nexport const messageRenderer = defineFieldRenderer(({ field }) => {\n\tconst context = useContext(FormContext)\n\tconst values = context?.effectiveValues ?? context?.state.values\n\tconst html = useMemo(() => {\n\t\tconst answered: SubmissionValue[] = Object.entries(values ?? {})\n\t\t\t.filter(([, value]) => value != null && value !== '')\n\t\t\t.map(([name, value]) => ({ field: name, value }))\n\t\treturn serializeBody(field.content, { values: answered, descriptors: [] })\n\t}, [field.content, values])\n\tif (html === '') {\n\t\treturn null\n\t}\n\t// Safe to inject: serializeBody HTML-escapes all text (recall values included) and sanitizes link URLs.\n\t// biome-ignore lint/security/noDangerouslySetInnerHtml: HTML is produced by our escaping serializer, never raw user input\n\treturn <div className=\"fb-field__message\" dangerouslySetInnerHTML={{ __html: html }} />\n})\n"],"mappings":";;;;;;;;;;;;AAaA,MAAa,kBAAkB,qBAAqB,EAAE,YAAY;CACjE,MAAM,UAAU,WAAW,WAAW;CACtC,MAAM,SAAS,SAAS,mBAAmB,SAAS,MAAM;CAC1D,MAAM,OAAO,cAAc;EAC1B,MAAM,WAA8B,OAAO,QAAQ,UAAU,CAAC,CAAC,EAC7D,QAAQ,GAAG,WAAW,SAAS,QAAQ,UAAU,EAAE,EACnD,KAAK,CAAC,MAAM,YAAY;GAAE,OAAO;GAAM;EAAM,EAAE;EACjD,OAAO,cAAc,MAAM,SAAS;GAAE,QAAQ;GAAU,aAAa,CAAC;EAAE,CAAC;CAC1E,GAAG,CAAC,MAAM,SAAS,MAAM,CAAC;CAC1B,IAAI,SAAS,IACZ,OAAO;CAIR,OAAO,oBAAC,OAAD;EAAK,WAAU;EAAoB,yBAAyB,EAAE,QAAQ,KAAK;CAAI,CAAA;AACvF,CAAC"}
@@ -5,7 +5,7 @@ import { Input } from "../primitives/Input.js";
5
5
  import { jsx } from "react/jsx-runtime";
6
6
  import { useId } from "react";
7
7
  //#region src/react/renderers/number.tsx
8
- const numberRenderer = defineFieldRenderer(({ field, name, value, onChange, onBlur, errors, warnings, required, disabled }) => {
8
+ const numberRenderer = defineFieldRenderer(({ field, name, value, onChange, onBlur, errors, required, disabled }) => {
9
9
  const id = useId();
10
10
  const describedById = `${id}-desc`;
11
11
  return /* @__PURE__ */ jsx(FieldShell, {
@@ -14,7 +14,6 @@ const numberRenderer = defineFieldRenderer(({ field, name, value, onChange, onBl
14
14
  description: typeof field.description === "string" ? field.description : void 0,
15
15
  required,
16
16
  errors,
17
- warnings,
18
17
  describedById,
19
18
  children: /* @__PURE__ */ jsx(Input, {
20
19
  id,
@@ -1 +1 @@
1
- {"version":3,"file":"number.js","names":[],"sources":["../../../src/react/renderers/number.tsx"],"sourcesContent":["'use client'\n\nimport { useId } from 'react'\nimport { defineFieldRenderer } from '../contract'\nimport { FieldShell } from '../primitives/FieldShell'\nimport { Input } from '../primitives/Input'\n\nexport const numberRenderer = defineFieldRenderer<number | undefined>(\n\t({ field, name, value, onChange, onBlur, errors, warnings, required, disabled }) => {\n\t\tconst id = useId()\n\t\tconst describedById = `${id}-desc`\n\t\treturn (\n\t\t\t<FieldShell\n\t\t\t\tid={id}\n\t\t\t\tlabel={field.label}\n\t\t\t\tdescription={typeof field.description === 'string' ? field.description : undefined}\n\t\t\t\trequired={required}\n\t\t\t\terrors={errors}\n\t\t\t\twarnings={warnings}\n\t\t\t\tdescribedById={describedById}\n\t\t\t>\n\t\t\t\t<Input\n\t\t\t\t\tid={id}\n\t\t\t\t\tname={name}\n\t\t\t\t\ttype=\"number\"\n\t\t\t\t\tvalue={value == null ? '' : String(value)}\n\t\t\t\t\tonChange={(raw) => {\n\t\t\t\t\t\tconst next = Number(raw)\n\t\t\t\t\t\tonChange(raw === '' || Number.isNaN(next) ? undefined : next)\n\t\t\t\t\t}}\n\t\t\t\t\tonBlur={onBlur}\n\t\t\t\t\tplaceholder={typeof field.placeholder === 'string' ? field.placeholder : undefined}\n\t\t\t\t\trequired={required}\n\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\tinvalid={errors.length > 0}\n\t\t\t\t\tdescribedById={describedById}\n\t\t\t\t/>\n\t\t\t</FieldShell>\n\t\t)\n\t}\n)\n"],"mappings":";;;;;;;AAOA,MAAa,iBAAiB,qBAC5B,EAAE,OAAO,MAAM,OAAO,UAAU,QAAQ,QAAQ,UAAU,UAAU,eAAe;CACnF,MAAM,KAAK,MAAM;CACjB,MAAM,gBAAgB,GAAG,GAAG;CAC5B,OACC,oBAAC,YAAD;EACK;EACJ,OAAO,MAAM;EACb,aAAa,OAAO,MAAM,gBAAgB,WAAW,MAAM,cAAc,KAAA;EAC/D;EACF;EACE;EACK;YAEf,oBAAC,OAAD;GACK;GACE;GACN,MAAK;GACL,OAAO,SAAS,OAAO,KAAK,OAAO,KAAK;GACxC,WAAW,QAAQ;IAClB,MAAM,OAAO,OAAO,GAAG;IACvB,SAAS,QAAQ,MAAM,OAAO,MAAM,IAAI,IAAI,KAAA,IAAY,IAAI;GAC7D;GACQ;GACR,aAAa,OAAO,MAAM,gBAAgB,WAAW,MAAM,cAAc,KAAA;GAC/D;GACA;GACV,SAAS,OAAO,SAAS;GACV;EACf,CAAA;CACU,CAAA;AAEd,CACD"}
1
+ {"version":3,"file":"number.js","names":[],"sources":["../../../src/react/renderers/number.tsx"],"sourcesContent":["'use client'\n\nimport { useId } from 'react'\nimport { defineFieldRenderer } from '../contract'\nimport { FieldShell } from '../primitives/FieldShell'\nimport { Input } from '../primitives/Input'\n\nexport const numberRenderer = defineFieldRenderer<number | undefined>(\n\t({ field, name, value, onChange, onBlur, errors, required, disabled }) => {\n\t\tconst id = useId()\n\t\tconst describedById = `${id}-desc`\n\t\treturn (\n\t\t\t<FieldShell\n\t\t\t\tid={id}\n\t\t\t\tlabel={field.label}\n\t\t\t\tdescription={typeof field.description === 'string' ? field.description : undefined}\n\t\t\t\trequired={required}\n\t\t\t\terrors={errors}\n\t\t\t\tdescribedById={describedById}\n\t\t\t>\n\t\t\t\t<Input\n\t\t\t\t\tid={id}\n\t\t\t\t\tname={name}\n\t\t\t\t\ttype=\"number\"\n\t\t\t\t\tvalue={value == null ? '' : String(value)}\n\t\t\t\t\tonChange={(raw) => {\n\t\t\t\t\t\tconst next = Number(raw)\n\t\t\t\t\t\tonChange(raw === '' || Number.isNaN(next) ? undefined : next)\n\t\t\t\t\t}}\n\t\t\t\t\tonBlur={onBlur}\n\t\t\t\t\tplaceholder={typeof field.placeholder === 'string' ? field.placeholder : undefined}\n\t\t\t\t\trequired={required}\n\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\tinvalid={errors.length > 0}\n\t\t\t\t\tdescribedById={describedById}\n\t\t\t\t/>\n\t\t\t</FieldShell>\n\t\t)\n\t}\n)\n"],"mappings":";;;;;;;AAOA,MAAa,iBAAiB,qBAC5B,EAAE,OAAO,MAAM,OAAO,UAAU,QAAQ,QAAQ,UAAU,eAAe;CACzE,MAAM,KAAK,MAAM;CACjB,MAAM,gBAAgB,GAAG,GAAG;CAC5B,OACC,oBAAC,YAAD;EACK;EACJ,OAAO,MAAM;EACb,aAAa,OAAO,MAAM,gBAAgB,WAAW,MAAM,cAAc,KAAA;EAC/D;EACF;EACO;YAEf,oBAAC,OAAD;GACK;GACE;GACN,MAAK;GACL,OAAO,SAAS,OAAO,KAAK,OAAO,KAAK;GACxC,WAAW,QAAQ;IAClB,MAAM,OAAO,OAAO,GAAG;IACvB,SAAS,QAAQ,MAAM,OAAO,MAAM,IAAI,IAAI,KAAA,IAAY,IAAI;GAC7D;GACQ;GACR,aAAa,OAAO,MAAM,gBAAgB,WAAW,MAAM,cAAc,KAAA;GAC/D;GACA;GACV,SAAS,OAAO,SAAS;GACV;EACf,CAAA;CACU,CAAA;AAEd,CACD"}
@@ -0,0 +1,45 @@
1
+ "use client";
2
+ import { COUNTRIES, US_STATES } from "../../fields/data/regions.js";
3
+ import { defineFieldRenderer } from "../contract.js";
4
+ import { FieldShell } from "../primitives/FieldShell.js";
5
+ import { Select } from "../primitives/Select.js";
6
+ import { jsx } from "react/jsx-runtime";
7
+ import { useId } from "react";
8
+ //#region src/react/renderers/region.tsx
9
+ /**
10
+ * A `<select>` over a fixed, code-supplied option set, for field types (country/state) whose choices
11
+ * live in the plugin rather than in per-instance `options`. Mirrors `selectRenderer` but takes the
12
+ * options as a closure argument instead of reading `field.options`, so the stored value is one of the
13
+ * fixed codes and the placeholder still gates the empty selection.
14
+ */
15
+ const regionRenderer = (options) => defineFieldRenderer(({ field, name, value, onChange, onBlur, errors, required, disabled }) => {
16
+ const id = useId();
17
+ const describedById = `${id}-desc`;
18
+ return /* @__PURE__ */ jsx(FieldShell, {
19
+ id,
20
+ label: field.label,
21
+ description: typeof field.description === "string" ? field.description : void 0,
22
+ required,
23
+ errors,
24
+ describedById,
25
+ children: /* @__PURE__ */ jsx(Select, {
26
+ id,
27
+ name,
28
+ value: value ?? "",
29
+ options,
30
+ onChange,
31
+ onBlur,
32
+ placeholder: typeof field.placeholder === "string" ? field.placeholder : void 0,
33
+ required,
34
+ disabled,
35
+ invalid: errors.length > 0,
36
+ describedById
37
+ })
38
+ });
39
+ });
40
+ const countryRenderer = regionRenderer(COUNTRIES);
41
+ const stateRenderer = regionRenderer(US_STATES);
42
+ //#endregion
43
+ export { countryRenderer, stateRenderer };
44
+
45
+ //# sourceMappingURL=region.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"region.js","names":[],"sources":["../../../src/react/renderers/region.tsx"],"sourcesContent":["'use client'\n\nimport { useId } from 'react'\nimport { COUNTRIES, US_STATES } from '../../fields/data/regions'\nimport { defineFieldRenderer } from '../contract'\nimport { FieldShell } from '../primitives/FieldShell'\nimport { Select, type SelectOption } from '../primitives/Select'\n\n/**\n * A `<select>` over a fixed, code-supplied option set, for field types (country/state) whose choices\n * live in the plugin rather than in per-instance `options`. Mirrors `selectRenderer` but takes the\n * options as a closure argument instead of reading `field.options`, so the stored value is one of the\n * fixed codes and the placeholder still gates the empty selection.\n */\nconst regionRenderer = (options: SelectOption[]) =>\n\tdefineFieldRenderer<string>(\n\t\t({ field, name, value, onChange, onBlur, errors, required, disabled }) => {\n\t\t\tconst id = useId()\n\t\t\tconst describedById = `${id}-desc`\n\t\t\treturn (\n\t\t\t\t<FieldShell\n\t\t\t\t\tid={id}\n\t\t\t\t\tlabel={field.label}\n\t\t\t\t\tdescription={typeof field.description === 'string' ? field.description : undefined}\n\t\t\t\t\trequired={required}\n\t\t\t\t\terrors={errors}\n\t\t\t\t\tdescribedById={describedById}\n\t\t\t\t>\n\t\t\t\t\t<Select\n\t\t\t\t\t\tid={id}\n\t\t\t\t\t\tname={name}\n\t\t\t\t\t\tvalue={value ?? ''}\n\t\t\t\t\t\toptions={options}\n\t\t\t\t\t\tonChange={onChange}\n\t\t\t\t\t\tonBlur={onBlur}\n\t\t\t\t\t\tplaceholder={typeof field.placeholder === 'string' ? field.placeholder : undefined}\n\t\t\t\t\t\trequired={required}\n\t\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\t\tinvalid={errors.length > 0}\n\t\t\t\t\t\tdescribedById={describedById}\n\t\t\t\t\t/>\n\t\t\t\t</FieldShell>\n\t\t\t)\n\t\t}\n\t)\n\nexport const countryRenderer = regionRenderer(COUNTRIES)\nexport const stateRenderer = regionRenderer(US_STATES)\n"],"mappings":";;;;;;;;;;;;;;AAcA,MAAM,kBAAkB,YACvB,qBACE,EAAE,OAAO,MAAM,OAAO,UAAU,QAAQ,QAAQ,UAAU,eAAe;CACzE,MAAM,KAAK,MAAM;CACjB,MAAM,gBAAgB,GAAG,GAAG;CAC5B,OACC,oBAAC,YAAD;EACK;EACJ,OAAO,MAAM;EACb,aAAa,OAAO,MAAM,gBAAgB,WAAW,MAAM,cAAc,KAAA;EAC/D;EACF;EACO;YAEf,oBAAC,QAAD;GACK;GACE;GACN,OAAO,SAAS;GACP;GACC;GACF;GACR,aAAa,OAAO,MAAM,gBAAgB,WAAW,MAAM,cAAc,KAAA;GAC/D;GACA;GACV,SAAS,OAAO,SAAS;GACV;EACf,CAAA;CACU,CAAA;AAEd,CACD;AAED,MAAa,kBAAkB,eAAe,SAAS;AACvD,MAAa,gBAAgB,eAAe,SAAS"}
@@ -1,5 +1,6 @@
1
1
  "use client";
2
2
  import { keys } from "../../translations/keys.js";
3
+ import { isNamedField } from "../../fields/fieldKey.js";
3
4
  import { defineFieldRenderer } from "../contract.js";
4
5
  import { useFormContext } from "../FormContext.js";
5
6
  import { FieldShell } from "../primitives/FieldShell.js";
@@ -9,27 +10,25 @@ import { createElement, useId } from "react";
9
10
  //#region src/react/renderers/repeater.tsx
10
11
  /**
11
12
  * Thin wrapper so each sub-field renderer is a proper React component (has stable hook identity
12
- * per row/field). Reads errors and warnings for the composite path `field[row].subField` from
13
+ * per row/field). Reads errors for the composite path `field[row].subField` from
13
14
  * form state so server-side validation errors are surfaced inline next to the sub-field input,
14
15
  * overriding any static values passed by the parent.
15
16
  */
16
17
  const SubFieldWrapper = ({ renderer, name, ...props }) => {
17
18
  const { state } = useFormContext();
18
19
  const errors = state.errors?.[name] ?? [];
19
- const warnings = state.warnings?.[name] ?? [];
20
20
  return renderer({
21
21
  ...props,
22
22
  name,
23
- errors,
24
- warnings
23
+ errors
25
24
  });
26
25
  };
27
- const repeaterRenderer = defineFieldRenderer(({ field, id: rootId, errors, warnings, required, t, locale }) => {
26
+ const repeaterRenderer = defineFieldRenderer(({ field, name, id: rootId, errors, required, t, locale }) => {
28
27
  const { rendererRegistry } = useFormContext();
29
- const { value, setValue, onBlur } = useField(field.name);
28
+ const { value, setValue, onBlur } = useField(name);
30
29
  const addId = useId();
31
30
  const rows = Array.isArray(value) ? value : [];
32
- const subFields = Array.isArray(field.subFields) ? field.subFields : [];
31
+ const subFields = (Array.isArray(field.subFields) ? field.subFields : []).filter(isNamedField);
33
32
  const maxRows = typeof field.maxRows === "number" ? field.maxRows : void 0;
34
33
  const minRows = typeof field.minRows === "number" ? field.minRows : 0;
35
34
  const addLabel = typeof field.addLabel === "string" && field.addLabel.length > 0 ? field.addLabel : t(keys.repeaterAddRow);
@@ -54,7 +53,6 @@ const repeaterRenderer = defineFieldRenderer(({ field, id: rootId, errors, warni
54
53
  description: typeof field.description === "string" ? field.description : void 0,
55
54
  required,
56
55
  errors,
57
- warnings,
58
56
  describedById: `${rootId}-desc`,
59
57
  children: /* @__PURE__ */ jsxs("div", {
60
58
  className: "fb-repeater",
@@ -82,12 +80,11 @@ const repeaterRenderer = defineFieldRenderer(({ field, id: rootId, errors, warni
82
80
  renderer,
83
81
  field: subField,
84
82
  id: `${rootId}-${rowIndex}-${subField.name}`,
85
- name: `${field.name}[${rowIndex}].${subField.name}`,
83
+ name: `${name}[${rowIndex}].${subField.name}`,
86
84
  value: row[subField.name],
87
85
  onChange: (v) => updateRow(rowIndex, subField.name, v),
88
86
  onBlur,
89
87
  errors: [],
90
- warnings: [],
91
88
  required: subField.required ?? false,
92
89
  disabled: false,
93
90
  locale,
@@ -1 +1 @@
1
- {"version":3,"file":"repeater.js","names":[],"sources":["../../../src/react/renderers/repeater.tsx"],"sourcesContent":["'use client'\n\nimport { createElement, useId } from 'react'\nimport type { FormFieldInstance } from '../../submissions/types'\nimport { keys } from '../../translations/keys'\nimport type { FieldRenderer } from '../contract'\nimport { defineFieldRenderer } from '../contract'\nimport { useFormContext } from '../FormContext'\nimport { FieldShell } from '../primitives/FieldShell'\nimport { useField } from '../useField'\n\ntype RepeaterRow = Record<string, unknown>\n\n/**\n * Thin wrapper so each sub-field renderer is a proper React component (has stable hook identity\n * per row/field). Reads errors and warnings for the composite path `field[row].subField` from\n * form state so server-side validation errors are surfaced inline next to the sub-field input,\n * overriding any static values passed by the parent.\n */\nconst SubFieldWrapper = ({\n\trenderer,\n\tname,\n\t...props\n}: { renderer: FieldRenderer } & Parameters<FieldRenderer>[0]) => {\n\tconst { state } = useFormContext()\n\tconst errors = (state.errors as Record<string, string[]>)?.[name] ?? []\n\tconst warnings = (state.warnings as Record<string, string[]>)?.[name] ?? []\n\treturn renderer({ ...props, name, errors, warnings })\n}\n\nexport const repeaterRenderer = defineFieldRenderer<RepeaterRow[]>(\n\t({ field, id: rootId, errors, warnings, required, t, locale }) => {\n\t\tconst { rendererRegistry } = useFormContext()\n\t\tconst { value, setValue, onBlur } = useField<RepeaterRow[]>(field.name)\n\t\tconst addId = useId()\n\n\t\tconst rows = Array.isArray(value) ? value : []\n\t\tconst subFields = Array.isArray(field.subFields) ? (field.subFields as FormFieldInstance[]) : []\n\t\tconst maxRows = typeof field.maxRows === 'number' ? field.maxRows : undefined\n\t\tconst minRows = typeof field.minRows === 'number' ? field.minRows : 0\n\t\tconst addLabel =\n\t\t\ttypeof field.addLabel === 'string' && field.addLabel.length > 0\n\t\t\t\t? field.addLabel\n\t\t\t\t: t(keys.repeaterAddRow)\n\n\t\tconst addRow = () => {\n\t\t\tif (maxRows != null && rows.length >= maxRows) return\n\t\t\tsetValue([...rows, {}])\n\t\t\tonBlur()\n\t\t}\n\n\t\tconst removeRow = (index: number) => {\n\t\t\tsetValue(rows.filter((_, i) => i !== index))\n\t\t\tonBlur()\n\t\t}\n\n\t\tconst updateRow = (index: number, fieldName: string, fieldValue: unknown) => {\n\t\t\tsetValue(rows.map((row, i) => (i === index ? { ...row, [fieldName]: fieldValue } : row)))\n\t\t}\n\n\t\treturn (\n\t\t\t<FieldShell\n\t\t\t\tid={rootId}\n\t\t\t\tlabel={typeof field.label === 'string' ? field.label : undefined}\n\t\t\t\tdescription={typeof field.description === 'string' ? field.description : undefined}\n\t\t\t\trequired={required}\n\t\t\t\terrors={errors}\n\t\t\t\twarnings={warnings}\n\t\t\t\tdescribedById={`${rootId}-desc`}\n\t\t\t>\n\t\t\t\t<div className=\"fb-repeater\">\n\t\t\t\t\t{rows.map((row, rowIndex) => {\n\t\t\t\t\t\tconst rowLabel = t(keys.repeaterRow).replace('{n}', String(rowIndex + 1))\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t// biome-ignore lint/suspicious/noArrayIndexKey: repeater rows have no stable ID; index key is intentional\n\t\t\t\t\t\t\t<fieldset key={rowIndex} className=\"fb-repeater__row\">\n\t\t\t\t\t\t\t\t<legend className=\"fb-repeater__row-legend\">\n\t\t\t\t\t\t\t\t\t{rowLabel}\n\t\t\t\t\t\t\t\t\t{rows.length > minRows && (\n\t\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"fb-repeater__remove\"\n\t\t\t\t\t\t\t\t\t\t\tonClick={() => removeRow(rowIndex)}\n\t\t\t\t\t\t\t\t\t\t\taria-label={`${t(keys.repeaterRemoveRow)} ${rowLabel}`}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t{t(keys.repeaterRemoveRow)}\n\t\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t</legend>\n\t\t\t\t\t\t\t\t<div className=\"fb-repeater__row-fields\">\n\t\t\t\t\t\t\t\t\t{subFields.map((subField) => {\n\t\t\t\t\t\t\t\t\t\tconst renderer = rendererRegistry.get(subField.blockType)\n\t\t\t\t\t\t\t\t\t\tif (!renderer) return null\n\t\t\t\t\t\t\t\t\t\tconst subId = `${rootId}-${rowIndex}-${subField.name}`\n\t\t\t\t\t\t\t\t\t\tconst compositeName = `${field.name}[${rowIndex}].${subField.name}`\n\t\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t\t<div key={subField.name} className=\"fb-repeater__sub-field\">\n\t\t\t\t\t\t\t\t\t\t\t\t{createElement(SubFieldWrapper, {\n\t\t\t\t\t\t\t\t\t\t\t\t\trenderer,\n\t\t\t\t\t\t\t\t\t\t\t\t\tfield: subField,\n\t\t\t\t\t\t\t\t\t\t\t\t\tid: subId,\n\t\t\t\t\t\t\t\t\t\t\t\t\tname: compositeName,\n\t\t\t\t\t\t\t\t\t\t\t\t\tvalue: row[subField.name],\n\t\t\t\t\t\t\t\t\t\t\t\t\tonChange: (v) => updateRow(rowIndex, subField.name, v),\n\t\t\t\t\t\t\t\t\t\t\t\t\tonBlur,\n\t\t\t\t\t\t\t\t\t\t\t\t\t// SubFieldWrapper overrides these from form state; passed here to satisfy the type\n\t\t\t\t\t\t\t\t\t\t\t\t\terrors: [],\n\t\t\t\t\t\t\t\t\t\t\t\t\twarnings: [],\n\t\t\t\t\t\t\t\t\t\t\t\t\trequired: subField.required ?? false,\n\t\t\t\t\t\t\t\t\t\t\t\t\tdisabled: false,\n\t\t\t\t\t\t\t\t\t\t\t\t\tlocale,\n\t\t\t\t\t\t\t\t\t\t\t\t\tt,\n\t\t\t\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</fieldset>\n\t\t\t\t\t\t)\n\t\t\t\t\t})}\n\t\t\t\t\t{(maxRows == null || rows.length < maxRows) && (\n\t\t\t\t\t\t<button id={addId} type=\"button\" className=\"fb-repeater__add\" onClick={addRow}>\n\t\t\t\t\t\t\t{addLabel}\n\t\t\t\t\t\t</button>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t</FieldShell>\n\t\t)\n\t}\n)\n"],"mappings":"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"}
1
+ {"version":3,"file":"repeater.js","names":[],"sources":["../../../src/react/renderers/repeater.tsx"],"sourcesContent":["'use client'\n\nimport { createElement, useId } from 'react'\nimport { isNamedField } from '../../fields/fieldKey'\nimport type { FormFieldInstance } from '../../submissions/types'\nimport { keys } from '../../translations/keys'\nimport type { FieldRenderer } from '../contract'\nimport { defineFieldRenderer } from '../contract'\nimport { useFormContext } from '../FormContext'\nimport { FieldShell } from '../primitives/FieldShell'\nimport { useField } from '../useField'\n\ntype RepeaterRow = Record<string, unknown>\n\n/**\n * Thin wrapper so each sub-field renderer is a proper React component (has stable hook identity\n * per row/field). Reads errors for the composite path `field[row].subField` from\n * form state so server-side validation errors are surfaced inline next to the sub-field input,\n * overriding any static values passed by the parent.\n */\nconst SubFieldWrapper = ({\n\trenderer,\n\tname,\n\t...props\n}: { renderer: FieldRenderer } & Parameters<FieldRenderer>[0]) => {\n\tconst { state } = useFormContext()\n\tconst errors = (state.errors as Record<string, string[]>)?.[name] ?? []\n\treturn renderer({ ...props, name, errors })\n}\n\nexport const repeaterRenderer = defineFieldRenderer<RepeaterRow[]>(\n\t({ field, name, id: rootId, errors, required, t, locale }) => {\n\t\tconst { rendererRegistry } = useFormContext()\n\t\tconst { value, setValue, onBlur } = useField<RepeaterRow[]>(name)\n\t\tconst addId = useId()\n\n\t\tconst rows = Array.isArray(value) ? value : []\n\t\tconst subFields = (\n\t\t\tArray.isArray(field.subFields) ? (field.subFields as FormFieldInstance[]) : []\n\t\t).filter(isNamedField)\n\t\tconst maxRows = typeof field.maxRows === 'number' ? field.maxRows : undefined\n\t\tconst minRows = typeof field.minRows === 'number' ? field.minRows : 0\n\t\tconst addLabel =\n\t\t\ttypeof field.addLabel === 'string' && field.addLabel.length > 0\n\t\t\t\t? field.addLabel\n\t\t\t\t: t(keys.repeaterAddRow)\n\n\t\tconst addRow = () => {\n\t\t\tif (maxRows != null && rows.length >= maxRows) return\n\t\t\tsetValue([...rows, {}])\n\t\t\tonBlur()\n\t\t}\n\n\t\tconst removeRow = (index: number) => {\n\t\t\tsetValue(rows.filter((_, i) => i !== index))\n\t\t\tonBlur()\n\t\t}\n\n\t\tconst updateRow = (index: number, fieldName: string, fieldValue: unknown) => {\n\t\t\tsetValue(rows.map((row, i) => (i === index ? { ...row, [fieldName]: fieldValue } : row)))\n\t\t}\n\n\t\treturn (\n\t\t\t<FieldShell\n\t\t\t\tid={rootId}\n\t\t\t\tlabel={typeof field.label === 'string' ? field.label : undefined}\n\t\t\t\tdescription={typeof field.description === 'string' ? field.description : undefined}\n\t\t\t\trequired={required}\n\t\t\t\terrors={errors}\n\t\t\t\tdescribedById={`${rootId}-desc`}\n\t\t\t>\n\t\t\t\t<div className=\"fb-repeater\">\n\t\t\t\t\t{rows.map((row, rowIndex) => {\n\t\t\t\t\t\tconst rowLabel = t(keys.repeaterRow).replace('{n}', String(rowIndex + 1))\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t// biome-ignore lint/suspicious/noArrayIndexKey: repeater rows have no stable ID; index key is intentional\n\t\t\t\t\t\t\t<fieldset key={rowIndex} className=\"fb-repeater__row\">\n\t\t\t\t\t\t\t\t<legend className=\"fb-repeater__row-legend\">\n\t\t\t\t\t\t\t\t\t{rowLabel}\n\t\t\t\t\t\t\t\t\t{rows.length > minRows && (\n\t\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"fb-repeater__remove\"\n\t\t\t\t\t\t\t\t\t\t\tonClick={() => removeRow(rowIndex)}\n\t\t\t\t\t\t\t\t\t\t\taria-label={`${t(keys.repeaterRemoveRow)} ${rowLabel}`}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t{t(keys.repeaterRemoveRow)}\n\t\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t</legend>\n\t\t\t\t\t\t\t\t<div className=\"fb-repeater__row-fields\">\n\t\t\t\t\t\t\t\t\t{subFields.map((subField) => {\n\t\t\t\t\t\t\t\t\t\tconst renderer = rendererRegistry.get(subField.blockType)\n\t\t\t\t\t\t\t\t\t\tif (!renderer) return null\n\t\t\t\t\t\t\t\t\t\tconst subId = `${rootId}-${rowIndex}-${subField.name}`\n\t\t\t\t\t\t\t\t\t\tconst compositeName = `${name}[${rowIndex}].${subField.name}`\n\t\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t\t<div key={subField.name} className=\"fb-repeater__sub-field\">\n\t\t\t\t\t\t\t\t\t\t\t\t{createElement(SubFieldWrapper, {\n\t\t\t\t\t\t\t\t\t\t\t\t\trenderer,\n\t\t\t\t\t\t\t\t\t\t\t\t\tfield: subField,\n\t\t\t\t\t\t\t\t\t\t\t\t\tid: subId,\n\t\t\t\t\t\t\t\t\t\t\t\t\tname: compositeName,\n\t\t\t\t\t\t\t\t\t\t\t\t\tvalue: row[subField.name],\n\t\t\t\t\t\t\t\t\t\t\t\t\tonChange: (v) => updateRow(rowIndex, subField.name, v),\n\t\t\t\t\t\t\t\t\t\t\t\t\tonBlur,\n\t\t\t\t\t\t\t\t\t\t\t\t\t// SubFieldWrapper overrides these from form state; passed here to satisfy the type\n\t\t\t\t\t\t\t\t\t\t\t\t\terrors: [],\n\t\t\t\t\t\t\t\t\t\t\t\t\trequired: subField.required ?? false,\n\t\t\t\t\t\t\t\t\t\t\t\t\tdisabled: false,\n\t\t\t\t\t\t\t\t\t\t\t\t\tlocale,\n\t\t\t\t\t\t\t\t\t\t\t\t\tt,\n\t\t\t\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</fieldset>\n\t\t\t\t\t\t)\n\t\t\t\t\t})}\n\t\t\t\t\t{(maxRows == null || rows.length < maxRows) && (\n\t\t\t\t\t\t<button id={addId} type=\"button\" className=\"fb-repeater__add\" onClick={addRow}>\n\t\t\t\t\t\t\t{addLabel}\n\t\t\t\t\t\t</button>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t</FieldShell>\n\t\t)\n\t}\n)\n"],"mappings":"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"}
@@ -5,7 +5,7 @@ import { Select } from "../primitives/Select.js";
5
5
  import { jsx } from "react/jsx-runtime";
6
6
  import { useId } from "react";
7
7
  //#region src/react/renderers/select.tsx
8
- const selectRenderer = defineFieldRenderer(({ field, name, value, onChange, onBlur, errors, warnings, required, disabled }) => {
8
+ const selectRenderer = defineFieldRenderer(({ field, name, value, onChange, onBlur, errors, required, disabled }) => {
9
9
  const id = useId();
10
10
  const describedById = `${id}-desc`;
11
11
  const options = Array.isArray(field.options) ? field.options : [];
@@ -15,7 +15,6 @@ const selectRenderer = defineFieldRenderer(({ field, name, value, onChange, onBl
15
15
  description: typeof field.description === "string" ? field.description : void 0,
16
16
  required,
17
17
  errors,
18
- warnings,
19
18
  describedById,
20
19
  children: /* @__PURE__ */ jsx(Select, {
21
20
  id,
@@ -1 +1 @@
1
- {"version":3,"file":"select.js","names":[],"sources":["../../../src/react/renderers/select.tsx"],"sourcesContent":["'use client'\n\nimport { useId } from 'react'\nimport { defineFieldRenderer } from '../contract'\nimport { FieldShell } from '../primitives/FieldShell'\nimport { Select } from '../primitives/Select'\n\nexport const selectRenderer = defineFieldRenderer<string>(\n\t({ field, name, value, onChange, onBlur, errors, warnings, required, disabled }) => {\n\t\tconst id = useId()\n\t\tconst describedById = `${id}-desc`\n\t\tconst options = Array.isArray(field.options)\n\t\t\t? (field.options as { label: string; value: string }[])\n\t\t\t: []\n\t\treturn (\n\t\t\t<FieldShell\n\t\t\t\tid={id}\n\t\t\t\tlabel={field.label}\n\t\t\t\tdescription={typeof field.description === 'string' ? field.description : undefined}\n\t\t\t\trequired={required}\n\t\t\t\terrors={errors}\n\t\t\t\twarnings={warnings}\n\t\t\t\tdescribedById={describedById}\n\t\t\t>\n\t\t\t\t<Select\n\t\t\t\t\tid={id}\n\t\t\t\t\tname={name}\n\t\t\t\t\tvalue={value ?? ''}\n\t\t\t\t\toptions={options}\n\t\t\t\t\tonChange={onChange}\n\t\t\t\t\tonBlur={onBlur}\n\t\t\t\t\tplaceholder={typeof field.placeholder === 'string' ? field.placeholder : undefined}\n\t\t\t\t\trequired={required}\n\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\tinvalid={errors.length > 0}\n\t\t\t\t\tdescribedById={describedById}\n\t\t\t\t/>\n\t\t\t</FieldShell>\n\t\t)\n\t}\n)\n"],"mappings":";;;;;;;AAOA,MAAa,iBAAiB,qBAC5B,EAAE,OAAO,MAAM,OAAO,UAAU,QAAQ,QAAQ,UAAU,UAAU,eAAe;CACnF,MAAM,KAAK,MAAM;CACjB,MAAM,gBAAgB,GAAG,GAAG;CAC5B,MAAM,UAAU,MAAM,QAAQ,MAAM,OAAO,IACvC,MAAM,UACP,CAAC;CACJ,OACC,oBAAC,YAAD;EACK;EACJ,OAAO,MAAM;EACb,aAAa,OAAO,MAAM,gBAAgB,WAAW,MAAM,cAAc,KAAA;EAC/D;EACF;EACE;EACK;YAEf,oBAAC,QAAD;GACK;GACE;GACN,OAAO,SAAS;GACP;GACC;GACF;GACR,aAAa,OAAO,MAAM,gBAAgB,WAAW,MAAM,cAAc,KAAA;GAC/D;GACA;GACV,SAAS,OAAO,SAAS;GACV;EACf,CAAA;CACU,CAAA;AAEd,CACD"}
1
+ {"version":3,"file":"select.js","names":[],"sources":["../../../src/react/renderers/select.tsx"],"sourcesContent":["'use client'\n\nimport { useId } from 'react'\nimport { defineFieldRenderer } from '../contract'\nimport { FieldShell } from '../primitives/FieldShell'\nimport { Select } from '../primitives/Select'\n\nexport const selectRenderer = defineFieldRenderer<string>(\n\t({ field, name, value, onChange, onBlur, errors, required, disabled }) => {\n\t\tconst id = useId()\n\t\tconst describedById = `${id}-desc`\n\t\tconst options = Array.isArray(field.options)\n\t\t\t? (field.options as { label: string; value: string }[])\n\t\t\t: []\n\t\treturn (\n\t\t\t<FieldShell\n\t\t\t\tid={id}\n\t\t\t\tlabel={field.label}\n\t\t\t\tdescription={typeof field.description === 'string' ? field.description : undefined}\n\t\t\t\trequired={required}\n\t\t\t\terrors={errors}\n\t\t\t\tdescribedById={describedById}\n\t\t\t>\n\t\t\t\t<Select\n\t\t\t\t\tid={id}\n\t\t\t\t\tname={name}\n\t\t\t\t\tvalue={value ?? ''}\n\t\t\t\t\toptions={options}\n\t\t\t\t\tonChange={onChange}\n\t\t\t\t\tonBlur={onBlur}\n\t\t\t\t\tplaceholder={typeof field.placeholder === 'string' ? field.placeholder : undefined}\n\t\t\t\t\trequired={required}\n\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\tinvalid={errors.length > 0}\n\t\t\t\t\tdescribedById={describedById}\n\t\t\t\t/>\n\t\t\t</FieldShell>\n\t\t)\n\t}\n)\n"],"mappings":";;;;;;;AAOA,MAAa,iBAAiB,qBAC5B,EAAE,OAAO,MAAM,OAAO,UAAU,QAAQ,QAAQ,UAAU,eAAe;CACzE,MAAM,KAAK,MAAM;CACjB,MAAM,gBAAgB,GAAG,GAAG;CAC5B,MAAM,UAAU,MAAM,QAAQ,MAAM,OAAO,IACvC,MAAM,UACP,CAAC;CACJ,OACC,oBAAC,YAAD;EACK;EACJ,OAAO,MAAM;EACb,aAAa,OAAO,MAAM,gBAAgB,WAAW,MAAM,cAAc,KAAA;EAC/D;EACF;EACO;YAEf,oBAAC,QAAD;GACK;GACE;GACN,OAAO,SAAS;GACP;GACC;GACF;GACR,aAAa,OAAO,MAAM,gBAAgB,WAAW,MAAM,cAAc,KAAA;GAC/D;GACA;GACV,SAAS,OAAO,SAAS;GACV;EACf,CAAA;CACU,CAAA;AAEd,CACD"}
@@ -5,7 +5,7 @@ import { Input } from "../primitives/Input.js";
5
5
  import { jsx } from "react/jsx-runtime";
6
6
  import { useId } from "react";
7
7
  //#region src/react/renderers/text.tsx
8
- const textRenderer = defineFieldRenderer(({ field, name, value, onChange, onBlur, errors, warnings, required, disabled }) => {
8
+ const textRenderer = defineFieldRenderer(({ field, name, value, onChange, onBlur, errors, required, disabled }) => {
9
9
  const id = useId();
10
10
  const describedById = `${id}-desc`;
11
11
  return /* @__PURE__ */ jsx(FieldShell, {
@@ -14,7 +14,6 @@ const textRenderer = defineFieldRenderer(({ field, name, value, onChange, onBlur
14
14
  description: typeof field.description === "string" ? field.description : void 0,
15
15
  required,
16
16
  errors,
17
- warnings,
18
17
  describedById,
19
18
  children: /* @__PURE__ */ jsx(Input, {
20
19
  id,
@@ -1 +1 @@
1
- {"version":3,"file":"text.js","names":[],"sources":["../../../src/react/renderers/text.tsx"],"sourcesContent":["'use client'\n\nimport { useId } from 'react'\nimport { defineFieldRenderer } from '../contract'\nimport { FieldShell } from '../primitives/FieldShell'\nimport { Input } from '../primitives/Input'\n\nexport const textRenderer = defineFieldRenderer<string>(\n\t({ field, name, value, onChange, onBlur, errors, warnings, required, disabled }) => {\n\t\tconst id = useId()\n\t\tconst describedById = `${id}-desc`\n\t\treturn (\n\t\t\t<FieldShell\n\t\t\t\tid={id}\n\t\t\t\tlabel={field.label}\n\t\t\t\tdescription={typeof field.description === 'string' ? field.description : undefined}\n\t\t\t\trequired={required}\n\t\t\t\terrors={errors}\n\t\t\t\twarnings={warnings}\n\t\t\t\tdescribedById={describedById}\n\t\t\t>\n\t\t\t\t<Input\n\t\t\t\t\tid={id}\n\t\t\t\t\tname={name}\n\t\t\t\t\ttype=\"text\"\n\t\t\t\t\tvalue={value ?? ''}\n\t\t\t\t\tonChange={onChange}\n\t\t\t\t\tonBlur={onBlur}\n\t\t\t\t\tplaceholder={typeof field.placeholder === 'string' ? field.placeholder : undefined}\n\t\t\t\t\trequired={required}\n\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\tinvalid={errors.length > 0}\n\t\t\t\t\tdescribedById={describedById}\n\t\t\t\t/>\n\t\t\t</FieldShell>\n\t\t)\n\t}\n)\n"],"mappings":";;;;;;;AAOA,MAAa,eAAe,qBAC1B,EAAE,OAAO,MAAM,OAAO,UAAU,QAAQ,QAAQ,UAAU,UAAU,eAAe;CACnF,MAAM,KAAK,MAAM;CACjB,MAAM,gBAAgB,GAAG,GAAG;CAC5B,OACC,oBAAC,YAAD;EACK;EACJ,OAAO,MAAM;EACb,aAAa,OAAO,MAAM,gBAAgB,WAAW,MAAM,cAAc,KAAA;EAC/D;EACF;EACE;EACK;YAEf,oBAAC,OAAD;GACK;GACE;GACN,MAAK;GACL,OAAO,SAAS;GACN;GACF;GACR,aAAa,OAAO,MAAM,gBAAgB,WAAW,MAAM,cAAc,KAAA;GAC/D;GACA;GACV,SAAS,OAAO,SAAS;GACV;EACf,CAAA;CACU,CAAA;AAEd,CACD"}
1
+ {"version":3,"file":"text.js","names":[],"sources":["../../../src/react/renderers/text.tsx"],"sourcesContent":["'use client'\n\nimport { useId } from 'react'\nimport { defineFieldRenderer } from '../contract'\nimport { FieldShell } from '../primitives/FieldShell'\nimport { Input } from '../primitives/Input'\n\nexport const textRenderer = defineFieldRenderer<string>(\n\t({ field, name, value, onChange, onBlur, errors, required, disabled }) => {\n\t\tconst id = useId()\n\t\tconst describedById = `${id}-desc`\n\t\treturn (\n\t\t\t<FieldShell\n\t\t\t\tid={id}\n\t\t\t\tlabel={field.label}\n\t\t\t\tdescription={typeof field.description === 'string' ? field.description : undefined}\n\t\t\t\trequired={required}\n\t\t\t\terrors={errors}\n\t\t\t\tdescribedById={describedById}\n\t\t\t>\n\t\t\t\t<Input\n\t\t\t\t\tid={id}\n\t\t\t\t\tname={name}\n\t\t\t\t\ttype=\"text\"\n\t\t\t\t\tvalue={value ?? ''}\n\t\t\t\t\tonChange={onChange}\n\t\t\t\t\tonBlur={onBlur}\n\t\t\t\t\tplaceholder={typeof field.placeholder === 'string' ? field.placeholder : undefined}\n\t\t\t\t\trequired={required}\n\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\tinvalid={errors.length > 0}\n\t\t\t\t\tdescribedById={describedById}\n\t\t\t\t/>\n\t\t\t</FieldShell>\n\t\t)\n\t}\n)\n"],"mappings":";;;;;;;AAOA,MAAa,eAAe,qBAC1B,EAAE,OAAO,MAAM,OAAO,UAAU,QAAQ,QAAQ,UAAU,eAAe;CACzE,MAAM,KAAK,MAAM;CACjB,MAAM,gBAAgB,GAAG,GAAG;CAC5B,OACC,oBAAC,YAAD;EACK;EACJ,OAAO,MAAM;EACb,aAAa,OAAO,MAAM,gBAAgB,WAAW,MAAM,cAAc,KAAA;EAC/D;EACF;EACO;YAEf,oBAAC,OAAD;GACK;GACE;GACN,MAAK;GACL,OAAO,SAAS;GACN;GACF;GACR,aAAa,OAAO,MAAM,gBAAgB,WAAW,MAAM,cAAc,KAAA;GAC/D;GACA;GACV,SAAS,OAAO,SAAS;GACV;EACf,CAAA;CACU,CAAA;AAEd,CACD"}
@@ -5,7 +5,7 @@ import { Textarea } from "../primitives/Textarea.js";
5
5
  import { jsx } from "react/jsx-runtime";
6
6
  import { useId } from "react";
7
7
  //#region src/react/renderers/textarea.tsx
8
- const textareaRenderer = defineFieldRenderer(({ field, name, value, onChange, onBlur, errors, warnings, required, disabled }) => {
8
+ const textareaRenderer = defineFieldRenderer(({ field, name, value, onChange, onBlur, errors, required, disabled }) => {
9
9
  const id = useId();
10
10
  const describedById = `${id}-desc`;
11
11
  return /* @__PURE__ */ jsx(FieldShell, {
@@ -14,7 +14,6 @@ const textareaRenderer = defineFieldRenderer(({ field, name, value, onChange, on
14
14
  description: typeof field.description === "string" ? field.description : void 0,
15
15
  required,
16
16
  errors,
17
- warnings,
18
17
  describedById,
19
18
  children: /* @__PURE__ */ jsx(Textarea, {
20
19
  id,
@@ -1 +1 @@
1
- {"version":3,"file":"textarea.js","names":[],"sources":["../../../src/react/renderers/textarea.tsx"],"sourcesContent":["'use client'\n\nimport { useId } from 'react'\nimport { defineFieldRenderer } from '../contract'\nimport { FieldShell } from '../primitives/FieldShell'\nimport { Textarea } from '../primitives/Textarea'\n\nexport const textareaRenderer = defineFieldRenderer<string>(\n\t({ field, name, value, onChange, onBlur, errors, warnings, required, disabled }) => {\n\t\tconst id = useId()\n\t\tconst describedById = `${id}-desc`\n\t\treturn (\n\t\t\t<FieldShell\n\t\t\t\tid={id}\n\t\t\t\tlabel={field.label}\n\t\t\t\tdescription={typeof field.description === 'string' ? field.description : undefined}\n\t\t\t\trequired={required}\n\t\t\t\terrors={errors}\n\t\t\t\twarnings={warnings}\n\t\t\t\tdescribedById={describedById}\n\t\t\t>\n\t\t\t\t<Textarea\n\t\t\t\t\tid={id}\n\t\t\t\t\tname={name}\n\t\t\t\t\tvalue={value ?? ''}\n\t\t\t\t\tonChange={onChange}\n\t\t\t\t\tonBlur={onBlur}\n\t\t\t\t\tplaceholder={typeof field.placeholder === 'string' ? field.placeholder : undefined}\n\t\t\t\t\trequired={required}\n\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\tinvalid={errors.length > 0}\n\t\t\t\t\tdescribedById={describedById}\n\t\t\t\t/>\n\t\t\t</FieldShell>\n\t\t)\n\t}\n)\n"],"mappings":";;;;;;;AAOA,MAAa,mBAAmB,qBAC9B,EAAE,OAAO,MAAM,OAAO,UAAU,QAAQ,QAAQ,UAAU,UAAU,eAAe;CACnF,MAAM,KAAK,MAAM;CACjB,MAAM,gBAAgB,GAAG,GAAG;CAC5B,OACC,oBAAC,YAAD;EACK;EACJ,OAAO,MAAM;EACb,aAAa,OAAO,MAAM,gBAAgB,WAAW,MAAM,cAAc,KAAA;EAC/D;EACF;EACE;EACK;YAEf,oBAAC,UAAD;GACK;GACE;GACN,OAAO,SAAS;GACN;GACF;GACR,aAAa,OAAO,MAAM,gBAAgB,WAAW,MAAM,cAAc,KAAA;GAC/D;GACA;GACV,SAAS,OAAO,SAAS;GACV;EACf,CAAA;CACU,CAAA;AAEd,CACD"}
1
+ {"version":3,"file":"textarea.js","names":[],"sources":["../../../src/react/renderers/textarea.tsx"],"sourcesContent":["'use client'\n\nimport { useId } from 'react'\nimport { defineFieldRenderer } from '../contract'\nimport { FieldShell } from '../primitives/FieldShell'\nimport { Textarea } from '../primitives/Textarea'\n\nexport const textareaRenderer = defineFieldRenderer<string>(\n\t({ field, name, value, onChange, onBlur, errors, required, disabled }) => {\n\t\tconst id = useId()\n\t\tconst describedById = `${id}-desc`\n\t\treturn (\n\t\t\t<FieldShell\n\t\t\t\tid={id}\n\t\t\t\tlabel={field.label}\n\t\t\t\tdescription={typeof field.description === 'string' ? field.description : undefined}\n\t\t\t\trequired={required}\n\t\t\t\terrors={errors}\n\t\t\t\tdescribedById={describedById}\n\t\t\t>\n\t\t\t\t<Textarea\n\t\t\t\t\tid={id}\n\t\t\t\t\tname={name}\n\t\t\t\t\tvalue={value ?? ''}\n\t\t\t\t\tonChange={onChange}\n\t\t\t\t\tonBlur={onBlur}\n\t\t\t\t\tplaceholder={typeof field.placeholder === 'string' ? field.placeholder : undefined}\n\t\t\t\t\trequired={required}\n\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\tinvalid={errors.length > 0}\n\t\t\t\t\tdescribedById={describedById}\n\t\t\t\t/>\n\t\t\t</FieldShell>\n\t\t)\n\t}\n)\n"],"mappings":";;;;;;;AAOA,MAAa,mBAAmB,qBAC9B,EAAE,OAAO,MAAM,OAAO,UAAU,QAAQ,QAAQ,UAAU,eAAe;CACzE,MAAM,KAAK,MAAM;CACjB,MAAM,gBAAgB,GAAG,GAAG;CAC5B,OACC,oBAAC,YAAD;EACK;EACJ,OAAO,MAAM;EACb,aAAa,OAAO,MAAM,gBAAgB,WAAW,MAAM,cAAc,KAAA;EAC/D;EACF;EACO;YAEf,oBAAC,UAAD;GACK;GACE;GACN,OAAO,SAAS;GACN;GACF;GACR,aAAa,OAAO,MAAM,gBAAgB,WAAW,MAAM,cAAc,KAAA;GAC/D;GACA;GACV,SAAS,OAAO,SAAS;GACV;EACf,CAAA;CACU,CAAA;AAEd,CACD"}
@@ -3,13 +3,34 @@ type FieldErrors = Record<string, string[]>;
3
3
  type FormState = {
4
4
  values: Record<string, unknown>;
5
5
  errors: FieldErrors;
6
- warnings: FieldErrors;
7
6
  touched: Record<string, boolean>;
8
7
  submitting: boolean;
9
8
  submitted: boolean;
10
9
  submitAttempted: boolean;
11
10
  submitError?: string;
12
11
  };
12
+ type FormAction = {
13
+ type: 'SET_VALUE';
14
+ name: string;
15
+ value: unknown;
16
+ } | {
17
+ type: 'TOUCH';
18
+ name: string;
19
+ } | {
20
+ type: 'SET_FIELD_ISSUES';
21
+ name: string;
22
+ errors: string[];
23
+ } | {
24
+ type: 'SET_ALL_ISSUES';
25
+ errors: FieldErrors;
26
+ } | {
27
+ type: 'SUBMIT_START';
28
+ } | {
29
+ type: 'SUBMIT_SUCCESS';
30
+ } | {
31
+ type: 'SUBMIT_ERROR';
32
+ message: string;
33
+ };
13
34
  //#endregion
14
- export { FormState };
35
+ export { FieldErrors, FormAction, FormState };
15
36
  //# sourceMappingURL=state.d.ts.map
@@ -1,8 +1,22 @@
1
+ import { isNamedField } from "../fields/fieldKey.js";
1
2
  //#region src/react/state.ts
3
+ /**
4
+ * Per-field defaults for the reducer's initial state. Nameless (bare) blocks carry no value and
5
+ * are skipped. A repeater with a positive `minRows` starts pre-seeded with that many empty rows,
6
+ * matching the schema's own floor. Computed once, ahead of the reducer, so seeding is never an
7
+ * action: it can't touch a field, trigger validation, or (via `Form`'s dispatch wrapper) be
8
+ * mistaken for the user's first edit and fire `form.started`.
9
+ */
10
+ const seedFieldValues = (fields) => Object.fromEntries(fields.filter(isNamedField).map((field) => {
11
+ if (field.blockType === "repeater") {
12
+ const minRows = typeof field.minRows === "number" ? field.minRows : 0;
13
+ if (minRows > 0) return [field.name, Array.from({ length: minRows }, () => ({}))];
14
+ }
15
+ return [field.name, void 0];
16
+ }));
2
17
  const initialFormState = (values) => ({
3
18
  values,
4
19
  errors: {},
5
- warnings: {},
6
20
  touched: {},
7
21
  submitting: false,
8
22
  submitted: false,
@@ -34,16 +48,11 @@ const formReducer = (state, action) => {
34
48
  errors: {
35
49
  ...state.errors,
36
50
  [action.name]: action.errors
37
- },
38
- warnings: {
39
- ...state.warnings,
40
- [action.name]: action.warnings
41
51
  }
42
52
  };
43
53
  case "SET_ALL_ISSUES": return {
44
54
  ...state,
45
55
  errors: action.errors,
46
- warnings: action.warnings,
47
56
  submitAttempted: true
48
57
  };
49
58
  case "SUBMIT_START": return {
@@ -65,6 +74,6 @@ const formReducer = (state, action) => {
65
74
  }
66
75
  };
67
76
  //#endregion
68
- export { formReducer, initialFormState };
77
+ export { formReducer, initialFormState, seedFieldValues };
69
78
 
70
79
  //# sourceMappingURL=state.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"state.js","names":[],"sources":["../../src/react/state.ts"],"sourcesContent":["export type FieldErrors = Record<string, string[]>\n\nexport type FormState = {\n\tvalues: Record<string, unknown>\n\terrors: FieldErrors\n\twarnings: FieldErrors\n\ttouched: Record<string, boolean>\n\tsubmitting: boolean\n\tsubmitted: boolean\n\tsubmitAttempted: boolean\n\tsubmitError?: string\n}\n\nexport type FormAction =\n\t| { type: 'SET_VALUE'; name: string; value: unknown }\n\t| { type: 'TOUCH'; name: string }\n\t| { type: 'SET_FIELD_ISSUES'; name: string; errors: string[]; warnings: string[] }\n\t| { type: 'SET_ALL_ISSUES'; errors: FieldErrors; warnings: FieldErrors }\n\t| { type: 'SUBMIT_START' }\n\t| { type: 'SUBMIT_SUCCESS' }\n\t| { type: 'SUBMIT_ERROR'; message: string }\n\nexport const initialFormState = (values: Record<string, unknown>): FormState => ({\n\tvalues,\n\terrors: {},\n\twarnings: {},\n\ttouched: {},\n\tsubmitting: false,\n\tsubmitted: false,\n\tsubmitAttempted: false,\n})\n\n/** Changing a value clears that field's prior errors (re-validated by the caller). */\nexport const formReducer = (state: FormState, action: FormAction): FormState => {\n\tswitch (action.type) {\n\t\tcase 'SET_VALUE': {\n\t\t\tconst { [action.name]: _removed, ...restErrors } = state.errors\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\tvalues: { ...state.values, [action.name]: action.value },\n\t\t\t\terrors: restErrors,\n\t\t\t}\n\t\t}\n\t\tcase 'TOUCH':\n\t\t\treturn state.touched[action.name]\n\t\t\t\t? state\n\t\t\t\t: { ...state, touched: { ...state.touched, [action.name]: true } }\n\t\tcase 'SET_FIELD_ISSUES':\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\terrors: { ...state.errors, [action.name]: action.errors },\n\t\t\t\twarnings: { ...state.warnings, [action.name]: action.warnings },\n\t\t\t}\n\t\tcase 'SET_ALL_ISSUES':\n\t\t\treturn { ...state, errors: action.errors, warnings: action.warnings, submitAttempted: true }\n\t\tcase 'SUBMIT_START':\n\t\t\treturn { ...state, submitting: true, submitError: undefined }\n\t\tcase 'SUBMIT_SUCCESS':\n\t\t\treturn { ...state, submitting: false, submitted: true }\n\t\tcase 'SUBMIT_ERROR':\n\t\t\treturn { ...state, submitting: false, submitError: action.message }\n\t\tdefault:\n\t\t\treturn state\n\t}\n}\n"],"mappings":";AAsBA,MAAa,oBAAoB,YAAgD;CAChF;CACA,QAAQ,CAAC;CACT,UAAU,CAAC;CACX,SAAS,CAAC;CACV,YAAY;CACZ,WAAW;CACX,iBAAiB;AAClB;;AAGA,MAAa,eAAe,OAAkB,WAAkC;CAC/E,QAAQ,OAAO,MAAf;EACC,KAAK,aAAa;GACjB,MAAM,GAAG,OAAO,OAAO,UAAU,GAAG,eAAe,MAAM;GACzD,OAAO;IACN,GAAG;IACH,QAAQ;KAAE,GAAG,MAAM;MAAS,OAAO,OAAO,OAAO;IAAM;IACvD,QAAQ;GACT;EACD;EACA,KAAK,SACJ,OAAO,MAAM,QAAQ,OAAO,QACzB,QACA;GAAE,GAAG;GAAO,SAAS;IAAE,GAAG,MAAM;KAAU,OAAO,OAAO;GAAK;EAAE;EACnE,KAAK,oBACJ,OAAO;GACN,GAAG;GACH,QAAQ;IAAE,GAAG,MAAM;KAAS,OAAO,OAAO,OAAO;GAAO;GACxD,UAAU;IAAE,GAAG,MAAM;KAAW,OAAO,OAAO,OAAO;GAAS;EAC/D;EACD,KAAK,kBACJ,OAAO;GAAE,GAAG;GAAO,QAAQ,OAAO;GAAQ,UAAU,OAAO;GAAU,iBAAiB;EAAK;EAC5F,KAAK,gBACJ,OAAO;GAAE,GAAG;GAAO,YAAY;GAAM,aAAa,KAAA;EAAU;EAC7D,KAAK,kBACJ,OAAO;GAAE,GAAG;GAAO,YAAY;GAAO,WAAW;EAAK;EACvD,KAAK,gBACJ,OAAO;GAAE,GAAG;GAAO,YAAY;GAAO,aAAa,OAAO;EAAQ;EACnE,SACC,OAAO;CACT;AACD"}
1
+ {"version":3,"file":"state.js","names":[],"sources":["../../src/react/state.ts"],"sourcesContent":["import { isNamedField } from '../fields/fieldKey'\nimport type { FormFieldInstance } from '../submissions/types'\n\nexport type FieldErrors = Record<string, string[]>\n\nexport type FormState = {\n\tvalues: Record<string, unknown>\n\terrors: FieldErrors\n\ttouched: Record<string, boolean>\n\tsubmitting: boolean\n\tsubmitted: boolean\n\tsubmitAttempted: boolean\n\tsubmitError?: string\n}\n\nexport type FormAction =\n\t| { type: 'SET_VALUE'; name: string; value: unknown }\n\t| { type: 'TOUCH'; name: string }\n\t| { type: 'SET_FIELD_ISSUES'; name: string; errors: string[] }\n\t| { type: 'SET_ALL_ISSUES'; errors: FieldErrors }\n\t| { type: 'SUBMIT_START' }\n\t| { type: 'SUBMIT_SUCCESS' }\n\t| { type: 'SUBMIT_ERROR'; message: string }\n\n/**\n * Per-field defaults for the reducer's initial state. Nameless (bare) blocks carry no value and\n * are skipped. A repeater with a positive `minRows` starts pre-seeded with that many empty rows,\n * matching the schema's own floor. Computed once, ahead of the reducer, so seeding is never an\n * action: it can't touch a field, trigger validation, or (via `Form`'s dispatch wrapper) be\n * mistaken for the user's first edit and fire `form.started`.\n */\nexport const seedFieldValues = (fields: FormFieldInstance[]): Record<string, unknown> =>\n\tObject.fromEntries(\n\t\tfields.filter(isNamedField).map((field) => {\n\t\t\tif (field.blockType === 'repeater') {\n\t\t\t\tconst minRows = typeof field.minRows === 'number' ? field.minRows : 0\n\t\t\t\tif (minRows > 0) {\n\t\t\t\t\treturn [field.name, Array.from({ length: minRows }, () => ({}))]\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn [field.name, undefined]\n\t\t})\n\t)\n\nexport const initialFormState = (values: Record<string, unknown>): FormState => ({\n\tvalues,\n\terrors: {},\n\ttouched: {},\n\tsubmitting: false,\n\tsubmitted: false,\n\tsubmitAttempted: false,\n})\n\n/** Changing a value clears that field's prior errors (re-validated by the caller). */\nexport const formReducer = (state: FormState, action: FormAction): FormState => {\n\tswitch (action.type) {\n\t\tcase 'SET_VALUE': {\n\t\t\tconst { [action.name]: _removed, ...restErrors } = state.errors\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\tvalues: { ...state.values, [action.name]: action.value },\n\t\t\t\terrors: restErrors,\n\t\t\t}\n\t\t}\n\t\tcase 'TOUCH':\n\t\t\treturn state.touched[action.name]\n\t\t\t\t? state\n\t\t\t\t: { ...state, touched: { ...state.touched, [action.name]: true } }\n\t\tcase 'SET_FIELD_ISSUES':\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\terrors: { ...state.errors, [action.name]: action.errors },\n\t\t\t}\n\t\tcase 'SET_ALL_ISSUES':\n\t\t\treturn { ...state, errors: action.errors, submitAttempted: true }\n\t\tcase 'SUBMIT_START':\n\t\t\treturn { ...state, submitting: true, submitError: undefined }\n\t\tcase 'SUBMIT_SUCCESS':\n\t\t\treturn { ...state, submitting: false, submitted: true }\n\t\tcase 'SUBMIT_ERROR':\n\t\t\treturn { ...state, submitting: false, submitError: action.message }\n\t\tdefault:\n\t\t\treturn state\n\t}\n}\n"],"mappings":";;;;;;;;;AA+BA,MAAa,mBAAmB,WAC/B,OAAO,YACN,OAAO,OAAO,YAAY,EAAE,KAAK,UAAU;CAC1C,IAAI,MAAM,cAAc,YAAY;EACnC,MAAM,UAAU,OAAO,MAAM,YAAY,WAAW,MAAM,UAAU;EACpE,IAAI,UAAU,GACb,OAAO,CAAC,MAAM,MAAM,MAAM,KAAK,EAAE,QAAQ,QAAQ,UAAU,CAAC,EAAE,CAAC;CAEjE;CACA,OAAO,CAAC,MAAM,MAAM,KAAA,CAAS;AAC9B,CAAC,CACF;AAED,MAAa,oBAAoB,YAAgD;CAChF;CACA,QAAQ,CAAC;CACT,SAAS,CAAC;CACV,YAAY;CACZ,WAAW;CACX,iBAAiB;AAClB;;AAGA,MAAa,eAAe,OAAkB,WAAkC;CAC/E,QAAQ,OAAO,MAAf;EACC,KAAK,aAAa;GACjB,MAAM,GAAG,OAAO,OAAO,UAAU,GAAG,eAAe,MAAM;GACzD,OAAO;IACN,GAAG;IACH,QAAQ;KAAE,GAAG,MAAM;MAAS,OAAO,OAAO,OAAO;IAAM;IACvD,QAAQ;GACT;EACD;EACA,KAAK,SACJ,OAAO,MAAM,QAAQ,OAAO,QACzB,QACA;GAAE,GAAG;GAAO,SAAS;IAAE,GAAG,MAAM;KAAU,OAAO,OAAO;GAAK;EAAE;EACnE,KAAK,oBACJ,OAAO;GACN,GAAG;GACH,QAAQ;IAAE,GAAG,MAAM;KAAS,OAAO,OAAO,OAAO;GAAO;EACzD;EACD,KAAK,kBACJ,OAAO;GAAE,GAAG;GAAO,QAAQ,OAAO;GAAQ,iBAAiB;EAAK;EACjE,KAAK,gBACJ,OAAO;GAAE,GAAG;GAAO,YAAY;GAAM,aAAa,KAAA;EAAU;EAC7D,KAAK,kBACJ,OAAO;GAAE,GAAG;GAAO,YAAY;GAAO,WAAW;EAAK;EACvD,KAAK,gBACJ,OAAO;GAAE,GAAG;GAAO,YAAY;GAAO,aAAa,OAAO;EAAQ;EACnE,SACC,OAAO;CACT;AACD"}
@@ -1,7 +1,7 @@
1
1
  //#region src/react/uploadFile.d.ts
2
2
  type UploadFileInput = {
3
- file: File; /** Upload collection slug. Defaults to `form-uploads`. */
4
- collection?: string;
3
+ file: File; /** Upload collection slug. File fields carry it as the server-stamped `collection` block config. */
4
+ collection: string;
5
5
  apiRoute?: string;
6
6
  fetchImpl?: typeof fetch;
7
7
  };
@@ -5,7 +5,7 @@
5
5
  * at submit, so the client is never trusted for it. Pure: inject `fetchImpl` in tests.
6
6
  */
7
7
  const uploadFile = async (input) => {
8
- const { file, collection = "form-uploads", apiRoute = "/api", fetchImpl = fetch } = input;
8
+ const { file, collection, apiRoute = "/api", fetchImpl = fetch } = input;
9
9
  const body = new FormData();
10
10
  body.append("file", file);
11
11
  let response;
@@ -1 +1 @@
1
- {"version":3,"file":"uploadFile.js","names":[],"sources":["../../src/react/uploadFile.ts"],"sourcesContent":["export type UploadFileInput = {\n\tfile: File\n\t/** Upload collection slug. Defaults to `form-uploads`. */\n\tcollection?: string\n\tapiRoute?: string\n\tfetchImpl?: typeof fetch\n}\n\nexport type UploadFileResult = { ok: true; id: string | number } | { ok: false; message?: string }\n\n/**\n * Upload one file to a Payload upload collection (`POST {apiRoute}/{collection}`, multipart) and return its\n * id, which the file field stores as its value. The server re-derives the file metadata from the stored doc\n * at submit, so the client is never trusted for it. Pure: inject `fetchImpl` in tests.\n */\nexport const uploadFile = async (input: UploadFileInput): Promise<UploadFileResult> => {\n\tconst { file, collection = 'form-uploads', apiRoute = '/api', fetchImpl = fetch } = input\n\tconst body = new FormData()\n\tbody.append('file', file)\n\tlet response: Response\n\ttry {\n\t\tresponse = await fetchImpl(`${apiRoute}/${collection}`, { method: 'POST', body })\n\t} catch (error) {\n\t\treturn { ok: false, message: error instanceof Error ? error.message : 'Network error' }\n\t}\n\tif (!response.ok) {\n\t\treturn { ok: false, message: `Upload failed (${response.status})` }\n\t}\n\tconst data = (await response.json().catch(() => ({}))) as { doc?: { id?: string | number } }\n\tconst id = data.doc?.id\n\treturn id == null ? { ok: false, message: 'No id returned' } : { ok: true, id }\n}\n"],"mappings":";;;;;;AAeA,MAAa,aAAa,OAAO,UAAsD;CACtF,MAAM,EAAE,MAAM,aAAa,gBAAgB,WAAW,QAAQ,YAAY,UAAU;CACpF,MAAM,OAAO,IAAI,SAAS;CAC1B,KAAK,OAAO,QAAQ,IAAI;CACxB,IAAI;CACJ,IAAI;EACH,WAAW,MAAM,UAAU,GAAG,SAAS,GAAG,cAAc;GAAE,QAAQ;GAAQ;EAAK,CAAC;CACjF,SAAS,OAAO;EACf,OAAO;GAAE,IAAI;GAAO,SAAS,iBAAiB,QAAQ,MAAM,UAAU;EAAgB;CACvF;CACA,IAAI,CAAC,SAAS,IACb,OAAO;EAAE,IAAI;EAAO,SAAS,kBAAkB,SAAS,OAAO;CAAG;CAGnE,MAAM,MAAK,MADS,SAAS,KAAK,EAAE,aAAa,CAAC,EAAE,GACpC,KAAK;CACrB,OAAO,MAAM,OAAO;EAAE,IAAI;EAAO,SAAS;CAAiB,IAAI;EAAE,IAAI;EAAM;CAAG;AAC/E"}
1
+ {"version":3,"file":"uploadFile.js","names":[],"sources":["../../src/react/uploadFile.ts"],"sourcesContent":["export type UploadFileInput = {\n\tfile: File\n\t/** Upload collection slug. File fields carry it as the server-stamped `collection` block config. */\n\tcollection: string\n\tapiRoute?: string\n\tfetchImpl?: typeof fetch\n}\n\nexport type UploadFileResult = { ok: true; id: string | number } | { ok: false; message?: string }\n\n/**\n * Upload one file to a Payload upload collection (`POST {apiRoute}/{collection}`, multipart) and return its\n * id, which the file field stores as its value. The server re-derives the file metadata from the stored doc\n * at submit, so the client is never trusted for it. Pure: inject `fetchImpl` in tests.\n */\nexport const uploadFile = async (input: UploadFileInput): Promise<UploadFileResult> => {\n\tconst { file, collection, apiRoute = '/api', fetchImpl = fetch } = input\n\tconst body = new FormData()\n\tbody.append('file', file)\n\tlet response: Response\n\ttry {\n\t\tresponse = await fetchImpl(`${apiRoute}/${collection}`, { method: 'POST', body })\n\t} catch (error) {\n\t\treturn { ok: false, message: error instanceof Error ? error.message : 'Network error' }\n\t}\n\tif (!response.ok) {\n\t\treturn { ok: false, message: `Upload failed (${response.status})` }\n\t}\n\tconst data = (await response.json().catch(() => ({}))) as { doc?: { id?: string | number } }\n\tconst id = data.doc?.id\n\treturn id == null ? { ok: false, message: 'No id returned' } : { ok: true, id }\n}\n"],"mappings":";;;;;;AAeA,MAAa,aAAa,OAAO,UAAsD;CACtF,MAAM,EAAE,MAAM,YAAY,WAAW,QAAQ,YAAY,UAAU;CACnE,MAAM,OAAO,IAAI,SAAS;CAC1B,KAAK,OAAO,QAAQ,IAAI;CACxB,IAAI;CACJ,IAAI;EACH,WAAW,MAAM,UAAU,GAAG,SAAS,GAAG,cAAc;GAAE,QAAQ;GAAQ;EAAK,CAAC;CACjF,SAAS,OAAO;EACf,OAAO;GAAE,IAAI;GAAO,SAAS,iBAAiB,QAAQ,MAAM,UAAU;EAAgB;CACvF;CACA,IAAI,CAAC,SAAS,IACb,OAAO;EAAE,IAAI;EAAO,SAAS,kBAAkB,SAAS,OAAO;CAAG;CAGnE,MAAM,MAAK,MADS,SAAS,KAAK,EAAE,aAAa,CAAC,EAAE,GACpC,KAAK;CACrB,OAAO,MAAM,OAAO;EAAE,IAAI;EAAO,SAAS;CAAiB,IAAI;EAAE,IAAI;EAAM;CAAG;AAC/E"}
@@ -2,7 +2,6 @@
2
2
  type UseFieldResult<TValue = unknown> = {
3
3
  value: TValue | undefined;
4
4
  errors: string[];
5
- warnings: string[];
6
5
  touched: boolean;
7
6
  setValue: (value: TValue) => void; /** Mark touched and validate now (call on blur). */
8
7
  onBlur: () => void;
@@ -37,7 +37,6 @@ const useField = (name) => {
37
37
  return {
38
38
  value,
39
39
  errors: showIssues ? state.errors[name] ?? [] : [],
40
- warnings: showIssues ? state.warnings[name] ?? [] : [],
41
40
  touched,
42
41
  setValue,
43
42
  onBlur
@@ -1 +1 @@
1
- {"version":3,"file":"useField.js","names":[],"sources":["../../src/react/useField.ts"],"sourcesContent":["'use client'\n\nimport { useCallback } from 'react'\nimport { useFormContext } from './FormContext'\n\nexport type UseFieldResult<TValue = unknown> = {\n\tvalue: TValue | undefined\n\terrors: string[]\n\twarnings: string[]\n\ttouched: boolean\n\tsetValue: (value: TValue) => void\n\t/** Mark touched and validate now (call on blur). */\n\tonBlur: () => void\n}\n\n/** Bind one field by name to the form controller: its value, issues, and change/blur handlers. */\nexport const useField = <TValue = unknown>(name: string): UseFieldResult<TValue> => {\n\tconst { state, dispatch, validateField } = useFormContext()\n\tconst touched = state.touched[name] ?? false\n\tconst showIssues = touched || state.submitAttempted\n\tconst value = state.values[name] as TValue | undefined\n\n\tconst setValue = useCallback(\n\t\t(next: TValue) => {\n\t\t\tdispatch({ type: 'SET_VALUE', name, value: next })\n\t\t\tif (touched || state.submitAttempted) {\n\t\t\t\tvalidateField(name, next)\n\t\t\t}\n\t\t},\n\t\t[dispatch, name, touched, state.submitAttempted, validateField]\n\t)\n\n\tconst onBlur = useCallback(() => {\n\t\tdispatch({ type: 'TOUCH', name })\n\t\tvalidateField(name, value)\n\t}, [dispatch, name, validateField, value])\n\n\treturn {\n\t\tvalue,\n\t\terrors: showIssues ? (state.errors[name] ?? []) : [],\n\t\twarnings: showIssues ? (state.warnings[name] ?? []) : [],\n\t\ttouched,\n\t\tsetValue,\n\t\tonBlur,\n\t}\n}\n"],"mappings":";;;;;AAgBA,MAAa,YAA8B,SAAyC;CACnF,MAAM,EAAE,OAAO,UAAU,kBAAkB,eAAe;CAC1D,MAAM,UAAU,MAAM,QAAQ,SAAS;CACvC,MAAM,aAAa,WAAW,MAAM;CACpC,MAAM,QAAQ,MAAM,OAAO;CAE3B,MAAM,WAAW,aACf,SAAiB;EACjB,SAAS;GAAE,MAAM;GAAa;GAAM,OAAO;EAAK,CAAC;EACjD,IAAI,WAAW,MAAM,iBACpB,cAAc,MAAM,IAAI;CAE1B,GACA;EAAC;EAAU;EAAM;EAAS,MAAM;EAAiB;CAAa,CAC/D;CAEA,MAAM,SAAS,kBAAkB;EAChC,SAAS;GAAE,MAAM;GAAS;EAAK,CAAC;EAChC,cAAc,MAAM,KAAK;CAC1B,GAAG;EAAC;EAAU;EAAM;EAAe;CAAK,CAAC;CAEzC,OAAO;EACN;EACA,QAAQ,aAAc,MAAM,OAAO,SAAS,CAAC,IAAK,CAAC;EACnD,UAAU,aAAc,MAAM,SAAS,SAAS,CAAC,IAAK,CAAC;EACvD;EACA;EACA;CACD;AACD"}
1
+ {"version":3,"file":"useField.js","names":[],"sources":["../../src/react/useField.ts"],"sourcesContent":["'use client'\n\nimport { useCallback } from 'react'\nimport { useFormContext } from './FormContext'\n\nexport type UseFieldResult<TValue = unknown> = {\n\tvalue: TValue | undefined\n\terrors: string[]\n\ttouched: boolean\n\tsetValue: (value: TValue) => void\n\t/** Mark touched and validate now (call on blur). */\n\tonBlur: () => void\n}\n\n/** Bind one field by name to the form controller: its value, issues, and change/blur handlers. */\nexport const useField = <TValue = unknown>(name: string): UseFieldResult<TValue> => {\n\tconst { state, dispatch, validateField } = useFormContext()\n\tconst touched = state.touched[name] ?? false\n\tconst showIssues = touched || state.submitAttempted\n\tconst value = state.values[name] as TValue | undefined\n\n\tconst setValue = useCallback(\n\t\t(next: TValue) => {\n\t\t\tdispatch({ type: 'SET_VALUE', name, value: next })\n\t\t\tif (touched || state.submitAttempted) {\n\t\t\t\tvalidateField(name, next)\n\t\t\t}\n\t\t},\n\t\t[dispatch, name, touched, state.submitAttempted, validateField]\n\t)\n\n\tconst onBlur = useCallback(() => {\n\t\tdispatch({ type: 'TOUCH', name })\n\t\tvalidateField(name, value)\n\t}, [dispatch, name, validateField, value])\n\n\treturn {\n\t\tvalue,\n\t\terrors: showIssues ? (state.errors[name] ?? []) : [],\n\t\ttouched,\n\t\tsetValue,\n\t\tonBlur,\n\t}\n}\n"],"mappings":";;;;;AAeA,MAAa,YAA8B,SAAyC;CACnF,MAAM,EAAE,OAAO,UAAU,kBAAkB,eAAe;CAC1D,MAAM,UAAU,MAAM,QAAQ,SAAS;CACvC,MAAM,aAAa,WAAW,MAAM;CACpC,MAAM,QAAQ,MAAM,OAAO;CAE3B,MAAM,WAAW,aACf,SAAiB;EACjB,SAAS;GAAE,MAAM;GAAa;GAAM,OAAO;EAAK,CAAC;EACjD,IAAI,WAAW,MAAM,iBACpB,cAAc,MAAM,IAAI;CAE1B,GACA;EAAC;EAAU;EAAM;EAAS,MAAM;EAAiB;CAAa,CAC/D;CAEA,MAAM,SAAS,kBAAkB;EAChC,SAAS;GAAE,MAAM;GAAS;EAAK,CAAC;EAChC,cAAc,MAAM,KAAK;CAC1B,GAAG;EAAC;EAAU;EAAM;EAAe;CAAK,CAAC;CAEzC,OAAO;EACN;EACA,QAAQ,aAAc,MAAM,OAAO,SAAS,CAAC,IAAK,CAAC;EACnD;EACA;EACA;CACD;AACD"}
@@ -1,7 +1,7 @@
1
1
  import { FormState } from "./state.js";
2
2
 
3
3
  //#region src/react/useFormState.d.ts
4
- /** The whole form state (values, errors, warnings, touched, submitting, submitted, submitError). */
4
+ /** The whole form state (values, errors, touched, submitting, submitted, submitError). */
5
5
  declare const useFormState: () => FormState;
6
6
  //#endregion
7
7
  export { useFormState };
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { useFormContext } from "./FormContext.js";
3
3
  //#region src/react/useFormState.ts
4
- /** The whole form state (values, errors, warnings, touched, submitting, submitted, submitError). */
4
+ /** The whole form state (values, errors, touched, submitting, submitted, submitError). */
5
5
  const useFormState = () => useFormContext().state;
6
6
  //#endregion
7
7
  export { useFormState };
@@ -1 +1 @@
1
- {"version":3,"file":"useFormState.js","names":[],"sources":["../../src/react/useFormState.ts"],"sourcesContent":["'use client'\n\nimport { useFormContext } from './FormContext'\nimport type { FormState } from './state'\n\n/** The whole form state (values, errors, warnings, touched, submitting, submitted, submitError). */\nexport const useFormState = (): FormState => useFormContext().state\n"],"mappings":";;;;AAMA,MAAa,qBAAgC,eAAe,EAAE"}
1
+ {"version":3,"file":"useFormState.js","names":[],"sources":["../../src/react/useFormState.ts"],"sourcesContent":["'use client'\n\nimport { useFormContext } from './FormContext'\nimport type { FormState } from './state'\n\n/** The whole form state (values, errors, touched, submitting, submitted, submitError). */\nexport const useFormState = (): FormState => useFormContext().state\n"],"mappings":";;;;AAMA,MAAa,qBAAgC,eAAe,EAAE"}
@@ -2,11 +2,11 @@ import { runValidation } from "../validation/runValidation.js";
2
2
  //#region src/react/validateField.ts
3
3
  /**
4
4
  * Run client-side validation for one field, reusing the shared engine in `mode: 'client'` (server-only
5
- * rules are skipped, no `req`/`payload`). Splits issues into blocking errors and advisory warnings.
5
+ * rules are skipped, no `req`/`payload`). Every returned message is a blocking error.
6
6
  */
7
7
  const validateFieldValue = async (input) => {
8
8
  const { field, value, registry, ruleRegistry, answers, locale, t } = input;
9
- const { errors: issues } = await runValidation({
9
+ const { errors } = await runValidation({
10
10
  field,
11
11
  fieldDefinition: registry.get(field.blockType),
12
12
  value,
@@ -19,10 +19,7 @@ const validateFieldValue = async (input) => {
19
19
  event: "onChange",
20
20
  mode: "client"
21
21
  });
22
- return {
23
- errors: issues.filter((issue) => issue.severity === "error").map((issue) => issue.message),
24
- warnings: issues.filter((issue) => issue.severity === "warning").map((issue) => issue.message)
25
- };
22
+ return { errors };
26
23
  };
27
24
  //#endregion
28
25
  export { validateFieldValue };
@@ -1 +1 @@
1
- {"version":3,"file":"validateField.js","names":[],"sources":["../../src/react/validateField.ts"],"sourcesContent":["import type { FieldTypeRegistry } from '../fields/registry'\nimport type { Translate } from '../fields/types'\nimport type { FormFieldInstance } from '../submissions/types'\nimport type { ValidationRuleRegistry } from '../validation/registry'\nimport { runValidation } from '../validation/runValidation'\n\nexport type ValidateFieldInput = {\n\tfield: FormFieldInstance\n\tvalue: unknown\n\tregistry: FieldTypeRegistry\n\truleRegistry: ValidationRuleRegistry\n\tanswers: Record<string, unknown>\n\tlocale: string\n\tt: Translate\n}\n\nexport type ValidateFieldResult = { errors: string[]; warnings: string[] }\n\n/**\n * Run client-side validation for one field, reusing the shared engine in `mode: 'client'` (server-only\n * rules are skipped, no `req`/`payload`). Splits issues into blocking errors and advisory warnings.\n */\nexport const validateFieldValue = async (\n\tinput: ValidateFieldInput\n): Promise<ValidateFieldResult> => {\n\tconst { field, value, registry, ruleRegistry, answers, locale, t } = input\n\tconst { errors: issues } = await runValidation({\n\t\tfield,\n\t\tfieldDefinition: registry.get(field.blockType),\n\t\tvalue,\n\t\tfieldType: field.blockType,\n\t\truleRegistry,\n\t\tanswers,\n\t\tlocale,\n\t\tt,\n\t\toperation: 'create',\n\t\tevent: 'onChange',\n\t\tmode: 'client',\n\t})\n\treturn {\n\t\terrors: issues.filter((issue) => issue.severity === 'error').map((issue) => issue.message),\n\t\twarnings: issues.filter((issue) => issue.severity === 'warning').map((issue) => issue.message),\n\t}\n}\n"],"mappings":";;;;;;AAsBA,MAAa,qBAAqB,OACjC,UACkC;CAClC,MAAM,EAAE,OAAO,OAAO,UAAU,cAAc,SAAS,QAAQ,MAAM;CACrE,MAAM,EAAE,QAAQ,WAAW,MAAM,cAAc;EAC9C;EACA,iBAAiB,SAAS,IAAI,MAAM,SAAS;EAC7C;EACA,WAAW,MAAM;EACjB;EACA;EACA;EACA;EACA,WAAW;EACX,OAAO;EACP,MAAM;CACP,CAAC;CACD,OAAO;EACN,QAAQ,OAAO,QAAQ,UAAU,MAAM,aAAa,OAAO,EAAE,KAAK,UAAU,MAAM,OAAO;EACzF,UAAU,OAAO,QAAQ,UAAU,MAAM,aAAa,SAAS,EAAE,KAAK,UAAU,MAAM,OAAO;CAC9F;AACD"}
1
+ {"version":3,"file":"validateField.js","names":[],"sources":["../../src/react/validateField.ts"],"sourcesContent":["import type { FieldTypeRegistry } from '../fields/registry'\nimport type { Translate } from '../fields/types'\nimport type { FormFieldInstance } from '../submissions/types'\nimport type { ValidationRuleRegistry } from '../validation/registry'\nimport { runValidation } from '../validation/runValidation'\n\nexport type ValidateFieldInput = {\n\tfield: FormFieldInstance\n\tvalue: unknown\n\tregistry: FieldTypeRegistry\n\truleRegistry: ValidationRuleRegistry\n\tanswers: Record<string, unknown>\n\tlocale: string\n\tt: Translate\n}\n\nexport type ValidateFieldResult = { errors: string[] }\n\n/**\n * Run client-side validation for one field, reusing the shared engine in `mode: 'client'` (server-only\n * rules are skipped, no `req`/`payload`). Every returned message is a blocking error.\n */\nexport const validateFieldValue = async (\n\tinput: ValidateFieldInput\n): Promise<ValidateFieldResult> => {\n\tconst { field, value, registry, ruleRegistry, answers, locale, t } = input\n\tconst { errors } = await runValidation({\n\t\tfield,\n\t\tfieldDefinition: registry.get(field.blockType),\n\t\tvalue,\n\t\tfieldType: field.blockType,\n\t\truleRegistry,\n\t\tanswers,\n\t\tlocale,\n\t\tt,\n\t\toperation: 'create',\n\t\tevent: 'onChange',\n\t\tmode: 'client',\n\t})\n\treturn { errors }\n}\n"],"mappings":";;;;;;AAsBA,MAAa,qBAAqB,OACjC,UACkC;CAClC,MAAM,EAAE,OAAO,OAAO,UAAU,cAAc,SAAS,QAAQ,MAAM;CACrE,MAAM,EAAE,WAAW,MAAM,cAAc;EACtC;EACA,iBAAiB,SAAS,IAAI,MAAM,SAAS;EAC7C;EACA,WAAW,MAAM;EACjB;EACA;EACA;EACA;EACA,WAAW;EACX,OAAO;EACP,MAAM;CACP,CAAC;CACD,OAAO,EAAE,OAAO;AACjB"}
@@ -1,8 +1,9 @@
1
1
  //#region src/recall/interpolate.d.ts
2
2
  /**
3
- * Replace `{{ name }}` and `{{ name|fallback }}` tokens. `resolve` returns the recalled value (''
4
- * when absent); the fallback (or '') is substituted when `resolve` yields ''. Token-free input is
5
- * returned unchanged, so this is a no-op for ordinary text.
3
+ * Replace `{{ name }}`, `{{ name|fallback }}`, and `{{ name||fallback }}` tokens (single and
4
+ * double pipe are equivalent; the second pipe is just consumed, not part of the fallback text).
5
+ * `resolve` returns the recalled value ('' when absent); the fallback (or '') is substituted when
6
+ * `resolve` yields ''. Token-free input is returned unchanged, so this is a no-op for ordinary text.
6
7
  */
7
8
  declare const interpolate: (template: string, resolve: (name: string) => string) => string;
8
9
  //#endregion
@@ -1,9 +1,10 @@
1
1
  //#region src/recall/interpolate.ts
2
- const TOKEN = /\{\{\s*([^{}|]+?)\s*(?:\|([^{}]*?))?\}\}/g;
2
+ const TOKEN = /\{\{\s*([^{}|]+?)\s*(?:\|\|?([^{}]*?))?\}\}/g;
3
3
  /**
4
- * Replace `{{ name }}` and `{{ name|fallback }}` tokens. `resolve` returns the recalled value (''
5
- * when absent); the fallback (or '') is substituted when `resolve` yields ''. Token-free input is
6
- * returned unchanged, so this is a no-op for ordinary text.
4
+ * Replace `{{ name }}`, `{{ name|fallback }}`, and `{{ name||fallback }}` tokens (single and
5
+ * double pipe are equivalent; the second pipe is just consumed, not part of the fallback text).
6
+ * `resolve` returns the recalled value ('' when absent); the fallback (or '') is substituted when
7
+ * `resolve` yields ''. Token-free input is returned unchanged, so this is a no-op for ordinary text.
7
8
  */
8
9
  const interpolate = (template, resolve) => template.replace(TOKEN, (_match, rawName, rawFallback) => {
9
10
  const value = resolve(rawName.trim());
@@ -1 +1 @@
1
- {"version":3,"file":"interpolate.js","names":[],"sources":["../../src/recall/interpolate.ts"],"sourcesContent":["const TOKEN = /\\{\\{\\s*([^{}|]+?)\\s*(?:\\|([^{}]*?))?\\}\\}/g\n\n/**\n * Replace `{{ name }}` and `{{ name|fallback }}` tokens. `resolve` returns the recalled value (''\n * when absent); the fallback (or '') is substituted when `resolve` yields ''. Token-free input is\n * returned unchanged, so this is a no-op for ordinary text.\n */\nexport const interpolate = (template: string, resolve: (name: string) => string): string =>\n\ttemplate.replace(TOKEN, (_match, rawName: string, rawFallback?: string) => {\n\t\tconst value = resolve(rawName.trim())\n\t\tif (value !== '') {\n\t\t\treturn value\n\t\t}\n\t\treturn rawFallback === undefined ? '' : rawFallback.trim()\n\t})\n"],"mappings":";AAAA,MAAM,QAAQ;;;;;;AAOd,MAAa,eAAe,UAAkB,YAC7C,SAAS,QAAQ,QAAQ,QAAQ,SAAiB,gBAAyB;CAC1E,MAAM,QAAQ,QAAQ,QAAQ,KAAK,CAAC;CACpC,IAAI,UAAU,IACb,OAAO;CAER,OAAO,gBAAgB,KAAA,IAAY,KAAK,YAAY,KAAK;AAC1D,CAAC"}
1
+ {"version":3,"file":"interpolate.js","names":[],"sources":["../../src/recall/interpolate.ts"],"sourcesContent":["const TOKEN = /\\{\\{\\s*([^{}|]+?)\\s*(?:\\|\\|?([^{}]*?))?\\}\\}/g\n\n/**\n * Replace `{{ name }}`, `{{ name|fallback }}`, and `{{ name||fallback }}` tokens (single and\n * double pipe are equivalent; the second pipe is just consumed, not part of the fallback text).\n * `resolve` returns the recalled value ('' when absent); the fallback (or '') is substituted when\n * `resolve` yields ''. Token-free input is returned unchanged, so this is a no-op for ordinary text.\n */\nexport const interpolate = (template: string, resolve: (name: string) => string): string =>\n\ttemplate.replace(TOKEN, (_match, rawName: string, rawFallback?: string) => {\n\t\tconst value = resolve(rawName.trim())\n\t\tif (value !== '') {\n\t\t\treturn value\n\t\t}\n\t\treturn rawFallback === undefined ? '' : rawFallback.trim()\n\t})\n"],"mappings":";AAAA,MAAM,QAAQ;;;;;;;AAQd,MAAa,eAAe,UAAkB,YAC7C,SAAS,QAAQ,QAAQ,QAAQ,SAAiB,gBAAyB;CAC1E,MAAM,QAAQ,QAAQ,QAAQ,KAAK,CAAC;CACpC,IAAI,UAAU,IACb,OAAO;CAER,OAAO,gBAAgB,KAAA,IAAY,KAAK,YAAY,KAAK;AAC1D,CAAC"}
@@ -1,5 +1,5 @@
1
- import { AnyFormFieldDefinition } from "../fields/types.js";
2
1
  import { FormFieldInstance } from "../submissions/types.js";
2
+ import { AnyFormFieldDefinition } from "../fields/types.js";
3
3
 
4
4
  //#region src/recall/resolver.d.ts
5
5
  type RecallResolver = (name: string) => string;
@@ -1,3 +1,4 @@
1
+ import { isNamedField } from "../fields/fieldKey.js";
1
2
  //#region src/recall/resolver.ts
2
3
  /** Derive a value->label map from a select-like field instance's `options`. */
3
4
  const optionLabelsFor = (field) => {
@@ -13,7 +14,7 @@ const optionLabelsFor = (field) => {
13
14
  * value -> ''. Pure and isomorphic; the renderer and server templates share it.
14
15
  */
15
16
  const buildRecallResolver = (args) => {
16
- const byName = new Map(args.fields.map((field) => [field.name, field]));
17
+ const byName = new Map(args.fields.filter(isNamedField).map((field) => [field.name, field]));
17
18
  return (name) => {
18
19
  const field = byName.get(name);
19
20
  if (!field) return "";
@@ -30,7 +31,18 @@ const buildRecallResolver = (args) => {
30
31
  return Array.isArray(value) ? value.join(", ") : String(value);
31
32
  };
32
33
  };
34
+ /**
35
+ * Build a submission-shaped descriptor per named field: the client-side counterpart to the
36
+ * per-field descriptors `runSubmission` snapshots server-side. Lets client-rendered templates
37
+ * (the response message) label rows the same way server-rendered ones (email-team) do. `optionLabels`
38
+ * is omitted: pair with values already formatted via `buildRecallResolver`, not raw stored values.
39
+ */
40
+ const descriptorsFor = (fields) => fields.filter(isNamedField).map((field) => ({
41
+ field: field.name,
42
+ label: field.label ?? field.name,
43
+ fieldType: field.blockType
44
+ }));
33
45
  //#endregion
34
- export { buildRecallResolver, optionLabelsFor };
46
+ export { buildRecallResolver, descriptorsFor, optionLabelsFor };
35
47
 
36
48
  //# sourceMappingURL=resolver.js.map