@10x-media/form-builder 0.1.0-beta.4 → 0.1.0-beta.6

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 (372) hide show
  1. package/CHANGELOG.md +112 -0
  2. package/README.md +3 -3
  3. package/dist/actions/body/serializeBody.d.ts +8 -5
  4. package/dist/actions/body/serializeBody.js.map +1 -1
  5. package/dist/actions/body/textOfBody.d.ts +13 -0
  6. package/dist/actions/body/textOfBody.js +35 -0
  7. package/dist/actions/body/textOfBody.js.map +1 -0
  8. package/dist/actions/builtin/confirmation.js +81 -48
  9. package/dist/actions/builtin/confirmation.js.map +1 -1
  10. package/dist/actions/builtin/emailTeam.js +67 -38
  11. package/dist/actions/builtin/emailTeam.js.map +1 -1
  12. package/dist/actions/builtin/index.d.ts +9 -3
  13. package/dist/actions/builtin/index.js +8 -5
  14. package/dist/actions/builtin/index.js.map +1 -1
  15. package/dist/actions/defineAction.d.ts +1 -1
  16. package/dist/actions/emailRecipients.d.ts +12 -0
  17. package/dist/actions/emailRecipients.js +72 -0
  18. package/dist/actions/emailRecipients.js.map +1 -0
  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/task.js +9 -8
  23. package/dist/actions/task.js.map +1 -1
  24. package/dist/aggregation/aggregateResponses.d.ts +9 -0
  25. package/dist/aggregation/aggregateResponses.js +8 -14
  26. package/dist/aggregation/aggregateResponses.js.map +1 -1
  27. package/dist/aggregation/resolveResultsRequest.d.ts +19 -6
  28. package/dist/aggregation/resolveResultsRequest.js +58 -12
  29. package/dist/aggregation/resolveResultsRequest.js.map +1 -1
  30. package/dist/calc/computeCalcFields.js +2 -1
  31. package/dist/calc/computeCalcFields.js.map +1 -1
  32. package/dist/client/ByteSizeField.d.ts +8 -0
  33. package/dist/client/ByteSizeField.js +3 -1
  34. package/dist/client/ByteSizeField.js.map +1 -1
  35. package/dist/client/ClosePollButton.d.ts +15 -0
  36. package/dist/client/ClosePollButton.js +80 -0
  37. package/dist/client/ClosePollButton.js.map +1 -0
  38. package/dist/client/CondensedArray.d.ts +15 -0
  39. package/dist/client/CondensedArray.js +97 -0
  40. package/dist/client/CondensedArray.js.map +1 -0
  41. package/dist/client/ConsentBlockLabel.d.ts +15 -0
  42. package/dist/client/ConsentBlockLabel.js +71 -0
  43. package/dist/client/ConsentBlockLabel.js.map +1 -0
  44. package/dist/client/ConsentSourceRowLabel.d.ts +9 -0
  45. package/dist/client/ConsentSourceRowLabel.js +21 -0
  46. package/dist/client/ConsentSourceRowLabel.js.map +1 -0
  47. package/dist/client/EndpointOptionsSelect.d.ts +46 -0
  48. package/dist/client/EndpointOptionsSelect.js +106 -0
  49. package/dist/client/EndpointOptionsSelect.js.map +1 -0
  50. package/dist/client/FieldBlockLabel.d.ts +18 -0
  51. package/dist/client/FieldBlockLabel.js +34 -0
  52. package/dist/client/FieldBlockLabel.js.map +1 -0
  53. package/dist/client/FieldNameSelect.d.ts +21 -4
  54. package/dist/client/FieldNameSelect.js +29 -15
  55. package/dist/client/FieldNameSelect.js.map +1 -1
  56. package/dist/client/FlowBuilder.d.ts +2 -1
  57. package/dist/client/FlowBuilder.js +63 -57
  58. package/dist/client/FlowBuilder.js.map +1 -1
  59. package/dist/client/RecipientsSelect.d.ts +31 -0
  60. package/dist/client/RecipientsSelect.js +174 -0
  61. package/dist/client/RecipientsSelect.js.map +1 -0
  62. package/dist/client/RuleDescription.d.ts +21 -0
  63. package/dist/client/RuleDescription.js +19 -0
  64. package/dist/client/RuleDescription.js.map +1 -0
  65. package/dist/client/admin.css +41 -0
  66. package/dist/client/endpointOptions.js +29 -0
  67. package/dist/client/endpointOptions.js.map +1 -0
  68. package/dist/client/flowAuthoring.js +114 -7
  69. package/dist/client/flowAuthoring.js.map +1 -1
  70. package/dist/client/synthesizeClientField.js +15 -8
  71. package/dist/client/synthesizeClientField.js.map +1 -1
  72. package/dist/collections/buttonFields.d.ts +34 -0
  73. package/dist/collections/buttonFields.js +35 -0
  74. package/dist/collections/buttonFields.js.map +1 -0
  75. package/dist/collections/cells/FieldCountCell.d.ts +15 -0
  76. package/dist/collections/cells/FieldCountCell.js +18 -0
  77. package/dist/collections/cells/FieldCountCell.js.map +1 -0
  78. package/dist/collections/cells/FlowStepsCell.d.ts +14 -0
  79. package/dist/collections/cells/FlowStepsCell.js +17 -0
  80. package/dist/collections/cells/FlowStepsCell.js.map +1 -0
  81. package/dist/collections/formSubmissions.js +23 -17
  82. package/dist/collections/formSubmissions.js.map +1 -1
  83. package/dist/collections/forms.js +323 -134
  84. package/dist/collections/forms.js.map +1 -1
  85. package/dist/collections/redirectFields.d.ts +29 -0
  86. package/dist/consent/applyConsentStatements.d.ts +14 -0
  87. package/dist/consent/applyConsentStatements.js +17 -0
  88. package/dist/consent/applyConsentStatements.js.map +1 -0
  89. package/dist/consent/captureConsent.d.ts +31 -11
  90. package/dist/consent/captureConsent.js +53 -13
  91. package/dist/consent/captureConsent.js.map +1 -1
  92. package/dist/consent/consentSourcesField.d.ts +62 -0
  93. package/dist/consent/consentSourcesField.js +86 -0
  94. package/dist/consent/consentSourcesField.js.map +1 -0
  95. package/dist/consent/resolveConsentEntries.d.ts +24 -0
  96. package/dist/consent/resolveConsentEntries.js +43 -0
  97. package/dist/consent/resolveConsentEntries.js.map +1 -0
  98. package/dist/consent/resolveConsentSourcesRequest.d.ts +37 -0
  99. package/dist/consent/resolveConsentSourcesRequest.js +55 -0
  100. package/dist/consent/resolveConsentSourcesRequest.js.map +1 -0
  101. package/dist/consent/resolveConsentStatements.d.ts +45 -0
  102. package/dist/consent/resolveConsentStatements.js +44 -0
  103. package/dist/consent/resolveConsentStatements.js.map +1 -0
  104. package/dist/consent/resolvePublishedVersionRef.d.ts +17 -11
  105. package/dist/consent/resolvePublishedVersionRef.js +13 -10
  106. package/dist/consent/resolvePublishedVersionRef.js.map +1 -1
  107. package/dist/consent/types.d.ts +53 -0
  108. package/dist/email/departments.d.ts +59 -0
  109. package/dist/email/departments.js +87 -0
  110. package/dist/email/departments.js.map +1 -0
  111. package/dist/email/departmentsField.d.ts +53 -0
  112. package/dist/email/departmentsField.js +73 -0
  113. package/dist/email/departmentsField.js.map +1 -0
  114. package/dist/exports/client.d.ts +11 -1
  115. package/dist/exports/client.js +11 -1
  116. package/dist/exports/react.d.ts +8 -3
  117. package/dist/exports/react.js +6 -2
  118. package/dist/exports/rsc.d.ts +3 -1
  119. package/dist/exports/rsc.js +4 -2
  120. package/dist/exports/types.d.ts +16 -8
  121. package/dist/fields/buildFieldBlocks.js +28 -13
  122. package/dist/fields/buildFieldBlocks.js.map +1 -1
  123. package/dist/fields/builtin/calculation.js +7 -0
  124. package/dist/fields/builtin/calculation.js.map +1 -1
  125. package/dist/fields/builtin/checkbox.js +8 -0
  126. package/dist/fields/builtin/checkbox.js.map +1 -1
  127. package/dist/fields/builtin/consent.js +32 -21
  128. package/dist/fields/builtin/consent.js.map +1 -1
  129. package/dist/fields/builtin/country.d.ts +13 -0
  130. package/dist/fields/builtin/country.js +30 -0
  131. package/dist/fields/builtin/country.js.map +1 -0
  132. package/dist/fields/builtin/date.js +2 -0
  133. package/dist/fields/builtin/date.js.map +1 -1
  134. package/dist/fields/builtin/file.js +14 -7
  135. package/dist/fields/builtin/file.js.map +1 -1
  136. package/dist/fields/builtin/index.d.ts +8 -6
  137. package/dist/fields/builtin/index.js +12 -11
  138. package/dist/fields/builtin/index.js.map +1 -1
  139. package/dist/fields/builtin/message.js +8 -4
  140. package/dist/fields/builtin/message.js.map +1 -1
  141. package/dist/fields/builtin/repeater.js +1 -0
  142. package/dist/fields/builtin/repeater.js.map +1 -1
  143. package/dist/fields/builtin/select.js +1 -0
  144. package/dist/fields/builtin/select.js.map +1 -1
  145. package/dist/fields/builtin/state.d.ts +13 -0
  146. package/dist/fields/builtin/state.js +30 -0
  147. package/dist/fields/builtin/state.js.map +1 -0
  148. package/dist/fields/data/regions.d.ts +21 -0
  149. package/dist/fields/data/regions.js +1238 -0
  150. package/dist/fields/data/regions.js.map +1 -0
  151. package/dist/fields/fieldKey.d.ts +15 -0
  152. package/dist/fields/fieldKey.js +16 -0
  153. package/dist/fields/fieldKey.js.map +1 -0
  154. package/dist/fields/fieldNamesOfType.js +13 -8
  155. package/dist/fields/fieldNamesOfType.js.map +1 -1
  156. package/dist/fields/instanceOptions.js +20 -0
  157. package/dist/fields/instanceOptions.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 +46 -9
  162. package/dist/fields/sharedConfig.js.map +1 -1
  163. package/dist/fields/types.d.ts +63 -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 +16 -7
  168. package/dist/flow/normalizeFlow.js.map +1 -1
  169. package/dist/flow/types.d.ts +12 -3
  170. package/dist/flow/types.js +11 -0
  171. package/dist/flow/types.js.map +1 -0
  172. package/dist/form/pollState.d.ts +4 -4
  173. package/dist/form/pollState.js.map +1 -1
  174. package/dist/form/toFormDocument.d.ts +54 -12
  175. package/dist/form/toFormDocument.js +56 -8
  176. package/dist/form/toFormDocument.js.map +1 -1
  177. package/dist/form/types.d.ts +31 -14
  178. package/dist/index.d.ts +153 -29
  179. package/dist/index.js +47 -15
  180. package/dist/index.js.map +1 -1
  181. package/dist/plugin/customState.js +26 -0
  182. package/dist/plugin/customState.js.map +1 -0
  183. package/dist/plugin/registerCollections.js +24 -13
  184. package/dist/plugin/registerCollections.js.map +1 -1
  185. package/dist/plugin/uploadsCollection.d.ts +5 -0
  186. package/dist/plugin/uploadsCollection.js +10 -1
  187. package/dist/plugin/uploadsCollection.js.map +1 -1
  188. package/dist/poll/applyPollOptions.js +3 -2
  189. package/dist/poll/applyPollOptions.js.map +1 -1
  190. package/dist/poll/buildPollOptionSourceFields.js +2 -5
  191. package/dist/poll/buildPollOptionSourceFields.js.map +1 -1
  192. package/dist/poll/closeJob.d.ts +52 -0
  193. package/dist/poll/closeJob.js +119 -0
  194. package/dist/poll/closeJob.js.map +1 -0
  195. package/dist/poll/definePollOptionSource.d.ts +10 -1
  196. package/dist/poll/definePollOptionSource.js.map +1 -1
  197. package/dist/poll/definePollType.d.ts +34 -0
  198. package/dist/poll/definePollType.js +6 -0
  199. package/dist/poll/definePollType.js.map +1 -0
  200. package/dist/poll/effectivePollOptions.d.ts +38 -0
  201. package/dist/poll/effectivePollOptions.js +64 -0
  202. package/dist/poll/effectivePollOptions.js.map +1 -0
  203. package/dist/poll/mostVoted.d.ts +21 -0
  204. package/dist/poll/mostVoted.js +32 -0
  205. package/dist/poll/mostVoted.js.map +1 -0
  206. package/dist/poll/outcomeBeforeChange.js +91 -0
  207. package/dist/poll/outcomeBeforeChange.js.map +1 -0
  208. package/dist/poll/outcomeFields.d.ts +38 -0
  209. package/dist/poll/outcomeFields.js +52 -0
  210. package/dist/poll/outcomeFields.js.map +1 -0
  211. package/dist/poll/pollTypeRegistry.d.ts +34 -0
  212. package/dist/poll/pollTypeRegistry.js +71 -0
  213. package/dist/poll/pollTypeRegistry.js.map +1 -0
  214. package/dist/poll/resolvePollCloseRequest.js +105 -0
  215. package/dist/poll/resolvePollCloseRequest.js.map +1 -0
  216. package/dist/poll/resolvePollOptions.d.ts +2 -1
  217. package/dist/poll/resolvePollOptions.js +5 -17
  218. package/dist/poll/resolvePollOptions.js.map +1 -1
  219. package/dist/poll/resolvePollOptionsRequest.js +51 -0
  220. package/dist/poll/resolvePollOptionsRequest.js.map +1 -0
  221. package/dist/poll/resolvePollOutcome.d.ts +22 -9
  222. package/dist/poll/resolvePollOutcome.js +54 -14
  223. package/dist/poll/resolvePollOutcome.js.map +1 -1
  224. package/dist/poll/resultsField.js +21 -0
  225. package/dist/poll/resultsField.js.map +1 -0
  226. package/dist/prefill/valuesFromSearchParams.js +2 -1
  227. package/dist/prefill/valuesFromSearchParams.js.map +1 -1
  228. package/dist/react/Form.d.ts +8 -8
  229. package/dist/react/Form.js +74 -62
  230. package/dist/react/Form.js.map +1 -1
  231. package/dist/react/FormContext.d.ts +6 -4
  232. package/dist/react/FormContext.js.map +1 -1
  233. package/dist/react/FormControls.d.ts +3 -3
  234. package/dist/react/FormControls.js +3 -3
  235. package/dist/react/FormControls.js.map +1 -1
  236. package/dist/react/FormResults.d.ts +5 -5
  237. package/dist/react/FormResults.js +6 -6
  238. package/dist/react/FormResults.js.map +1 -1
  239. package/dist/react/Poll.d.ts +2 -2
  240. package/dist/react/Poll.js +5 -5
  241. package/dist/react/Poll.js.map +1 -1
  242. package/dist/react/contract.d.ts +2 -3
  243. package/dist/react/contract.js.map +1 -1
  244. package/dist/react/primitives/Checkbox.d.ts +4 -2
  245. package/dist/react/primitives/Checkbox.js +2 -1
  246. package/dist/react/primitives/Checkbox.js.map +1 -1
  247. package/dist/react/primitives/FieldShell.d.ts +2 -4
  248. package/dist/react/primitives/FieldShell.js +12 -19
  249. package/dist/react/primitives/FieldShell.js.map +1 -1
  250. package/dist/react/renderers/calculation.js +1 -2
  251. package/dist/react/renderers/calculation.js.map +1 -1
  252. package/dist/react/renderers/checkbox.js +1 -2
  253. package/dist/react/renderers/checkbox.js.map +1 -1
  254. package/dist/react/renderers/consent.js +78 -34
  255. package/dist/react/renderers/consent.js.map +1 -1
  256. package/dist/react/renderers/date.js +1 -3
  257. package/dist/react/renderers/date.js.map +1 -1
  258. package/dist/react/renderers/email.js +1 -2
  259. package/dist/react/renderers/email.js.map +1 -1
  260. package/dist/react/renderers/file.js +1 -2
  261. package/dist/react/renderers/file.js.map +1 -1
  262. package/dist/react/renderers/index.js +3 -0
  263. package/dist/react/renderers/index.js.map +1 -1
  264. package/dist/react/renderers/number.js +1 -2
  265. package/dist/react/renderers/number.js.map +1 -1
  266. package/dist/react/renderers/region.js +45 -0
  267. package/dist/react/renderers/region.js.map +1 -0
  268. package/dist/react/renderers/repeater.js +7 -10
  269. package/dist/react/renderers/repeater.js.map +1 -1
  270. package/dist/react/renderers/select.js +1 -2
  271. package/dist/react/renderers/select.js.map +1 -1
  272. package/dist/react/renderers/text.js +1 -2
  273. package/dist/react/renderers/text.js.map +1 -1
  274. package/dist/react/renderers/textarea.js +1 -2
  275. package/dist/react/renderers/textarea.js.map +1 -1
  276. package/dist/react/state.d.ts +0 -3
  277. package/dist/react/state.js +7 -11
  278. package/dist/react/state.js.map +1 -1
  279. package/dist/react/useField.d.ts +0 -1
  280. package/dist/react/useField.js +0 -1
  281. package/dist/react/useField.js.map +1 -1
  282. package/dist/react/useFormState.d.ts +1 -1
  283. package/dist/react/useFormState.js +1 -1
  284. package/dist/react/useFormState.js.map +1 -1
  285. package/dist/react/validateField.js +3 -6
  286. package/dist/react/validateField.js.map +1 -1
  287. package/dist/recall/interpolate.d.ts +4 -3
  288. package/dist/recall/interpolate.js +5 -4
  289. package/dist/recall/interpolate.js.map +1 -1
  290. package/dist/recall/resolver.d.ts +1 -1
  291. package/dist/recall/resolver.js +14 -2
  292. package/dist/recall/resolver.js.map +1 -1
  293. package/dist/spam/captcha.d.ts +1 -1
  294. package/dist/spam/captcha.js +1 -1
  295. package/dist/spam/captcha.js.map +1 -1
  296. package/dist/submissions/SubmissionAnswers.js +6 -2
  297. package/dist/submissions/SubmissionAnswers.js.map +1 -1
  298. package/dist/submissions/SubmissionAnswersClient.js +100 -64
  299. package/dist/submissions/SubmissionAnswersClient.js.map +1 -1
  300. package/dist/submissions/createSubmission.d.ts +36 -0
  301. package/dist/submissions/createSubmission.js +26 -0
  302. package/dist/submissions/createSubmission.js.map +1 -0
  303. package/dist/submissions/runSubmission.d.ts +10 -0
  304. package/dist/submissions/runSubmission.js +31 -19
  305. package/dist/submissions/runSubmission.js.map +1 -1
  306. package/dist/submissions/types.d.ts +11 -4
  307. package/dist/submissions/validateSubmission.js +39 -23
  308. package/dist/submissions/validateSubmission.js.map +1 -1
  309. package/dist/submissions/votedCookie.js +3 -3
  310. package/dist/submissions/votedCookie.js.map +1 -1
  311. package/dist/translations/de.js +104 -26
  312. package/dist/translations/de.js.map +1 -1
  313. package/dist/translations/en.js +105 -27
  314. package/dist/translations/en.js.map +1 -1
  315. package/dist/translations/keys.d.ts +99 -21
  316. package/dist/translations/keys.js +100 -22
  317. package/dist/translations/keys.js.map +1 -1
  318. package/dist/uploads/resolveFileRef.js +2 -1
  319. package/dist/uploads/resolveFileRef.js.map +1 -1
  320. package/dist/validation/buildRuleBlocks.js +18 -17
  321. package/dist/validation/buildRuleBlocks.js.map +1 -1
  322. package/dist/validation/builtin/email.js +1 -0
  323. package/dist/validation/builtin/email.js.map +1 -1
  324. package/dist/validation/builtin/matchesField.js +3 -7
  325. package/dist/validation/builtin/matchesField.js.map +1 -1
  326. package/dist/validation/builtin/max.js +1 -0
  327. package/dist/validation/builtin/max.js.map +1 -1
  328. package/dist/validation/builtin/maxDate.js +1 -0
  329. package/dist/validation/builtin/maxDate.js.map +1 -1
  330. package/dist/validation/builtin/maxLength.js +1 -0
  331. package/dist/validation/builtin/maxLength.js.map +1 -1
  332. package/dist/validation/builtin/min.js +1 -0
  333. package/dist/validation/builtin/min.js.map +1 -1
  334. package/dist/validation/builtin/minDate.js +1 -0
  335. package/dist/validation/builtin/minDate.js.map +1 -1
  336. package/dist/validation/builtin/minLength.js +1 -0
  337. package/dist/validation/builtin/minLength.js.map +1 -1
  338. package/dist/validation/builtin/notAlreadySubmitted.js +1 -0
  339. package/dist/validation/builtin/notAlreadySubmitted.js.map +1 -1
  340. package/dist/validation/builtin/oneOf.js +1 -0
  341. package/dist/validation/builtin/oneOf.js.map +1 -1
  342. package/dist/validation/builtin/pattern.js +11 -2
  343. package/dist/validation/builtin/pattern.js.map +1 -1
  344. package/dist/validation/builtin/url.js +1 -0
  345. package/dist/validation/builtin/url.js.map +1 -1
  346. package/dist/validation/builtin/validateRegexParams.js +44 -0
  347. package/dist/validation/builtin/validateRegexParams.js.map +1 -0
  348. package/dist/validation/fieldTargetParam.d.ts +22 -0
  349. package/dist/validation/fieldTargetParam.js +38 -0
  350. package/dist/validation/fieldTargetParam.js.map +1 -0
  351. package/dist/validation/runValidation.js +8 -29
  352. package/dist/validation/runValidation.js.map +1 -1
  353. package/dist/validation/types.d.ts +5 -11
  354. package/package.json +6 -6
  355. package/dist/consent/buildConsentSourceConfig.js +0 -49
  356. package/dist/consent/buildConsentSourceConfig.js.map +0 -1
  357. package/dist/consent/builtin/index.d.ts +0 -17
  358. package/dist/consent/builtin/index.js +0 -21
  359. package/dist/consent/builtin/index.js.map +0 -1
  360. package/dist/consent/builtin/pageReference.js +0 -75
  361. package/dist/consent/builtin/pageReference.js.map +0 -1
  362. package/dist/consent/builtin/static.js +0 -48
  363. package/dist/consent/builtin/static.js.map +0 -1
  364. package/dist/consent/defineConsentSource.d.ts +0 -35
  365. package/dist/consent/defineConsentSource.js +0 -6
  366. package/dist/consent/defineConsentSource.js.map +0 -1
  367. package/dist/consent/registry.d.ts +0 -16
  368. package/dist/consent/registry.js +0 -16
  369. package/dist/consent/registry.js.map +0 -1
  370. package/dist/consent/resolveConsentLinks.d.ts +0 -19
  371. package/dist/consent/resolveConsentLinks.js +0 -26
  372. package/dist/consent/resolveConsentLinks.js.map +0 -1
@@ -1,23 +1,46 @@
1
1
  "use client";
2
- import { FieldLabel, TextInput } from "@payloadcms/ui";
2
+ import { FieldLabel, Pill, TextInput } from "@payloadcms/ui";
3
3
  import { jsx, jsxs } from "react/jsx-runtime";
4
4
  //#region src/submissions/SubmissionAnswersClient.tsx
5
5
  const noop = (_e) => {};
6
- const pillStyle = (agreed) => ({
7
- display: "inline-block",
8
- padding: "2px 8px",
9
- borderRadius: "9999px",
10
- fontSize: "0.75rem",
11
- fontWeight: 600,
12
- background: agreed ? "var(--theme-success-500)" : "var(--theme-error-500)",
13
- color: "#fff"
14
- });
6
+ /** Horizontal gutter between fields sharing a row; also trimmed from each fractional basis so widths wrap cleanly rather than overflow. */
7
+ const FIELD_GAP = "calc(var(--base, 20px) / 2)";
8
+ const BASIS = {
9
+ full: "100%",
10
+ half: "50%",
11
+ third: "33.333%",
12
+ twoThirds: "66.666%"
13
+ };
14
+ /**
15
+ * Flex sizing for one answer field. Full fields (and file links / repeaters) claim a whole row;
16
+ * fractional ones sit side by side, their basis trimmed by the gutter and floored by `min-width`
17
+ * so a half or third never collapses on a narrow admin panel (it wraps to its own row instead).
18
+ */
19
+ const widthStyle = (width) => {
20
+ const basis = BASIS[width ?? "full"];
21
+ return basis === "100%" ? { flex: "1 1 100%" } : {
22
+ flex: `0 1 calc(${basis} - ${FIELD_GAP})`,
23
+ minWidth: "min(100%, 12rem)"
24
+ };
25
+ };
26
+ const answersGrid = {
27
+ display: "flex",
28
+ flexWrap: "wrap",
29
+ columnGap: FIELD_GAP
30
+ };
31
+ const fullWidth = { flex: "1 1 100%" };
15
32
  const rowHeading = {
16
33
  fontSize: "0.75rem",
17
34
  fontWeight: 600,
18
35
  color: "var(--theme-elevation-500)",
19
36
  margin: "0 0 4px"
20
37
  };
38
+ const linkStyle = {
39
+ display: "block",
40
+ padding: "8px 0",
41
+ color: "var(--theme-text)",
42
+ textDecoration: "underline"
43
+ };
21
44
  const SubmissionAnswersClient = ({ answers, repeaters, consent, meta, labels }) => {
22
45
  if (!(answers.length > 0 || repeaters.length > 0 || consent.length > 0 || meta.length > 0)) return /* @__PURE__ */ jsx("p", {
23
46
  style: { color: "var(--theme-elevation-500)" },
@@ -31,20 +54,17 @@ const SubmissionAnswersClient = ({ answers, repeaters, consent, meta, labels })
31
54
  gap: "32px"
32
55
  },
33
56
  children: [
34
- (answers.length > 0 || repeaters.length > 0) && /* @__PURE__ */ jsxs("section", { children: [
35
- /* @__PURE__ */ jsx(FieldLabel, { label: labels.answers }),
36
- answers.map(({ field, label, value, href }) => href ? /* @__PURE__ */ jsxs("div", {
57
+ (answers.length > 0 || repeaters.length > 0) && /* @__PURE__ */ jsxs("section", { children: [/* @__PURE__ */ jsx(FieldLabel, { label: labels.answers }), /* @__PURE__ */ jsxs("div", {
58
+ className: "render-fields",
59
+ style: answersGrid,
60
+ children: [answers.map(({ field, label, value, href, width }) => href ? /* @__PURE__ */ jsxs("div", {
37
61
  className: "field-type",
62
+ style: fullWidth,
38
63
  children: [/* @__PURE__ */ jsx(FieldLabel, { label }), /* @__PURE__ */ jsx("a", {
39
64
  href,
40
65
  target: "_blank",
41
66
  rel: "noreferrer",
42
- style: {
43
- display: "block",
44
- padding: "8px 0",
45
- color: "var(--theme-text)",
46
- textDecoration: "underline"
47
- },
67
+ style: linkStyle,
48
68
  children: value
49
69
  })]
50
70
  }, field) : /* @__PURE__ */ jsx(TextInput, {
@@ -52,10 +72,11 @@ const SubmissionAnswersClient = ({ answers, repeaters, consent, meta, labels })
52
72
  label,
53
73
  value,
54
74
  readOnly: true,
55
- onChange: noop
56
- }, field)),
57
- repeaters.map(({ field, label, rows }) => /* @__PURE__ */ jsxs("div", {
75
+ onChange: noop,
76
+ style: widthStyle(width)
77
+ }, field)), repeaters.map(({ field, label, rows }) => /* @__PURE__ */ jsxs("div", {
58
78
  className: "field-type",
79
+ style: fullWidth,
59
80
  children: [/* @__PURE__ */ jsx(FieldLabel, { label }), rows.length === 0 ? /* @__PURE__ */ jsx(TextInput, {
60
81
  path: `sa-${field}-empty`,
61
82
  label: "",
@@ -87,52 +108,67 @@ const SubmissionAnswersClient = ({ answers, repeaters, consent, meta, labels })
87
108
  }, subField.label))]
88
109
  }, row.id))
89
110
  })]
90
- }, field))
91
- ] }),
92
- consent.length > 0 && /* @__PURE__ */ jsxs("section", { children: [/* @__PURE__ */ jsx(FieldLabel, { label: labels.consent }), consent.map((entry) => /* @__PURE__ */ jsxs("div", {
93
- className: "field-type",
94
- children: [/* @__PURE__ */ jsx(FieldLabel, { label: entry.field }), /* @__PURE__ */ jsxs("div", {
95
- style: {
96
- display: "flex",
97
- flexDirection: "column",
98
- gap: "4px"
99
- },
100
- children: [/* @__PURE__ */ jsxs("div", {
111
+ }, field))]
112
+ })] }),
113
+ consent.length > 0 && /* @__PURE__ */ jsxs("section", { children: [/* @__PURE__ */ jsx(FieldLabel, { label: labels.consent }), /* @__PURE__ */ jsx("div", {
114
+ className: "render-fields",
115
+ children: consent.map((entry) => /* @__PURE__ */ jsxs("div", {
116
+ className: "field-type",
117
+ children: [/* @__PURE__ */ jsx(FieldLabel, { label: entry.field }), /* @__PURE__ */ jsxs("div", {
101
118
  style: {
102
119
  display: "flex",
103
- alignItems: "center",
104
- gap: "8px",
105
- flexWrap: "wrap"
106
- },
107
- children: [/* @__PURE__ */ jsx("span", {
108
- style: pillStyle(entry.agreed),
109
- children: entry.agreed ? labels.agreed : labels.declined
110
- }), entry.ref ? /* @__PURE__ */ jsxs("a", {
111
- href: entry.ref,
112
- target: "_blank",
113
- rel: "noreferrer",
114
- style: {
115
- fontSize: "0.8rem",
116
- color: "var(--theme-text)"
117
- },
118
- children: [entry.ref, entry.versionRef ? ` (v${entry.versionRef})` : ""]
119
- }) : null]
120
- }), /* @__PURE__ */ jsx("span", {
121
- style: {
122
- fontSize: "0.75rem",
123
- color: "var(--theme-elevation-500)"
120
+ flexDirection: "column",
121
+ gap: "4px"
124
122
  },
125
- children: entry.at
123
+ children: [
124
+ /* @__PURE__ */ jsxs("div", {
125
+ style: {
126
+ display: "flex",
127
+ alignItems: "center",
128
+ gap: "8px",
129
+ flexWrap: "wrap"
130
+ },
131
+ children: [/* @__PURE__ */ jsx(Pill, {
132
+ pillStyle: entry.agreed ? "success" : "error",
133
+ size: "small",
134
+ rounded: true,
135
+ children: entry.agreed ? labels.agreed : labels.declined
136
+ }), entry.name ? /* @__PURE__ */ jsxs("span", {
137
+ style: {
138
+ fontSize: "0.8rem",
139
+ color: "var(--theme-text)"
140
+ },
141
+ children: [entry.name, entry.versionRef ? ` (v${entry.versionRef})` : ""]
142
+ }) : null]
143
+ }),
144
+ entry.statementText ? /* @__PURE__ */ jsx("span", {
145
+ style: {
146
+ fontSize: "0.8rem",
147
+ color: "var(--theme-elevation-600)"
148
+ },
149
+ children: entry.statementText
150
+ }) : null,
151
+ /* @__PURE__ */ jsx("span", {
152
+ style: {
153
+ fontSize: "0.75rem",
154
+ color: "var(--theme-elevation-500)"
155
+ },
156
+ children: entry.at
157
+ })
158
+ ]
126
159
  })]
127
- })]
128
- }, entry.field))] }),
129
- meta.length > 0 && /* @__PURE__ */ jsxs("section", { children: [/* @__PURE__ */ jsx(FieldLabel, { label: labels.submissionDetails }), meta.map((item) => /* @__PURE__ */ jsx(TextInput, {
130
- path: `sa-meta-${item.label}`,
131
- label: item.label,
132
- value: item.value,
133
- readOnly: true,
134
- onChange: noop
135
- }, item.label))] })
160
+ }, entry.field))
161
+ })] }),
162
+ meta.length > 0 && /* @__PURE__ */ jsxs("section", { children: [/* @__PURE__ */ jsx(FieldLabel, { label: labels.submissionDetails }), /* @__PURE__ */ jsx("div", {
163
+ className: "render-fields",
164
+ children: meta.map((item) => /* @__PURE__ */ jsx(TextInput, {
165
+ path: `sa-meta-${item.label}`,
166
+ label: item.label,
167
+ value: item.value,
168
+ readOnly: true,
169
+ onChange: noop
170
+ }, item.label))
171
+ })] })
136
172
  ]
137
173
  });
138
174
  };
@@ -1 +1 @@
1
- {"version":3,"file":"SubmissionAnswersClient.js","names":[],"sources":["../../src/submissions/SubmissionAnswersClient.tsx"],"sourcesContent":["'use client'\n\nimport { FieldLabel, TextInput } from '@payloadcms/ui'\nimport type { ChangeEvent } from 'react'\n\nexport type AnswerItem = {\n\tfield: string\n\tlabel: string\n\tvalue: string\n\thref?: string\n\tmultiline?: boolean\n}\n\nexport type RepeaterRow = {\n\tid: string\n\tsubFields: Array<{ label: string; value: string }>\n}\n\nexport type RepeaterItem = {\n\tfield: string\n\tlabel: string\n\trows: RepeaterRow[]\n}\n\nexport type ConsentItem = {\n\tfield: string\n\tagreed: boolean\n\tref?: string\n\tversionRef?: string\n\tat: string\n}\n\nexport type MetaItem = {\n\tlabel: string\n\tvalue: string\n}\n\nexport type SubmissionAnswersLabels = {\n\tanswers: string\n\tconsent: string\n\tsubmissionDetails: string\n\tagreed: string\n\tdeclined: string\n\t/** Row heading template containing `{n}`, the 1-based row number. */\n\trow: string\n\tempty: string\n}\n\ntype Props = {\n\tanswers: AnswerItem[]\n\trepeaters: RepeaterItem[]\n\tconsent: ConsentItem[]\n\tmeta: MetaItem[]\n\tlabels: SubmissionAnswersLabels\n}\n\nconst noop = (_e: ChangeEvent<HTMLInputElement>) => {}\n\nconst pillStyle = (agreed: boolean): React.CSSProperties => ({\n\tdisplay: 'inline-block',\n\tpadding: '2px 8px',\n\tborderRadius: '9999px',\n\tfontSize: '0.75rem',\n\tfontWeight: 600,\n\tbackground: agreed ? 'var(--theme-success-500)' : 'var(--theme-error-500)',\n\tcolor: '#fff',\n})\n\nconst rowHeading: React.CSSProperties = {\n\tfontSize: '0.75rem',\n\tfontWeight: 600,\n\tcolor: 'var(--theme-elevation-500)',\n\tmargin: '0 0 4px',\n}\n\nexport const SubmissionAnswersClient = ({ answers, repeaters, consent, meta, labels }: Props) => {\n\tconst hasContent =\n\t\tanswers.length > 0 || repeaters.length > 0 || consent.length > 0 || meta.length > 0\n\n\tif (!hasContent) {\n\t\treturn <p style={{ color: 'var(--theme-elevation-500)' }}>{labels.empty}</p>\n\t}\n\n\treturn (\n\t\t<div className=\"field-type\" style={{ display: 'flex', flexDirection: 'column', gap: '32px' }}>\n\t\t\t{(answers.length > 0 || repeaters.length > 0) && (\n\t\t\t\t<section>\n\t\t\t\t\t<FieldLabel label={labels.answers} />\n\t\t\t\t\t{answers.map(({ field, label, value, href }) =>\n\t\t\t\t\t\thref ? (\n\t\t\t\t\t\t\t<div key={field} className=\"field-type\">\n\t\t\t\t\t\t\t\t<FieldLabel label={label} />\n\t\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\t\thref={href}\n\t\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\t\trel=\"noreferrer\"\n\t\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\t\tdisplay: 'block',\n\t\t\t\t\t\t\t\t\t\tpadding: '8px 0',\n\t\t\t\t\t\t\t\t\t\tcolor: 'var(--theme-text)',\n\t\t\t\t\t\t\t\t\t\ttextDecoration: 'underline',\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{value}\n\t\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t<TextInput\n\t\t\t\t\t\t\t\tkey={field}\n\t\t\t\t\t\t\t\tpath={`sa-${field}`}\n\t\t\t\t\t\t\t\tlabel={label}\n\t\t\t\t\t\t\t\tvalue={value}\n\t\t\t\t\t\t\t\treadOnly\n\t\t\t\t\t\t\t\tonChange={noop}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t)\n\t\t\t\t\t)}\n\n\t\t\t\t\t{repeaters.map(({ field, label, rows }) => (\n\t\t\t\t\t\t<div key={field} className=\"field-type\">\n\t\t\t\t\t\t\t<FieldLabel label={label} />\n\t\t\t\t\t\t\t{rows.length === 0 ? (\n\t\t\t\t\t\t\t\t<TextInput path={`sa-${field}-empty`} label=\"\" value=\"—\" readOnly onChange={noop} />\n\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\t\tstyle={{ display: 'flex', flexDirection: 'column', gap: '8px', marginTop: '4px' }}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{rows.map((row) => (\n\t\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\t\tkey={row.id}\n\t\t\t\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\t\t\t\tborder: '1px solid var(--theme-elevation-150)',\n\t\t\t\t\t\t\t\t\t\t\t\tborderRadius: '4px',\n\t\t\t\t\t\t\t\t\t\t\t\tpadding: '4px 12px 0',\n\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<p style={rowHeading}>\n\t\t\t\t\t\t\t\t\t\t\t\t{labels.row.replace('{n}', String(Number(row.id) + 1))}\n\t\t\t\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t\t\t\t{row.subFields.map((subField) => (\n\t\t\t\t\t\t\t\t\t\t\t\t<TextInput\n\t\t\t\t\t\t\t\t\t\t\t\t\tkey={subField.label}\n\t\t\t\t\t\t\t\t\t\t\t\t\tpath={`sa-${field}-${row.id}-${subField.label}`}\n\t\t\t\t\t\t\t\t\t\t\t\t\tlabel={subField.label}\n\t\t\t\t\t\t\t\t\t\t\t\t\tvalue={subField.value}\n\t\t\t\t\t\t\t\t\t\t\t\t\treadOnly\n\t\t\t\t\t\t\t\t\t\t\t\t\tonChange={noop}\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))}\n\t\t\t\t\t\t\t\t\t\t</div>\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)}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t))}\n\t\t\t\t</section>\n\t\t\t)}\n\n\t\t\t{consent.length > 0 && (\n\t\t\t\t<section>\n\t\t\t\t\t<FieldLabel label={labels.consent} />\n\t\t\t\t\t{consent.map((entry) => (\n\t\t\t\t\t\t<div key={entry.field} className=\"field-type\">\n\t\t\t\t\t\t\t<FieldLabel label={entry.field} />\n\t\t\t\t\t\t\t<div style={{ display: 'flex', flexDirection: 'column', gap: '4px' }}>\n\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\tstyle={{ display: 'flex', alignItems: 'center', gap: '8px', flexWrap: 'wrap' }}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<span style={pillStyle(entry.agreed)}>\n\t\t\t\t\t\t\t\t\t\t{entry.agreed ? labels.agreed : labels.declined}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t{entry.ref ? (\n\t\t\t\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\t\t\t\thref={entry.ref}\n\t\t\t\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\t\t\t\trel=\"noreferrer\"\n\t\t\t\t\t\t\t\t\t\t\tstyle={{ fontSize: '0.8rem', color: 'var(--theme-text)' }}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t{entry.ref}\n\t\t\t\t\t\t\t\t\t\t\t{entry.versionRef ? ` (v${entry.versionRef})` : ''}\n\t\t\t\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<span style={{ fontSize: '0.75rem', color: 'var(--theme-elevation-500)' }}>\n\t\t\t\t\t\t\t\t\t{entry.at}\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t))}\n\t\t\t\t</section>\n\t\t\t)}\n\n\t\t\t{meta.length > 0 && (\n\t\t\t\t<section>\n\t\t\t\t\t<FieldLabel label={labels.submissionDetails} />\n\t\t\t\t\t{meta.map((item) => (\n\t\t\t\t\t\t<TextInput\n\t\t\t\t\t\t\tkey={item.label}\n\t\t\t\t\t\t\tpath={`sa-meta-${item.label}`}\n\t\t\t\t\t\t\tlabel={item.label}\n\t\t\t\t\t\t\tvalue={item.value}\n\t\t\t\t\t\t\treadOnly\n\t\t\t\t\t\t\tonChange={noop}\n\t\t\t\t\t\t/>\n\t\t\t\t\t))}\n\t\t\t\t</section>\n\t\t\t)}\n\t\t</div>\n\t)\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"SubmissionAnswersClient.js","names":[],"sources":["../../src/submissions/SubmissionAnswersClient.tsx"],"sourcesContent":["'use client'\n\nimport { FieldLabel, Pill, TextInput } from '@payloadcms/ui'\nimport type { ChangeEvent } from 'react'\nimport type { SubmissionWidth } from './types'\n\nexport type AnswerItem = {\n\tfield: string\n\tlabel: string\n\tvalue: string\n\thref?: string\n\tmultiline?: boolean\n\twidth?: SubmissionWidth\n}\n\nexport type RepeaterRow = {\n\tid: string\n\tsubFields: Array<{ label: string; value: string }>\n}\n\nexport type RepeaterItem = {\n\tfield: string\n\tlabel: string\n\trows: RepeaterRow[]\n}\n\nexport type ConsentItem = {\n\tfield: string\n\tagreed: boolean\n\t/** The consent source's name at submit time (see `ConsentProof.name`). */\n\tname?: string\n\t/** The plain-text snapshot of the wording agreed to (see `ConsentProof.statementText`). */\n\tstatementText?: string\n\tversionRef?: string\n\tat: string\n}\n\nexport type MetaItem = {\n\tlabel: string\n\tvalue: string\n}\n\nexport type SubmissionAnswersLabels = {\n\tanswers: string\n\tconsent: string\n\tsubmissionDetails: string\n\tagreed: string\n\tdeclined: string\n\t/** Row heading template containing `{n}`, the 1-based row number. */\n\trow: string\n\tempty: string\n}\n\ntype Props = {\n\tanswers: AnswerItem[]\n\trepeaters: RepeaterItem[]\n\tconsent: ConsentItem[]\n\tmeta: MetaItem[]\n\tlabels: SubmissionAnswersLabels\n}\n\nconst noop = (_e: ChangeEvent<HTMLInputElement>) => {}\n\n/** Horizontal gutter between fields sharing a row; also trimmed from each fractional basis so widths wrap cleanly rather than overflow. */\nconst FIELD_GAP = 'calc(var(--base, 20px) / 2)'\n\nconst BASIS: Record<SubmissionWidth, string> = {\n\tfull: '100%',\n\thalf: '50%',\n\tthird: '33.333%',\n\ttwoThirds: '66.666%',\n}\n\n/**\n * Flex sizing for one answer field. Full fields (and file links / repeaters) claim a whole row;\n * fractional ones sit side by side, their basis trimmed by the gutter and floored by `min-width`\n * so a half or third never collapses on a narrow admin panel (it wraps to its own row instead).\n */\nconst widthStyle = (width?: SubmissionWidth): React.CSSProperties => {\n\tconst basis = BASIS[width ?? 'full']\n\treturn basis === '100%'\n\t\t? { flex: '1 1 100%' }\n\t\t: { flex: `0 1 calc(${basis} - ${FIELD_GAP})`, minWidth: 'min(100%, 12rem)' }\n}\n\nconst answersGrid: React.CSSProperties = {\n\tdisplay: 'flex',\n\tflexWrap: 'wrap',\n\tcolumnGap: FIELD_GAP,\n}\n\nconst fullWidth: React.CSSProperties = { flex: '1 1 100%' }\n\nconst rowHeading: React.CSSProperties = {\n\tfontSize: '0.75rem',\n\tfontWeight: 600,\n\tcolor: 'var(--theme-elevation-500)',\n\tmargin: '0 0 4px',\n}\n\nconst linkStyle: React.CSSProperties = {\n\tdisplay: 'block',\n\tpadding: '8px 0',\n\tcolor: 'var(--theme-text)',\n\ttextDecoration: 'underline',\n}\n\nexport const SubmissionAnswersClient = ({ answers, repeaters, consent, meta, labels }: Props) => {\n\tconst hasContent =\n\t\tanswers.length > 0 || repeaters.length > 0 || consent.length > 0 || meta.length > 0\n\n\tif (!hasContent) {\n\t\treturn <p style={{ color: 'var(--theme-elevation-500)' }}>{labels.empty}</p>\n\t}\n\n\treturn (\n\t\t<div className=\"field-type\" style={{ display: 'flex', flexDirection: 'column', gap: '32px' }}>\n\t\t\t{(answers.length > 0 || repeaters.length > 0) && (\n\t\t\t\t<section>\n\t\t\t\t\t<FieldLabel label={labels.answers} />\n\t\t\t\t\t<div className=\"render-fields\" style={answersGrid}>\n\t\t\t\t\t\t{answers.map(({ field, label, value, href, width }) =>\n\t\t\t\t\t\t\thref ? (\n\t\t\t\t\t\t\t\t<div key={field} className=\"field-type\" style={fullWidth}>\n\t\t\t\t\t\t\t\t\t<FieldLabel label={label} />\n\t\t\t\t\t\t\t\t\t<a href={href} target=\"_blank\" rel=\"noreferrer\" style={linkStyle}>\n\t\t\t\t\t\t\t\t\t\t{value}\n\t\t\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t<TextInput\n\t\t\t\t\t\t\t\t\tkey={field}\n\t\t\t\t\t\t\t\t\tpath={`sa-${field}`}\n\t\t\t\t\t\t\t\t\tlabel={label}\n\t\t\t\t\t\t\t\t\tvalue={value}\n\t\t\t\t\t\t\t\t\treadOnly\n\t\t\t\t\t\t\t\t\tonChange={noop}\n\t\t\t\t\t\t\t\t\tstyle={widthStyle(width)}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t{repeaters.map(({ field, label, rows }) => (\n\t\t\t\t\t\t\t<div key={field} className=\"field-type\" style={fullWidth}>\n\t\t\t\t\t\t\t\t<FieldLabel label={label} />\n\t\t\t\t\t\t\t\t{rows.length === 0 ? (\n\t\t\t\t\t\t\t\t\t<TextInput\n\t\t\t\t\t\t\t\t\t\tpath={`sa-${field}-empty`}\n\t\t\t\t\t\t\t\t\t\tlabel=\"\"\n\t\t\t\t\t\t\t\t\t\tvalue=\"—\"\n\t\t\t\t\t\t\t\t\t\treadOnly\n\t\t\t\t\t\t\t\t\t\tonChange={noop}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\t\t\tdisplay: 'flex',\n\t\t\t\t\t\t\t\t\t\t\tflexDirection: 'column',\n\t\t\t\t\t\t\t\t\t\t\tgap: '8px',\n\t\t\t\t\t\t\t\t\t\t\tmarginTop: '4px',\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\t\t{rows.map((row) => (\n\t\t\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\t\t\tkey={row.id}\n\t\t\t\t\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\t\t\t\t\tborder: '1px solid var(--theme-elevation-150)',\n\t\t\t\t\t\t\t\t\t\t\t\t\tborderRadius: '4px',\n\t\t\t\t\t\t\t\t\t\t\t\t\tpadding: '4px 12px 0',\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>\n\t\t\t\t\t\t\t\t\t\t\t\t<p style={rowHeading}>\n\t\t\t\t\t\t\t\t\t\t\t\t\t{labels.row.replace('{n}', String(Number(row.id) + 1))}\n\t\t\t\t\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t\t\t\t\t{row.subFields.map((subField) => (\n\t\t\t\t\t\t\t\t\t\t\t\t\t<TextInput\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tkey={subField.label}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tpath={`sa-${field}-${row.id}-${subField.label}`}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tlabel={subField.label}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tvalue={subField.value}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\treadOnly\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tonChange={noop}\n\t\t\t\t\t\t\t\t\t\t\t\t\t/>\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</div>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</div>\n\t\t\t\t</section>\n\t\t\t)}\n\n\t\t\t{consent.length > 0 && (\n\t\t\t\t<section>\n\t\t\t\t\t<FieldLabel label={labels.consent} />\n\t\t\t\t\t<div className=\"render-fields\">\n\t\t\t\t\t\t{consent.map((entry) => (\n\t\t\t\t\t\t\t<div key={entry.field} className=\"field-type\">\n\t\t\t\t\t\t\t\t<FieldLabel label={entry.field} />\n\t\t\t\t\t\t\t\t<div style={{ display: 'flex', flexDirection: 'column', gap: '4px' }}>\n\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\tstyle={{ display: 'flex', alignItems: 'center', gap: '8px', flexWrap: 'wrap' }}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<Pill pillStyle={entry.agreed ? 'success' : 'error'} size=\"small\" rounded>\n\t\t\t\t\t\t\t\t\t\t\t{entry.agreed ? labels.agreed : labels.declined}\n\t\t\t\t\t\t\t\t\t\t</Pill>\n\t\t\t\t\t\t\t\t\t\t{entry.name ? (\n\t\t\t\t\t\t\t\t\t\t\t<span style={{ fontSize: '0.8rem', color: 'var(--theme-text)' }}>\n\t\t\t\t\t\t\t\t\t\t\t\t{entry.name}\n\t\t\t\t\t\t\t\t\t\t\t\t{entry.versionRef ? ` (v${entry.versionRef})` : ''}\n\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t{entry.statementText ? (\n\t\t\t\t\t\t\t\t\t\t<span style={{ fontSize: '0.8rem', color: 'var(--theme-elevation-600)' }}>\n\t\t\t\t\t\t\t\t\t\t\t{entry.statementText}\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t<span style={{ fontSize: '0.75rem', color: 'var(--theme-elevation-500)' }}>\n\t\t\t\t\t\t\t\t\t\t{entry.at}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</div>\n\t\t\t\t</section>\n\t\t\t)}\n\n\t\t\t{meta.length > 0 && (\n\t\t\t\t<section>\n\t\t\t\t\t<FieldLabel label={labels.submissionDetails} />\n\t\t\t\t\t<div className=\"render-fields\">\n\t\t\t\t\t\t{meta.map((item) => (\n\t\t\t\t\t\t\t<TextInput\n\t\t\t\t\t\t\t\tkey={item.label}\n\t\t\t\t\t\t\t\tpath={`sa-meta-${item.label}`}\n\t\t\t\t\t\t\t\tlabel={item.label}\n\t\t\t\t\t\t\t\tvalue={item.value}\n\t\t\t\t\t\t\t\treadOnly\n\t\t\t\t\t\t\t\tonChange={noop}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</div>\n\t\t\t\t</section>\n\t\t\t)}\n\t\t</div>\n\t)\n}\n"],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ import { SubmissionDescriptor, SubmissionValue } from "./types.js";
2
+ import { ConsentProofEntry } from "./runSubmission.js";
3
+ import { Payload, PayloadRequest } from "payload";
4
+
5
+ //#region src/submissions/createSubmission.d.ts
6
+ type CreateSubmissionArgs = {
7
+ form: number | string;
8
+ values: SubmissionValue[]; /** Thread the incoming request when there is one, so spam metadata (IP, user agent) and per-identity rate limiting see it. */
9
+ req?: PayloadRequest;
10
+ };
11
+ /** The stored shape of a `form-submissions` document, as written by the collection's own hooks. */
12
+ type CreatedSubmission = {
13
+ id: number | string;
14
+ form: number | string;
15
+ status: 'complete' | 'partial';
16
+ locale?: string;
17
+ values?: SubmissionValue[];
18
+ descriptors?: SubmissionDescriptor[];
19
+ consent?: ConsentProofEntry[];
20
+ meta?: Record<string, unknown>;
21
+ createdAt: string;
22
+ updatedAt: string;
23
+ };
24
+ /**
25
+ * Server-side counterpart to the browser `submitForm` helper: a typed wrapper over `payload.create`
26
+ * for the `form-submissions` collection. Submitting this way runs the exact same pipeline a browser
27
+ * or raw REST submit does, server-authoritative validation, spam metadata capture when `req` is
28
+ * threaded through, descriptor snapshotting, consent capture, and post-submit action dispatch, since
29
+ * all of it lives in the collection's own hooks rather than in a route handler. Use it from server
30
+ * code (a script, a queued job, another collection's hook) instead of hand-rolling the collection
31
+ * slug and body shape.
32
+ */
33
+ declare const createSubmission: (payload: Payload, args: CreateSubmissionArgs) => Promise<CreatedSubmission>;
34
+ //#endregion
35
+ export { CreateSubmissionArgs, CreatedSubmission, createSubmission };
36
+ //# sourceMappingURL=createSubmission.d.ts.map
@@ -0,0 +1,26 @@
1
+ import { FORM_SUBMISSIONS_SLUG } from "../collections/formSubmissions.js";
2
+ //#region src/submissions/createSubmission.ts
3
+ /**
4
+ * Server-side counterpart to the browser `submitForm` helper: a typed wrapper over `payload.create`
5
+ * for the `form-submissions` collection. Submitting this way runs the exact same pipeline a browser
6
+ * or raw REST submit does, server-authoritative validation, spam metadata capture when `req` is
7
+ * threaded through, descriptor snapshotting, consent capture, and post-submit action dispatch, since
8
+ * all of it lives in the collection's own hooks rather than in a route handler. Use it from server
9
+ * code (a script, a queued job, another collection's hook) instead of hand-rolling the collection
10
+ * slug and body shape.
11
+ */
12
+ const createSubmission = (payload, args) => {
13
+ const create = payload.create;
14
+ return create({
15
+ collection: FORM_SUBMISSIONS_SLUG,
16
+ data: {
17
+ form: args.form,
18
+ values: args.values
19
+ },
20
+ req: args.req
21
+ });
22
+ };
23
+ //#endregion
24
+ export { createSubmission };
25
+
26
+ //# sourceMappingURL=createSubmission.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createSubmission.js","names":[],"sources":["../../src/submissions/createSubmission.ts"],"sourcesContent":["import type { Payload, PayloadRequest } from 'payload'\nimport { FORM_SUBMISSIONS_SLUG } from '../collections/formSubmissions'\nimport type { ConsentProofEntry } from './runSubmission'\nimport type { SubmissionDescriptor, SubmissionValue } from './types'\n\nexport type CreateSubmissionArgs = {\n\tform: number | string\n\tvalues: SubmissionValue[]\n\t/** Thread the incoming request when there is one, so spam metadata (IP, user agent) and per-identity rate limiting see it. */\n\treq?: PayloadRequest\n}\n\n/** The stored shape of a `form-submissions` document, as written by the collection's own hooks. */\nexport type CreatedSubmission = {\n\tid: number | string\n\tform: number | string\n\tstatus: 'complete' | 'partial'\n\tlocale?: string\n\tvalues?: SubmissionValue[]\n\tdescriptors?: SubmissionDescriptor[]\n\tconsent?: ConsentProofEntry[]\n\tmeta?: Record<string, unknown>\n\tcreatedAt: string\n\tupdatedAt: string\n}\n\n/**\n * Server-side counterpart to the browser `submitForm` helper: a typed wrapper over `payload.create`\n * for the `form-submissions` collection. Submitting this way runs the exact same pipeline a browser\n * or raw REST submit does, server-authoritative validation, spam metadata capture when `req` is\n * threaded through, descriptor snapshotting, consent capture, and post-submit action dispatch, since\n * all of it lives in the collection's own hooks rather than in a route handler. Use it from server\n * code (a script, a queued job, another collection's hook) instead of hand-rolling the collection\n * slug and body shape.\n */\nexport const createSubmission = (\n\tpayload: Payload,\n\targs: CreateSubmissionArgs\n): Promise<CreatedSubmission> => {\n\t// `form-submissions` is registered by this plugin at runtime, so a host's generated Payload types\n\t// need not describe it, and when they do, pin its `form` relationship to whichever single id type\n\t// (string or number) that host's database uses. `form` here accepts either, so create through a\n\t// slug-agnostic signature instead of the host's own shape (same idiom as `registerReliability`'s\n\t// locks-collection create in the jobs plugin).\n\tconst create = payload.create as unknown as (options: {\n\t\tcollection: string\n\t\tdata: { form: number | string; values: SubmissionValue[] }\n\t\treq?: PayloadRequest\n\t}) => Promise<CreatedSubmission>\n\treturn create({\n\t\tcollection: FORM_SUBMISSIONS_SLUG,\n\t\tdata: { form: args.form, values: args.values },\n\t\treq: args.req,\n\t})\n}\n"],"mappings":";;;;;;;;;;;AAmCA,MAAa,oBACZ,SACA,SACgC;CAMhC,MAAM,SAAS,QAAQ;CAKvB,OAAO,OAAO;EACb,YAAY;EACZ,MAAM;GAAE,MAAM,KAAK;GAAM,QAAQ,KAAK;EAAO;EAC7C,KAAK,KAAK;CACX,CAAC;AACF"}
@@ -0,0 +1,10 @@
1
+ import { ConsentProof } from "../consent/captureConsent.js";
2
+ import { Payload, PayloadRequest } from "payload";
3
+
4
+ //#region src/submissions/runSubmission.d.ts
5
+ type ConsentProofEntry = {
6
+ field: string;
7
+ } & ConsentProof;
8
+ //#endregion
9
+ export { ConsentProofEntry };
10
+ //# sourceMappingURL=runSubmission.d.ts.map
@@ -1,10 +1,19 @@
1
1
  import { keys } from "../translations/keys.js";
2
+ import { isNamedField } from "../fields/fieldKey.js";
2
3
  import { calcExpressionOf, computeCalcFields } from "../calc/computeCalcFields.js";
3
4
  import { evaluateCondition } from "../conditions/evaluate.js";
4
5
  import { captureConsent } from "../consent/captureConsent.js";
5
6
  import { captureFileRef } from "../uploads/captureFileRef.js";
6
7
  import { runValidation } from "../validation/runValidation.js";
7
8
  //#region src/submissions/runSubmission.ts
9
+ const SUBMISSION_WIDTHS = new Set([
10
+ "full",
11
+ "half",
12
+ "third",
13
+ "twoThirds"
14
+ ]);
15
+ /** The field instance's authored layout width, or undefined if unset/unrecognized (renders full). */
16
+ const widthOf = (instance) => typeof instance.width === "string" && SUBMISSION_WIDTHS.has(instance.width) ? instance.width : void 0;
8
17
  const errorKeyFor = (code) => {
9
18
  if (code === "mimeType") return keys.validationFileMimeType;
10
19
  if (code === "tooLarge") return keys.validationFileTooLarge;
@@ -54,19 +63,18 @@ const optionLabelsFor = (instance) => {
54
63
  * field whose `visibleWhen` is false is skipped entirely (never validated, never stored, so a client-sent
55
64
  * value for it is ignored), and a visible field whose `validateWhen` is false stores its value but skips
56
65
  * validation. A visible calc field stores its derived value and is never validated. Display-only field
57
- * types (value kind 'none', e.g. message) are skipped in both passes: never validated, never stored, and
58
- * a client-sent value under their name is dropped. Only `error` severity blocks; warnings are computed
59
- * but not surfaced server-side (the renderer surfaces them).
66
+ * types (value kind 'none', e.g. message) and nameless (bare) rows are skipped in both passes: never
67
+ * validated, never stored, and a client-sent value under their name is dropped.
60
68
  */
61
69
  const runSubmission = async (input) => {
62
- const { fields, values, registry, ruleRegistry, consentRegistry, locale, t, operation, req, payload, formId, uploadSlug, expectedOwner } = input;
70
+ const { fields, values, registry, ruleRegistry, consentEntries, consentSnapshot, locale, t, operation, req, payload, formId, uploadSlug, expectedOwner } = input;
63
71
  const incoming = new Map(values.map((entry) => [entry.field, entry.value]));
64
72
  const coercedAnswers = {};
65
73
  const coercedByName = /* @__PURE__ */ new Map();
66
74
  for (const instance of fields) {
67
75
  const definition = registry.get(instance.blockType);
76
+ if (!definition || definition.value === "none" || calcExpressionOf(instance) || !isNamedField(instance)) continue;
68
77
  const raw = incoming.get(instance.name);
69
- if (!definition || definition.value === "none" || calcExpressionOf(instance)) continue;
70
78
  const effectiveRaw = instance.blockType === "consent" && isEmpty(raw) ? false : instance.blockType === "repeater" && isEmpty(raw) ? [] : raw;
71
79
  if (isEmpty(effectiveRaw) && instance.blockType !== "repeater") continue;
72
80
  const value = coerce(definition.value, effectiveRaw);
@@ -81,7 +89,7 @@ const runSubmission = async (input) => {
81
89
  const now = (/* @__PURE__ */ new Date()).toISOString();
82
90
  for (const instance of fields) {
83
91
  const definition = registry.get(instance.blockType);
84
- if (!definition || definition.value === "none") continue;
92
+ if (!definition || definition.value === "none" || !isNamedField(instance)) continue;
85
93
  const raw = incoming.get(instance.name);
86
94
  const value = coercedByName.has(instance.name) ? coercedByName.get(instance.name) : raw;
87
95
  if (!evaluateCondition(instance.visibleWhen, effective)) continue;
@@ -93,7 +101,8 @@ const runSubmission = async (input) => {
93
101
  descriptors.push({
94
102
  field: instance.name,
95
103
  label: instance.label ?? instance.name,
96
- fieldType: instance.blockType
104
+ fieldType: instance.blockType,
105
+ ...widthOf(instance) ? { width: widthOf(instance) } : {}
97
106
  });
98
107
  continue;
99
108
  }
@@ -114,11 +123,10 @@ const runSubmission = async (input) => {
114
123
  payload,
115
124
  formId
116
125
  });
117
- const blocking = issues.filter((issue) => issue.severity === "error");
118
- if (blocking.length > 0) {
119
- for (const issue of blocking) errors.push({
126
+ if (issues.length > 0) {
127
+ for (const message of issues) errors.push({
120
128
  path: instance.name,
121
- message: issue.message
129
+ message
122
130
  });
123
131
  continue;
124
132
  }
@@ -155,7 +163,8 @@ const runSubmission = async (input) => {
155
163
  descriptors.push({
156
164
  field: instance.name,
157
165
  label: instance.label ?? instance.name,
158
- fieldType: instance.blockType
166
+ fieldType: instance.blockType,
167
+ ...widthOf(instance) ? { width: widthOf(instance) } : {}
159
168
  });
160
169
  continue;
161
170
  }
@@ -166,7 +175,8 @@ const runSubmission = async (input) => {
166
175
  descriptors.push({
167
176
  field: instance.name,
168
177
  label: instance.label ?? instance.name,
169
- fieldType: instance.blockType
178
+ fieldType: instance.blockType,
179
+ ...widthOf(instance) ? { width: widthOf(instance) } : {}
170
180
  });
171
181
  continue;
172
182
  }
@@ -174,11 +184,11 @@ const runSubmission = async (input) => {
174
184
  const proof = await captureConsent({
175
185
  field: instance,
176
186
  agreed: value === true,
177
- registry: consentRegistry,
187
+ entries: consentEntries ?? [],
178
188
  payload,
179
189
  req,
180
- locale,
181
- now
190
+ now,
191
+ snapshot: consentSnapshot
182
192
  });
183
193
  consentProofs.push({
184
194
  field: instance.name,
@@ -188,7 +198,7 @@ const runSubmission = async (input) => {
188
198
  }
189
199
  if (instance.blockType === "repeater") {
190
200
  const rows = Array.isArray(value) ? value : [];
191
- const subFields = Array.isArray(instance.subFields) ? instance.subFields : [];
201
+ const subFields = (Array.isArray(instance.subFields) ? instance.subFields : []).filter(isNamedField);
192
202
  for (let rowIndex = 0; rowIndex < rows.length; rowIndex++) {
193
203
  const row = rows[rowIndex] ?? {};
194
204
  for (const subField of subFields) {
@@ -213,9 +223,9 @@ const runSubmission = async (input) => {
213
223
  payload,
214
224
  formId
215
225
  });
216
- for (const issue of subErrors.filter((e) => e.severity === "error")) errors.push({
226
+ for (const message of subErrors) errors.push({
217
227
  path: subPath,
218
- message: issue.message
228
+ message
219
229
  });
220
230
  }
221
231
  if (subDef.value === "file" && payload) {
@@ -264,6 +274,7 @@ const runSubmission = async (input) => {
264
274
  field: instance.name,
265
275
  label: instance.label ?? instance.name,
266
276
  fieldType: instance.blockType,
277
+ ...widthOf(instance) ? { width: widthOf(instance) } : {},
267
278
  ...subFieldDescriptors.length > 0 ? { subFieldDescriptors } : {}
268
279
  });
269
280
  continue;
@@ -278,6 +289,7 @@ const runSubmission = async (input) => {
278
289
  field: instance.name,
279
290
  label: instance.label ?? instance.name,
280
291
  fieldType: instance.blockType,
292
+ ...widthOf(instance) ? { width: widthOf(instance) } : {},
281
293
  ...optionLabels ? { optionLabels } : {}
282
294
  });
283
295
  }
@@ -1 +1 @@
1
- {"version":3,"file":"runSubmission.js","names":[],"sources":["../../src/submissions/runSubmission.ts"],"sourcesContent":["import type { Payload, PayloadRequest } from 'payload'\nimport { calcExpressionOf, computeCalcFields } from '../calc/computeCalcFields'\nimport { evaluateCondition } from '../conditions/evaluate'\nimport type { ConsentProof } from '../consent/captureConsent'\nimport { captureConsent } from '../consent/captureConsent'\nimport type { ConsentSourceRegistry } from '../consent/registry'\nimport type { FieldTypeRegistry } from '../fields/registry'\nimport type { Translate } from '../fields/types'\nimport { keys } from '../translations/keys'\nimport { captureFileRef } from '../uploads/captureFileRef'\nimport type { FileFieldConfig, FileRefError } from '../uploads/types'\nimport type { ValidationRuleRegistry } from '../validation/registry'\nimport { runValidation } from '../validation/runValidation'\nimport type {\n\tFormFieldInstance,\n\tSubmissionDescriptor,\n\tSubmissionFieldError,\n\tSubmissionValue,\n} from './types'\n\nconst errorKeyFor = (code: FileRefError): string => {\n\tif (code === 'mimeType') {\n\t\treturn keys.validationFileMimeType\n\t}\n\tif (code === 'tooLarge') {\n\t\treturn keys.validationFileTooLarge\n\t}\n\treturn keys.validationFileMissing\n}\n\n/** Normalize the authored `mimeTypes` (a `hasMany` text field) to a `string[]`. */\nconst mimeTypesOf = (raw: unknown): string[] | undefined => {\n\tif (!Array.isArray(raw)) {\n\t\treturn undefined\n\t}\n\tconst out = (raw as unknown[]).filter((entry): entry is string => typeof entry === 'string')\n\treturn out.length > 0 ? out : undefined\n}\n\nconst fileFieldConfigOf = (instance: FormFieldInstance): FileFieldConfig => ({\n\tmimeTypes: mimeTypesOf(instance.mimeTypes),\n\tmaxSize: typeof instance.maxSize === 'number' ? instance.maxSize : undefined,\n})\n\nconst isEmpty = (value: unknown): boolean =>\n\tvalue == null || value === '' || (Array.isArray(value) && value.length === 0)\n\nconst coerce = (kind: string, value: unknown): unknown => {\n\tif (value == null) {\n\t\treturn value\n\t}\n\tif (kind === 'number') {\n\t\tconst next = typeof value === 'number' ? value : Number(value)\n\t\treturn Number.isNaN(next) ? value : next\n\t}\n\tif (kind === 'boolean') {\n\t\t// A genuine boolean from the renderer passes through; a raw client string is parsed strictly so that\n\t\t// \"false\"/\"0\"/\"off\"/\"no\"/\"\" are not silently truthy (this matters for the required-consent check).\n\t\tif (typeof value === 'string') {\n\t\t\tconst normalized = value.trim().toLowerCase()\n\t\t\treturn !(\n\t\t\t\tnormalized === '' ||\n\t\t\t\tnormalized === 'false' ||\n\t\t\t\tnormalized === '0' ||\n\t\t\t\tnormalized === 'off' ||\n\t\t\t\tnormalized === 'no'\n\t\t\t)\n\t\t}\n\t\treturn Boolean(value)\n\t}\n\tif (kind === 'text') {\n\t\treturn typeof value === 'string' ? value : String(value)\n\t}\n\treturn value\n}\n\nconst optionLabelsFor = (instance: FormFieldInstance): Record<string, string> | undefined => {\n\tconst options = instance.options\n\tif (!Array.isArray(options)) {\n\t\treturn undefined\n\t}\n\tconst map: Record<string, string> = {}\n\tfor (const option of options as Array<{ label?: string; value?: string }>) {\n\t\tif (typeof option?.value === 'string') {\n\t\t\tmap[option.value] = option.label ?? option.value\n\t\t}\n\t}\n\treturn Object.keys(map).length > 0 ? map : undefined\n}\n\nexport type ConsentProofEntry = { field: string } & ConsentProof\n\nexport type RunSubmissionInput = {\n\tfields: FormFieldInstance[]\n\tvalues: SubmissionValue[]\n\tregistry: FieldTypeRegistry\n\truleRegistry: ValidationRuleRegistry\n\tconsentRegistry: ConsentSourceRegistry\n\tlocale: string\n\tt: Translate\n\toperation: 'create' | 'update'\n\treq?: PayloadRequest\n\tpayload?: Payload\n\tformId?: number | string\n\t/**\n\t * The plugin-configured uploads collection slug. The block's stamped `collection` is for the\n\t * client only; the server resolves the slug from plugin config and fails closed without one.\n\t */\n\tuploadSlug?: string\n\t/** Resolved request identity, verified against an upload's `owner` stamp when a file field is captured. */\n\texpectedOwner?: string\n}\n\nexport type RunSubmissionResult = {\n\terrors: SubmissionFieldError[]\n\tvalues: SubmissionValue[]\n\tdescriptors: SubmissionDescriptor[]\n\tconsent: ConsentProofEntry[]\n}\n\n/**\n * Pure submission core, two-pass: first coerce every answered field to its typed kind (so cross-field\n * rules see coerced siblings), then validate each field through `runValidation` (required, intrinsic\n * facet, declarative rules), snapshotting a localized descriptor per answered field. Calc fields are\n * the trust boundary: their client-sent values are never seeded, their values are derived from their\n * expressions over the coerced answers, and those derived values are authoritative everywhere downstream\n * (conditions, validation, storage). Conditions gate the second pass against these effective answers: a\n * field whose `visibleWhen` is false is skipped entirely (never validated, never stored, so a client-sent\n * value for it is ignored), and a visible field whose `validateWhen` is false stores its value but skips\n * validation. A visible calc field stores its derived value and is never validated. Display-only field\n * types (value kind 'none', e.g. message) are skipped in both passes: never validated, never stored, and\n * a client-sent value under their name is dropped. Only `error` severity blocks; warnings are computed\n * but not surfaced server-side (the renderer surfaces them).\n */\nexport const runSubmission = async (input: RunSubmissionInput): Promise<RunSubmissionResult> => {\n\tconst {\n\t\tfields,\n\t\tvalues,\n\t\tregistry,\n\t\truleRegistry,\n\t\tconsentRegistry,\n\t\tlocale,\n\t\tt,\n\t\toperation,\n\t\treq,\n\t\tpayload,\n\t\tformId,\n\t\tuploadSlug,\n\t\texpectedOwner,\n\t} = input\n\tconst incoming = new Map(values.map((entry) => [entry.field, entry.value]))\n\n\tconst coercedAnswers: Record<string, unknown> = {}\n\tconst coercedByName = new Map<string, unknown>()\n\tfor (const instance of fields) {\n\t\tconst definition = registry.get(instance.blockType)\n\t\tconst raw = incoming.get(instance.name)\n\t\t// Never seed a calc field's client value: its value is derived below, so the client cannot influence it (even for a self-referencing expression).\n\t\t// A display-only ('none' kind) field carries no value at all, so a client-sent value under its name is dropped here.\n\t\tif (!definition || definition.value === 'none' || calcExpressionOf(instance)) {\n\t\t\tcontinue\n\t\t}\n\t\t// A consent field's \"not agreed\" state is semantically meaningful: treat a missing value as\n\t\t// `false` so the intrinsic validate can enforce required-agreement (not optional = must be true).\n\t\t// A repeater with no rows is coerced to [] so validate() can check minRows. The empty-guard\n\t\t// below must not skip repeaters: isEmpty([]) is true, but [] still needs to reach validate()\n\t\t// so a minRows > 0 constraint correctly rejects a zero-row submission.\n\t\tconst effectiveRaw =\n\t\t\tinstance.blockType === 'consent' && isEmpty(raw)\n\t\t\t\t? false\n\t\t\t\t: instance.blockType === 'repeater' && isEmpty(raw)\n\t\t\t\t\t? []\n\t\t\t\t\t: raw\n\t\tif (isEmpty(effectiveRaw) && instance.blockType !== 'repeater') {\n\t\t\tcontinue\n\t\t}\n\t\tconst value = coerce(definition.value, effectiveRaw)\n\t\tcoercedAnswers[instance.name] = value\n\t\tcoercedByName.set(instance.name, value)\n\t}\n\n\t// Calc values are authoritative everywhere downstream (conditions, validation, storage), never the client-sent value.\n\tconst effective = computeCalcFields(fields, coercedAnswers)\n\n\tconst errors: SubmissionFieldError[] = []\n\tconst outValues: SubmissionValue[] = []\n\tconst descriptors: SubmissionDescriptor[] = []\n\tconst consentProofs: ConsentProofEntry[] = []\n\tconst now = new Date().toISOString()\n\n\tfor (const instance of fields) {\n\t\tconst definition = registry.get(instance.blockType)\n\t\t// A 'none'-kind (display-only) field is never validated and never stored: no value, no descriptor.\n\t\tif (!definition || definition.value === 'none') {\n\t\t\tcontinue\n\t\t}\n\t\tconst raw = incoming.get(instance.name)\n\t\tconst value = coercedByName.has(instance.name) ? coercedByName.get(instance.name) : raw\n\n\t\tif (!evaluateCondition(instance.visibleWhen, effective)) {\n\t\t\tcontinue\n\t\t}\n\n\t\t// A calc field's value is server-derived and always valid: skip validation and the client value entirely, storing the computed result.\n\t\tif (calcExpressionOf(instance)) {\n\t\t\toutValues.push({ field: instance.name, value: effective[instance.name] })\n\t\t\tdescriptors.push({\n\t\t\t\tfield: instance.name,\n\t\t\t\tlabel: instance.label ?? instance.name,\n\t\t\t\tfieldType: instance.blockType,\n\t\t\t})\n\t\t\tcontinue\n\t\t}\n\n\t\tif (evaluateCondition(instance.validateWhen, effective)) {\n\t\t\tconst { errors: issues } = await runValidation({\n\t\t\t\tfield: instance,\n\t\t\t\tfieldDefinition: definition,\n\t\t\t\tvalue,\n\t\t\t\tfieldType: instance.blockType,\n\t\t\t\truleRegistry,\n\t\t\t\tanswers: effective,\n\t\t\t\tlocale,\n\t\t\t\tt,\n\t\t\t\toperation,\n\t\t\t\tevent: 'submit',\n\t\t\t\tmode: 'server',\n\t\t\t\treq,\n\t\t\t\tpayload,\n\t\t\t\tformId,\n\t\t\t})\n\t\t\tconst blocking = issues.filter((issue) => issue.severity === 'error')\n\t\t\tif (blocking.length > 0) {\n\t\t\t\tfor (const issue of blocking) {\n\t\t\t\t\terrors.push({ path: instance.name, message: issue.message })\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\t// Gate on the field-type definition's value kind, not the blockType literal, so a custom\n\t\t// type registered with value:'file' gets the same server-side capture and enforcement as\n\t\t// the built-in file field (a blockType check would leave it storing the raw client id).\n\t\tif (definition.value === 'file') {\n\t\t\tif (isEmpty(value)) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif (payload) {\n\t\t\t\tif (!uploadSlug) {\n\t\t\t\t\terrors.push({ path: instance.name, message: t(errorKeyFor('missing')) })\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst fileConfig = fileFieldConfigOf(instance)\n\t\t\t\tconst captured = await captureFileRef({\n\t\t\t\t\tpayload,\n\t\t\t\t\tcollectionSlug: uploadSlug,\n\t\t\t\t\tuploadId: value as string | number,\n\t\t\t\t\tconfig: fileConfig,\n\t\t\t\t\treq,\n\t\t\t\t\texpectedOwner,\n\t\t\t\t})\n\t\t\t\tif (!captured.ok) {\n\t\t\t\t\terrors.push({ path: instance.name, message: t(errorKeyFor(captured.code)) })\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\toutValues.push({ field: instance.name, value: captured.ref })\n\t\t\t\tdescriptors.push({\n\t\t\t\t\tfield: instance.name,\n\t\t\t\t\tlabel: instance.label ?? instance.name,\n\t\t\t\t\tfieldType: instance.blockType,\n\t\t\t\t})\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\toutValues.push({ field: instance.name, value })\n\t\t\tdescriptors.push({\n\t\t\t\tfield: instance.name,\n\t\t\t\tlabel: instance.label ?? instance.name,\n\t\t\t\tfieldType: instance.blockType,\n\t\t\t})\n\t\t\tcontinue\n\t\t}\n\n\t\tif (instance.blockType === 'consent' && payload) {\n\t\t\tconst proof = await captureConsent({\n\t\t\t\tfield: instance,\n\t\t\t\tagreed: value === true,\n\t\t\t\tregistry: consentRegistry,\n\t\t\t\tpayload,\n\t\t\t\treq,\n\t\t\t\tlocale,\n\t\t\t\tnow,\n\t\t\t})\n\t\t\tconsentProofs.push({ field: instance.name, ...proof })\n\t\t\tcontinue\n\t\t}\n\n\t\tif (instance.blockType === 'repeater') {\n\t\t\tconst rows = Array.isArray(value) ? (value as Array<Record<string, unknown>>) : []\n\t\t\tconst subFields = Array.isArray(instance.subFields)\n\t\t\t\t? (instance.subFields as FormFieldInstance[])\n\t\t\t\t: []\n\n\t\t\t// Per-row sub-field processing. Validation is gated by the sub-field's visibleWhen and\n\t\t\t// validateWhen against the row's own values; errors carry the path\n\t\t\t// fieldName[rowIndex].subFieldName so the client maps them to the right input. File\n\t\t\t// sub-fields additionally cross the server trust boundary: they are captured\n\t\t\t// unconditionally (a crafted request could carry an id for a conditionally-hidden field),\n\t\t\t// so a stored row never holds a raw, unenforced upload id.\n\t\t\tfor (let rowIndex = 0; rowIndex < rows.length; rowIndex++) {\n\t\t\t\tconst row = rows[rowIndex] ?? {}\n\t\t\t\tfor (const subField of subFields) {\n\t\t\t\t\tconst subDef = registry.get(subField.blockType)\n\t\t\t\t\tif (!subDef) continue\n\t\t\t\t\t// Display-only ('none' kind) sub-fields mirror the top-level skip: never validated,\n\t\t\t\t\t// never captured, and stripped from the stored row below so a client-injected value\n\t\t\t\t\t// under their name cannot ride along.\n\t\t\t\t\tif (subDef.value === 'none') continue\n\t\t\t\t\tconst subPath = `${instance.name}[${rowIndex}].${subField.name}`\n\t\t\t\t\tif (\n\t\t\t\t\t\tevaluateCondition(subField.visibleWhen, row) &&\n\t\t\t\t\t\tevaluateCondition(subField.validateWhen, row)\n\t\t\t\t\t) {\n\t\t\t\t\t\tconst { errors: subErrors } = await runValidation({\n\t\t\t\t\t\t\tfield: subField,\n\t\t\t\t\t\t\tfieldDefinition: subDef,\n\t\t\t\t\t\t\tvalue: row[subField.name],\n\t\t\t\t\t\t\tfieldType: subField.blockType,\n\t\t\t\t\t\t\truleRegistry,\n\t\t\t\t\t\t\tanswers: row,\n\t\t\t\t\t\t\tlocale,\n\t\t\t\t\t\t\tt,\n\t\t\t\t\t\t\toperation,\n\t\t\t\t\t\t\tevent: 'submit',\n\t\t\t\t\t\t\tmode: 'server',\n\t\t\t\t\t\t\treq,\n\t\t\t\t\t\t\tpayload,\n\t\t\t\t\t\t\tformId,\n\t\t\t\t\t\t})\n\t\t\t\t\t\tfor (const issue of subErrors.filter((e) => e.severity === 'error')) {\n\t\t\t\t\t\t\terrors.push({ path: subPath, message: issue.message })\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Mirror the top-level file capture: the client submits only an upload id, so\n\t\t\t\t\t// re-derive filename/mimeType/filesize from the stored doc and enforce\n\t\t\t\t\t// owner/mime/size against the sub-field's config, failing closed on a missing\n\t\t\t\t\t// uploads slug or any capture rejection. The captured FileRef replaces the raw\n\t\t\t\t\t// id in the row. Without a payload (pure unit context) the value stays verbatim,\n\t\t\t\t\t// exactly like the top-level path.\n\t\t\t\t\tif (subDef.value === 'file' && payload) {\n\t\t\t\t\t\tconst subValue = row[subField.name]\n\t\t\t\t\t\tif (isEmpty(subValue)) {\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!uploadSlug) {\n\t\t\t\t\t\t\terrors.push({ path: subPath, message: t(errorKeyFor('missing')) })\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst captured = await captureFileRef({\n\t\t\t\t\t\t\tpayload,\n\t\t\t\t\t\t\tcollectionSlug: uploadSlug,\n\t\t\t\t\t\t\tuploadId: subValue as string | number,\n\t\t\t\t\t\t\tconfig: fileFieldConfigOf(subField),\n\t\t\t\t\t\t\treq,\n\t\t\t\t\t\t\texpectedOwner,\n\t\t\t\t\t\t})\n\t\t\t\t\t\tif (!captured.ok) {\n\t\t\t\t\t\t\terrors.push({ path: subPath, message: t(errorKeyFor(captured.code)) })\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\t\t\t\t\t\trow[subField.name] = captured.ref\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (errors.length > 0) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tconst subFieldDescriptors: SubmissionDescriptor[] = subFields.map((sf) => ({\n\t\t\t\tfield: sf.name,\n\t\t\t\tlabel: sf.label ?? sf.name,\n\t\t\t\tfieldType: sf.blockType,\n\t\t\t\t...((sf.options as unknown) ? { optionLabels: optionLabelsFor(sf) ?? undefined } : {}),\n\t\t\t}))\n\n\t\t\t// Strip display-only sub-fields from the stored rows: like top-level 'none' fields they\n\t\t\t// carry no answer, so a client-injected value under their name must never persist.\n\t\t\tconst displayOnly = new Set(\n\t\t\t\tsubFields.filter((sf) => registry.get(sf.blockType)?.value === 'none').map((sf) => sf.name)\n\t\t\t)\n\t\t\tconst storedRows =\n\t\t\t\tdisplayOnly.size === 0\n\t\t\t\t\t? rows\n\t\t\t\t\t: rows.map((row) =>\n\t\t\t\t\t\t\tObject.fromEntries(Object.entries(row).filter(([key]) => !displayOnly.has(key)))\n\t\t\t\t\t\t)\n\n\t\t\toutValues.push({ field: instance.name, value: storedRows })\n\t\t\tdescriptors.push({\n\t\t\t\tfield: instance.name,\n\t\t\t\tlabel: instance.label ?? instance.name,\n\t\t\t\tfieldType: instance.blockType,\n\t\t\t\t...(subFieldDescriptors.length > 0 ? { subFieldDescriptors } : {}),\n\t\t\t})\n\t\t\tcontinue\n\t\t}\n\n\t\tif (isEmpty(raw)) {\n\t\t\tcontinue\n\t\t}\n\n\t\toutValues.push({ field: instance.name, value })\n\t\tconst optionLabels = optionLabelsFor(instance)\n\t\tdescriptors.push({\n\t\t\tfield: instance.name,\n\t\t\tlabel: instance.label ?? instance.name,\n\t\t\tfieldType: instance.blockType,\n\t\t\t...(optionLabels ? { optionLabels } : {}),\n\t\t})\n\t}\n\n\treturn { errors, values: outValues, descriptors, consent: consentProofs }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"runSubmission.js","names":[],"sources":["../../src/submissions/runSubmission.ts"],"sourcesContent":["import type { Payload, PayloadRequest } from 'payload'\nimport { calcExpressionOf, computeCalcFields } from '../calc/computeCalcFields'\nimport { evaluateCondition } from '../conditions/evaluate'\nimport type { ConsentProof, ConsentSnapshotMode } from '../consent/captureConsent'\nimport { captureConsent } from '../consent/captureConsent'\nimport type { ConsentSourceEntry } from '../consent/types'\nimport { isNamedField } from '../fields/fieldKey'\nimport type { FieldTypeRegistry } from '../fields/registry'\nimport type { Translate } from '../fields/types'\nimport { keys } from '../translations/keys'\nimport { captureFileRef } from '../uploads/captureFileRef'\nimport type { FileFieldConfig, FileRefError } from '../uploads/types'\nimport type { ValidationRuleRegistry } from '../validation/registry'\nimport { runValidation } from '../validation/runValidation'\nimport type {\n\tFormFieldInstance,\n\tSubmissionDescriptor,\n\tSubmissionFieldError,\n\tSubmissionValue,\n\tSubmissionWidth,\n} from './types'\n\nconst SUBMISSION_WIDTHS: ReadonlySet<string> = new Set<SubmissionWidth>([\n\t'full',\n\t'half',\n\t'third',\n\t'twoThirds',\n])\n\n/** The field instance's authored layout width, or undefined if unset/unrecognized (renders full). */\nexport const widthOf = (instance: FormFieldInstance): SubmissionWidth | undefined =>\n\ttypeof instance.width === 'string' && SUBMISSION_WIDTHS.has(instance.width)\n\t\t? (instance.width as SubmissionWidth)\n\t\t: undefined\n\nconst errorKeyFor = (code: FileRefError): string => {\n\tif (code === 'mimeType') {\n\t\treturn keys.validationFileMimeType\n\t}\n\tif (code === 'tooLarge') {\n\t\treturn keys.validationFileTooLarge\n\t}\n\treturn keys.validationFileMissing\n}\n\n/** Normalize the authored `mimeTypes` (a `hasMany` text field) to a `string[]`. */\nconst mimeTypesOf = (raw: unknown): string[] | undefined => {\n\tif (!Array.isArray(raw)) {\n\t\treturn undefined\n\t}\n\tconst out = (raw as unknown[]).filter((entry): entry is string => typeof entry === 'string')\n\treturn out.length > 0 ? out : undefined\n}\n\nconst fileFieldConfigOf = (instance: FormFieldInstance): FileFieldConfig => ({\n\tmimeTypes: mimeTypesOf(instance.mimeTypes),\n\tmaxSize: typeof instance.maxSize === 'number' ? instance.maxSize : undefined,\n})\n\nconst isEmpty = (value: unknown): boolean =>\n\tvalue == null || value === '' || (Array.isArray(value) && value.length === 0)\n\nconst coerce = (kind: string, value: unknown): unknown => {\n\tif (value == null) {\n\t\treturn value\n\t}\n\tif (kind === 'number') {\n\t\tconst next = typeof value === 'number' ? value : Number(value)\n\t\treturn Number.isNaN(next) ? value : next\n\t}\n\tif (kind === 'boolean') {\n\t\t// A genuine boolean from the renderer passes through; a raw client string is parsed strictly so that\n\t\t// \"false\"/\"0\"/\"off\"/\"no\"/\"\" are not silently truthy (this matters for the required-consent check).\n\t\tif (typeof value === 'string') {\n\t\t\tconst normalized = value.trim().toLowerCase()\n\t\t\treturn !(\n\t\t\t\tnormalized === '' ||\n\t\t\t\tnormalized === 'false' ||\n\t\t\t\tnormalized === '0' ||\n\t\t\t\tnormalized === 'off' ||\n\t\t\t\tnormalized === 'no'\n\t\t\t)\n\t\t}\n\t\treturn Boolean(value)\n\t}\n\tif (kind === 'text') {\n\t\treturn typeof value === 'string' ? value : String(value)\n\t}\n\treturn value\n}\n\nconst optionLabelsFor = (instance: FormFieldInstance): Record<string, string> | undefined => {\n\tconst options = instance.options\n\tif (!Array.isArray(options)) {\n\t\treturn undefined\n\t}\n\tconst map: Record<string, string> = {}\n\tfor (const option of options as Array<{ label?: string; value?: string }>) {\n\t\tif (typeof option?.value === 'string') {\n\t\t\tmap[option.value] = option.label ?? option.value\n\t\t}\n\t}\n\treturn Object.keys(map).length > 0 ? map : undefined\n}\n\nexport type ConsentProofEntry = { field: string } & ConsentProof\n\nexport type RunSubmissionInput = {\n\tfields: FormFieldInstance[]\n\tvalues: SubmissionValue[]\n\tregistry: FieldTypeRegistry\n\truleRegistry: ValidationRuleRegistry\n\t/**\n\t * The host's consent sources, resolved once by the caller (which owns the request-scoped\n\t * resolver and how a failure surfaces) and read here to build each consent proof.\n\t */\n\tconsentEntries?: ConsentSourceEntry[]\n\t/** What each consent proof snapshots of the agreed wording (plugin option `consent.snapshot`). */\n\tconsentSnapshot?: ConsentSnapshotMode\n\tlocale: string\n\tt: Translate\n\toperation: 'create' | 'update'\n\treq?: PayloadRequest\n\tpayload?: Payload\n\tformId?: number | string\n\t/**\n\t * The plugin-configured uploads collection slug. The block's stamped `collection` is for the\n\t * client only; the server resolves the slug from plugin config and fails closed without one.\n\t */\n\tuploadSlug?: string\n\t/** Resolved request identity, verified against an upload's `owner` stamp when a file field is captured. */\n\texpectedOwner?: string\n}\n\nexport type RunSubmissionResult = {\n\terrors: SubmissionFieldError[]\n\tvalues: SubmissionValue[]\n\tdescriptors: SubmissionDescriptor[]\n\tconsent: ConsentProofEntry[]\n}\n\n/**\n * Pure submission core, two-pass: first coerce every answered field to its typed kind (so cross-field\n * rules see coerced siblings), then validate each field through `runValidation` (required, intrinsic\n * facet, declarative rules), snapshotting a localized descriptor per answered field. Calc fields are\n * the trust boundary: their client-sent values are never seeded, their values are derived from their\n * expressions over the coerced answers, and those derived values are authoritative everywhere downstream\n * (conditions, validation, storage). Conditions gate the second pass against these effective answers: a\n * field whose `visibleWhen` is false is skipped entirely (never validated, never stored, so a client-sent\n * value for it is ignored), and a visible field whose `validateWhen` is false stores its value but skips\n * validation. A visible calc field stores its derived value and is never validated. Display-only field\n * types (value kind 'none', e.g. message) and nameless (bare) rows are skipped in both passes: never\n * validated, never stored, and a client-sent value under their name is dropped.\n */\nexport const runSubmission = async (input: RunSubmissionInput): Promise<RunSubmissionResult> => {\n\tconst {\n\t\tfields,\n\t\tvalues,\n\t\tregistry,\n\t\truleRegistry,\n\t\tconsentEntries,\n\t\tconsentSnapshot,\n\t\tlocale,\n\t\tt,\n\t\toperation,\n\t\treq,\n\t\tpayload,\n\t\tformId,\n\t\tuploadSlug,\n\t\texpectedOwner,\n\t} = input\n\tconst incoming = new Map(values.map((entry) => [entry.field, entry.value]))\n\n\tconst coercedAnswers: Record<string, unknown> = {}\n\tconst coercedByName = new Map<string, unknown>()\n\tfor (const instance of fields) {\n\t\tconst definition = registry.get(instance.blockType)\n\t\t// Never seed a calc field's client value: its value is derived below, so the client cannot influence it (even for a self-referencing expression).\n\t\t// A display-only ('none' kind) field carries no value at all, so a client-sent value under its name is dropped here.\n\t\t// A nameless (bare) row has no key to read a value under.\n\t\tif (\n\t\t\t!definition ||\n\t\t\tdefinition.value === 'none' ||\n\t\t\tcalcExpressionOf(instance) ||\n\t\t\t!isNamedField(instance)\n\t\t) {\n\t\t\tcontinue\n\t\t}\n\t\tconst raw = incoming.get(instance.name)\n\t\t// A consent field's \"not agreed\" state is semantically meaningful: treat a missing value as\n\t\t// `false` so the intrinsic validate can enforce required-agreement (not optional = must be true).\n\t\t// A repeater with no rows is coerced to [] so validate() can check minRows. The empty-guard\n\t\t// below must not skip repeaters: isEmpty([]) is true, but [] still needs to reach validate()\n\t\t// so a minRows > 0 constraint correctly rejects a zero-row submission.\n\t\tconst effectiveRaw =\n\t\t\tinstance.blockType === 'consent' && isEmpty(raw)\n\t\t\t\t? false\n\t\t\t\t: instance.blockType === 'repeater' && isEmpty(raw)\n\t\t\t\t\t? []\n\t\t\t\t\t: raw\n\t\tif (isEmpty(effectiveRaw) && instance.blockType !== 'repeater') {\n\t\t\tcontinue\n\t\t}\n\t\tconst value = coerce(definition.value, effectiveRaw)\n\t\tcoercedAnswers[instance.name] = value\n\t\tcoercedByName.set(instance.name, value)\n\t}\n\n\t// Calc values are authoritative everywhere downstream (conditions, validation, storage), never the client-sent value.\n\tconst effective = computeCalcFields(fields, coercedAnswers)\n\n\tconst errors: SubmissionFieldError[] = []\n\tconst outValues: SubmissionValue[] = []\n\tconst descriptors: SubmissionDescriptor[] = []\n\tconst consentProofs: ConsentProofEntry[] = []\n\tconst now = new Date().toISOString()\n\n\tfor (const instance of fields) {\n\t\tconst definition = registry.get(instance.blockType)\n\t\t// A 'none'-kind (display-only) field is never validated and never stored: no value, no descriptor.\n\t\t// A nameless (bare) row has no key to store under, so it is skipped the same way.\n\t\tif (!definition || definition.value === 'none' || !isNamedField(instance)) {\n\t\t\tcontinue\n\t\t}\n\t\tconst raw = incoming.get(instance.name)\n\t\tconst value = coercedByName.has(instance.name) ? coercedByName.get(instance.name) : raw\n\n\t\tif (!evaluateCondition(instance.visibleWhen, effective)) {\n\t\t\tcontinue\n\t\t}\n\n\t\t// A calc field's value is server-derived and always valid: skip validation and the client value entirely, storing the computed result.\n\t\tif (calcExpressionOf(instance)) {\n\t\t\toutValues.push({ field: instance.name, value: effective[instance.name] })\n\t\t\tdescriptors.push({\n\t\t\t\tfield: instance.name,\n\t\t\t\tlabel: instance.label ?? instance.name,\n\t\t\t\tfieldType: instance.blockType,\n\t\t\t\t...(widthOf(instance) ? { width: widthOf(instance) } : {}),\n\t\t\t})\n\t\t\tcontinue\n\t\t}\n\n\t\tif (evaluateCondition(instance.validateWhen, effective)) {\n\t\t\tconst { errors: issues } = await runValidation({\n\t\t\t\tfield: instance,\n\t\t\t\tfieldDefinition: definition,\n\t\t\t\tvalue,\n\t\t\t\tfieldType: instance.blockType,\n\t\t\t\truleRegistry,\n\t\t\t\tanswers: effective,\n\t\t\t\tlocale,\n\t\t\t\tt,\n\t\t\t\toperation,\n\t\t\t\tevent: 'submit',\n\t\t\t\tmode: 'server',\n\t\t\t\treq,\n\t\t\t\tpayload,\n\t\t\t\tformId,\n\t\t\t})\n\t\t\tif (issues.length > 0) {\n\t\t\t\tfor (const message of issues) {\n\t\t\t\t\terrors.push({ path: instance.name, message })\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\t// Gate on the field-type definition's value kind, not the blockType literal, so a custom\n\t\t// type registered with value:'file' gets the same server-side capture and enforcement as\n\t\t// the built-in file field (a blockType check would leave it storing the raw client id).\n\t\tif (definition.value === 'file') {\n\t\t\tif (isEmpty(value)) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif (payload) {\n\t\t\t\tif (!uploadSlug) {\n\t\t\t\t\terrors.push({ path: instance.name, message: t(errorKeyFor('missing')) })\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst fileConfig = fileFieldConfigOf(instance)\n\t\t\t\tconst captured = await captureFileRef({\n\t\t\t\t\tpayload,\n\t\t\t\t\tcollectionSlug: uploadSlug,\n\t\t\t\t\tuploadId: value as string | number,\n\t\t\t\t\tconfig: fileConfig,\n\t\t\t\t\treq,\n\t\t\t\t\texpectedOwner,\n\t\t\t\t})\n\t\t\t\tif (!captured.ok) {\n\t\t\t\t\terrors.push({ path: instance.name, message: t(errorKeyFor(captured.code)) })\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\toutValues.push({ field: instance.name, value: captured.ref })\n\t\t\t\tdescriptors.push({\n\t\t\t\t\tfield: instance.name,\n\t\t\t\t\tlabel: instance.label ?? instance.name,\n\t\t\t\t\tfieldType: instance.blockType,\n\t\t\t\t\t...(widthOf(instance) ? { width: widthOf(instance) } : {}),\n\t\t\t\t})\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\toutValues.push({ field: instance.name, value })\n\t\t\tdescriptors.push({\n\t\t\t\tfield: instance.name,\n\t\t\t\tlabel: instance.label ?? instance.name,\n\t\t\t\tfieldType: instance.blockType,\n\t\t\t\t...(widthOf(instance) ? { width: widthOf(instance) } : {}),\n\t\t\t})\n\t\t\tcontinue\n\t\t}\n\n\t\tif (instance.blockType === 'consent' && payload) {\n\t\t\tconst proof = await captureConsent({\n\t\t\t\tfield: instance,\n\t\t\t\tagreed: value === true,\n\t\t\t\tentries: consentEntries ?? [],\n\t\t\t\tpayload,\n\t\t\t\treq,\n\t\t\t\tnow,\n\t\t\t\tsnapshot: consentSnapshot,\n\t\t\t})\n\t\t\tconsentProofs.push({ field: instance.name, ...proof })\n\t\t\tcontinue\n\t\t}\n\n\t\tif (instance.blockType === 'repeater') {\n\t\t\tconst rows = Array.isArray(value) ? (value as Array<Record<string, unknown>>) : []\n\t\t\t// Nameless sub-rows are dropped like top-level ones (bare blocks are excluded from the\n\t\t\t// repeater's subFields config, so any encountered here is stray data).\n\t\t\tconst subFields = (\n\t\t\t\tArray.isArray(instance.subFields) ? (instance.subFields as FormFieldInstance[]) : []\n\t\t\t).filter(isNamedField)\n\n\t\t\t// Per-row sub-field processing. Validation is gated by the sub-field's visibleWhen and\n\t\t\t// validateWhen against the row's own values; errors carry the path\n\t\t\t// fieldName[rowIndex].subFieldName so the client maps them to the right input. File\n\t\t\t// sub-fields additionally cross the server trust boundary: they are captured\n\t\t\t// unconditionally (a crafted request could carry an id for a conditionally-hidden field),\n\t\t\t// so a stored row never holds a raw, unenforced upload id.\n\t\t\tfor (let rowIndex = 0; rowIndex < rows.length; rowIndex++) {\n\t\t\t\tconst row = rows[rowIndex] ?? {}\n\t\t\t\tfor (const subField of subFields) {\n\t\t\t\t\tconst subDef = registry.get(subField.blockType)\n\t\t\t\t\tif (!subDef) continue\n\t\t\t\t\t// Display-only ('none' kind) sub-fields mirror the top-level skip: never validated,\n\t\t\t\t\t// never captured, and stripped from the stored row below so a client-injected value\n\t\t\t\t\t// under their name cannot ride along.\n\t\t\t\t\tif (subDef.value === 'none') continue\n\t\t\t\t\tconst subPath = `${instance.name}[${rowIndex}].${subField.name}`\n\t\t\t\t\tif (\n\t\t\t\t\t\tevaluateCondition(subField.visibleWhen, row) &&\n\t\t\t\t\t\tevaluateCondition(subField.validateWhen, row)\n\t\t\t\t\t) {\n\t\t\t\t\t\tconst { errors: subErrors } = await runValidation({\n\t\t\t\t\t\t\tfield: subField,\n\t\t\t\t\t\t\tfieldDefinition: subDef,\n\t\t\t\t\t\t\tvalue: row[subField.name],\n\t\t\t\t\t\t\tfieldType: subField.blockType,\n\t\t\t\t\t\t\truleRegistry,\n\t\t\t\t\t\t\tanswers: row,\n\t\t\t\t\t\t\tlocale,\n\t\t\t\t\t\t\tt,\n\t\t\t\t\t\t\toperation,\n\t\t\t\t\t\t\tevent: 'submit',\n\t\t\t\t\t\t\tmode: 'server',\n\t\t\t\t\t\t\treq,\n\t\t\t\t\t\t\tpayload,\n\t\t\t\t\t\t\tformId,\n\t\t\t\t\t\t})\n\t\t\t\t\t\tfor (const message of subErrors) {\n\t\t\t\t\t\t\terrors.push({ path: subPath, message })\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Mirror the top-level file capture: the client submits only an upload id, so\n\t\t\t\t\t// re-derive filename/mimeType/filesize from the stored doc and enforce\n\t\t\t\t\t// owner/mime/size against the sub-field's config, failing closed on a missing\n\t\t\t\t\t// uploads slug or any capture rejection. The captured FileRef replaces the raw\n\t\t\t\t\t// id in the row. Without a payload (pure unit context) the value stays verbatim,\n\t\t\t\t\t// exactly like the top-level path.\n\t\t\t\t\tif (subDef.value === 'file' && payload) {\n\t\t\t\t\t\tconst subValue = row[subField.name]\n\t\t\t\t\t\tif (isEmpty(subValue)) {\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!uploadSlug) {\n\t\t\t\t\t\t\terrors.push({ path: subPath, message: t(errorKeyFor('missing')) })\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst captured = await captureFileRef({\n\t\t\t\t\t\t\tpayload,\n\t\t\t\t\t\t\tcollectionSlug: uploadSlug,\n\t\t\t\t\t\t\tuploadId: subValue as string | number,\n\t\t\t\t\t\t\tconfig: fileFieldConfigOf(subField),\n\t\t\t\t\t\t\treq,\n\t\t\t\t\t\t\texpectedOwner,\n\t\t\t\t\t\t})\n\t\t\t\t\t\tif (!captured.ok) {\n\t\t\t\t\t\t\terrors.push({ path: subPath, message: t(errorKeyFor(captured.code)) })\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\t\t\t\t\t\trow[subField.name] = captured.ref\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (errors.length > 0) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tconst subFieldDescriptors: SubmissionDescriptor[] = subFields.map((sf) => ({\n\t\t\t\tfield: sf.name,\n\t\t\t\tlabel: sf.label ?? sf.name,\n\t\t\t\tfieldType: sf.blockType,\n\t\t\t\t...((sf.options as unknown) ? { optionLabels: optionLabelsFor(sf) ?? undefined } : {}),\n\t\t\t}))\n\n\t\t\t// Strip display-only sub-fields from the stored rows: like top-level 'none' fields they\n\t\t\t// carry no answer, so a client-injected value under their name must never persist.\n\t\t\tconst displayOnly = new Set(\n\t\t\t\tsubFields.filter((sf) => registry.get(sf.blockType)?.value === 'none').map((sf) => sf.name)\n\t\t\t)\n\t\t\tconst storedRows =\n\t\t\t\tdisplayOnly.size === 0\n\t\t\t\t\t? rows\n\t\t\t\t\t: rows.map((row) =>\n\t\t\t\t\t\t\tObject.fromEntries(Object.entries(row).filter(([key]) => !displayOnly.has(key)))\n\t\t\t\t\t\t)\n\n\t\t\toutValues.push({ field: instance.name, value: storedRows })\n\t\t\tdescriptors.push({\n\t\t\t\tfield: instance.name,\n\t\t\t\tlabel: instance.label ?? instance.name,\n\t\t\t\tfieldType: instance.blockType,\n\t\t\t\t...(widthOf(instance) ? { width: widthOf(instance) } : {}),\n\t\t\t\t...(subFieldDescriptors.length > 0 ? { subFieldDescriptors } : {}),\n\t\t\t})\n\t\t\tcontinue\n\t\t}\n\n\t\tif (isEmpty(raw)) {\n\t\t\tcontinue\n\t\t}\n\n\t\toutValues.push({ field: instance.name, value })\n\t\tconst optionLabels = optionLabelsFor(instance)\n\t\tdescriptors.push({\n\t\t\tfield: instance.name,\n\t\t\tlabel: instance.label ?? instance.name,\n\t\t\tfieldType: instance.blockType,\n\t\t\t...(widthOf(instance) ? { width: widthOf(instance) } : {}),\n\t\t\t...(optionLabels ? { optionLabels } : {}),\n\t\t})\n\t}\n\n\treturn { errors, values: outValues, descriptors, consent: consentProofs }\n}\n"],"mappings":"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"}