@verbb/formie-browser 1.0.13 → 1.0.15

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 (389) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/dist/chunks/{address-country-Rx6GQTND.js → address-country-BcEQKw0T.js} +11 -5
  3. package/dist/chunks/{address-finder-k7_BXaRe.js → address-finder-BWGINCSA.js} +3 -3
  4. package/dist/chunks/address-state-DI3ndhMU.js +365 -0
  5. package/dist/chunks/{api-BUb6P-xu.js → api-BK9b340y.js} +93 -63
  6. package/dist/chunks/{api-DqpfkZWL.js → api-Dxl_CKw-.js} +202 -193
  7. package/dist/chunks/{api-sPqGbOww.js → api-ghNr2uxX.js} +15 -9
  8. package/dist/chunks/{async-nPFRNQ06.js → async-2GdXNFCE.js} +18 -1
  9. package/dist/chunks/{bpoint-Dlq34XH1.js → bpoint-BwtuyN_O.js} +3 -3
  10. package/dist/chunks/calculations-YEoVCG2q.js +310 -0
  11. package/dist/chunks/{captcha-eu-CGm8Lbrj.js → captcha-eu-DWLoQFKB.js} +6 -5
  12. package/dist/chunks/{checkbox-radio-BY2aTCOG.js → checkbox-radio-gsm8QPJg.js} +74 -75
  13. package/dist/chunks/{combobox-C0EuExSI.js → combobox-Ba08_cHL.js} +340 -328
  14. package/dist/chunks/conditions-Ceeg6ReZ.js +467 -0
  15. package/dist/chunks/country-from-ip-DDj_mFki.js +29 -0
  16. package/dist/chunks/csrf-DxHg_ZYt.js +61 -0
  17. package/dist/chunks/{custom-google-maps-BsaSirEZ.js → custom-google-maps-C4l2S3GO.js} +9 -3
  18. package/dist/chunks/{custom-link-CJ1-FjEM.js → custom-link-CLazgKYH.js} +8 -2
  19. package/dist/chunks/{custom-maps-DYW_pBid.js → custom-maps-DqcAlD0v.js} +10 -4
  20. package/dist/chunks/{date-picker-F9BUBDSW.js → date-picker-DaPvMrop.js} +467 -443
  21. package/dist/chunks/{dist-D6i-VNgM.js → dist-ZLeW0zZ3.js} +1281 -453
  22. package/dist/chunks/{eway-D9_m8ooj.js → eway-uw0DzU-L.js} +5 -5
  23. package/dist/chunks/field-references.resolver-Ca8MguFv.js +104 -0
  24. package/dist/chunks/{file-upload-rqfZNqlH.js → file-upload-B8_mH012.js} +119 -99
  25. package/dist/chunks/friendly-captcha-v1-CVXaXgDO.js +34 -0
  26. package/dist/chunks/{friendly-captcha-v2-CLSAbkqx.js → friendly-captcha-v2-DkeIVTKI.js} +6 -5
  27. package/dist/chunks/{friendly-challenge-8uPatWqk.js → friendly-challenge-DPG9MJb1.js} +111 -102
  28. package/dist/chunks/{go-cardless-DAT3ZaQf.js → go-cardless-c4wLJdOt.js} +2 -2
  29. package/dist/chunks/google-address-JHYvjwgN.js +168 -0
  30. package/dist/chunks/{hcaptcha-CGLAmgjO.js → hcaptcha-Dt3ELLlP.js} +4 -4
  31. package/dist/chunks/{hidden-D7_Ch-QN.js → hidden-BZhXnNPe.js} +8 -2
  32. package/dist/chunks/http-C2QdHuWO.js +27 -0
  33. package/dist/chunks/{leaflet-src-j-lHNmhR.js → leaflet-src-DE6rv6M-.js} +42 -46
  34. package/dist/chunks/{loqate-CJPzBmSm.js → loqate-m51iPyO1.js} +3 -3
  35. package/dist/chunks/{mollie-Bibhl67p.js → mollie-Bn0PX173.js} +2 -2
  36. package/dist/chunks/{moneris-H2wSqk9h.js → moneris-BRbUvI4t.js} +3 -3
  37. package/dist/chunks/opayo-BwWdInEP.js +188 -0
  38. package/dist/chunks/{paddle-DkvIxQdG.js → paddle-CympHVvd.js} +4 -4
  39. package/dist/chunks/{password-validation-D06uH9va.js → password-validation-C8_uO_c_.js} +18 -12
  40. package/dist/chunks/{paypal-CQpAF7Ua.js → paypal-h75h6wae.js} +8 -6
  41. package/dist/chunks/{payway-CwDkC7YZ.js → payway-C9rHTCC_.js} +4 -4
  42. package/dist/chunks/{phone-country-D3ayr60L.js → phone-country-B8fv-L5_.js} +80 -63
  43. package/dist/chunks/{place-kit-BGHklIZ-.js → place-kit-BnZGQ-L1.js} +11 -11
  44. package/dist/chunks/{placekit-autocomplete.esm-DWVabQlq.js → placekit-autocomplete.esm-CZZERYur.js} +11 -15
  45. package/dist/chunks/{recaptcha-enterprise-XPId5-bS.js → recaptcha-enterprise-CUs8BO6V.js} +4 -4
  46. package/dist/chunks/{recaptcha-shared-CLYJvojk.js → recaptcha-shared-DTbTw-MF.js} +2 -2
  47. package/dist/chunks/{recaptcha-v2-checkbox-Cy-0PEPc.js → recaptcha-v2-checkbox-P1McW4Pv.js} +4 -4
  48. package/dist/chunks/{recaptcha-v2-invisible-BwRH540O.js → recaptcha-v2-invisible-FGDqozSP.js} +4 -4
  49. package/dist/chunks/{recaptcha-v3-No4Ykrhk.js → recaptcha-v3-CflUHeZD.js} +4 -4
  50. package/dist/chunks/{repeater-BVnPUqTj.js → repeater-CyhDbozO.js} +60 -40
  51. package/dist/chunks/request-profile-DhwkeCpS.js +10 -0
  52. package/dist/chunks/rich-text-uV4o_pGk.js +361 -0
  53. package/dist/chunks/{chunk-3b4jIN3o.js → rolldown-runtime-DtPi1Y-2.js} +2 -2
  54. package/dist/chunks/{scripts-CbQ7agX3.js → scripts-DrccjrFv.js} +1 -1
  55. package/dist/chunks/{sdk-BhHAYgga.js → sdk-lkwSvlpM.js} +282 -234
  56. package/dist/chunks/{shared-Bx9s0i0P.js → shared-OKhSay59.js} +27 -21
  57. package/dist/chunks/{signature-IOhuicje.js → signature-7cldFbqj.js} +138 -112
  58. package/dist/chunks/skip-CEW89ExY.js +7 -0
  59. package/dist/chunks/{snaptcha-DKx98oon.js → snaptcha-C3QLYxFT.js} +2 -2
  60. package/dist/chunks/{square-DwdcOI1G.js → square-C1z5DPVw.js} +9 -7
  61. package/dist/chunks/{stripe-DaoG2FT1.js → stripe-Dmkdkq1y.js} +11 -12
  62. package/dist/chunks/{summary-Dks0gXS3.js → summary-Bn-g5SDx.js} +48 -46
  63. package/dist/chunks/{survey-likert-DkE6bR7B.js → survey-likert-fk1hUPff.js} +7 -1
  64. package/dist/chunks/{survey-rank-DN6x4IZM.js → survey-rank-BsLGl2LX.js} +37 -25
  65. package/dist/chunks/{survey-rating-BnsNL9U5.js → survey-rating-DVS6e6fM.js} +17 -5
  66. package/dist/chunks/{table-CAjCJHrL.js → table-j7MlLLCc.js} +22 -16
  67. package/dist/chunks/{text-limit-BGaY0jhI.js → text-limit-LGMPhFuC.js} +40 -34
  68. package/dist/chunks/{theme-classes-Tv7q7ToE.js → theme-classes-DAQuEqdP.js} +1 -1
  69. package/dist/chunks/{turnstile-DJakPzQD.js → turnstile-ptihQfLl.js} +4 -4
  70. package/dist/chunks/{upload-manager-W-QDgxKD.js → upload-manager-BW7l-BhF.js} +459 -387
  71. package/dist/chunks/{utils-Vqp8i_RM.js → utils-DpUBPadZ.js} +20 -14
  72. package/dist/css/formie-base.css +104 -1
  73. package/dist/css/theme/_messages.css +2 -0
  74. package/dist/css/theme/_tokens.css +31 -25
  75. package/dist/css/theme/forms/_form.css +5 -1
  76. package/dist/index.d.ts +5 -4
  77. package/dist/index.d.ts.map +1 -1
  78. package/dist/index.js +1779 -1415
  79. package/dist/js/contracts/client.d.ts +5 -3
  80. package/dist/js/contracts/client.d.ts.map +1 -1
  81. package/dist/js/contracts/common.d.ts +2 -2
  82. package/dist/js/contracts/common.d.ts.map +1 -1
  83. package/dist/js/contracts/modules.d.ts +37 -12
  84. package/dist/js/contracts/modules.d.ts.map +1 -1
  85. package/dist/js/contracts/schema.d.ts +20 -38
  86. package/dist/js/contracts/schema.d.ts.map +1 -1
  87. package/dist/js/contracts/theme.d.ts +4 -1
  88. package/dist/js/contracts/theme.d.ts.map +1 -1
  89. package/dist/js/core/client-rendered-modules.d.ts +17 -0
  90. package/dist/js/core/client-rendered-modules.d.ts.map +1 -0
  91. package/dist/js/core/create-formie-client.d.ts.map +1 -1
  92. package/dist/js/core/field-error-aria.d.ts +23 -0
  93. package/dist/js/core/field-error-aria.d.ts.map +1 -0
  94. package/dist/js/core/hydrate-modules.d.ts +10 -8
  95. package/dist/js/core/hydrate-modules.d.ts.map +1 -1
  96. package/dist/js/core/submit-result-state.d.ts.map +1 -1
  97. package/dist/js/core/submit-result-ui.d.ts +3 -1
  98. package/dist/js/core/submit-result-ui.d.ts.map +1 -1
  99. package/dist/js/core/validation-focus.d.ts.map +1 -1
  100. package/dist/js/modules/address/address-finder.d.ts +1 -1
  101. package/dist/js/modules/address/address-finder.d.ts.map +1 -1
  102. package/dist/js/modules/address/factories.d.ts +3 -3
  103. package/dist/js/modules/address/factories.d.ts.map +1 -1
  104. package/dist/js/modules/address/google-address.d.ts +12 -1
  105. package/dist/js/modules/address/google-address.d.ts.map +1 -1
  106. package/dist/js/modules/address/index.d.ts +2 -2
  107. package/dist/js/modules/address/index.d.ts.map +1 -1
  108. package/dist/js/modules/address/loqate.d.ts +1 -1
  109. package/dist/js/modules/address/loqate.d.ts.map +1 -1
  110. package/dist/js/modules/address/place-kit.d.ts +1 -1
  111. package/dist/js/modules/address/place-kit.d.ts.map +1 -1
  112. package/dist/js/modules/captchas/captcha-eu.d.ts +1 -1
  113. package/dist/js/modules/captchas/captcha-eu.d.ts.map +1 -1
  114. package/dist/js/modules/captchas/factories.d.ts +11 -11
  115. package/dist/js/modules/captchas/factories.d.ts.map +1 -1
  116. package/dist/js/modules/captchas/friendly-captcha-v1.d.ts +1 -1
  117. package/dist/js/modules/captchas/friendly-captcha-v1.d.ts.map +1 -1
  118. package/dist/js/modules/captchas/friendly-captcha-v2.d.ts +1 -1
  119. package/dist/js/modules/captchas/friendly-captcha-v2.d.ts.map +1 -1
  120. package/dist/js/modules/captchas/hcaptcha.d.ts +1 -1
  121. package/dist/js/modules/captchas/hcaptcha.d.ts.map +1 -1
  122. package/dist/js/modules/captchas/index.d.ts +2 -2
  123. package/dist/js/modules/captchas/index.d.ts.map +1 -1
  124. package/dist/js/modules/captchas/recaptcha-enterprise.d.ts +1 -1
  125. package/dist/js/modules/captchas/recaptcha-enterprise.d.ts.map +1 -1
  126. package/dist/js/modules/captchas/recaptcha-v2-checkbox.d.ts +1 -1
  127. package/dist/js/modules/captchas/recaptcha-v2-checkbox.d.ts.map +1 -1
  128. package/dist/js/modules/captchas/recaptcha-v2-invisible.d.ts +1 -1
  129. package/dist/js/modules/captchas/recaptcha-v2-invisible.d.ts.map +1 -1
  130. package/dist/js/modules/captchas/recaptcha-v3.d.ts +1 -1
  131. package/dist/js/modules/captchas/recaptcha-v3.d.ts.map +1 -1
  132. package/dist/js/modules/captchas/snaptcha.d.ts +1 -1
  133. package/dist/js/modules/captchas/snaptcha.d.ts.map +1 -1
  134. package/dist/js/modules/captchas/turnstile.d.ts +1 -1
  135. package/dist/js/modules/captchas/turnstile.d.ts.map +1 -1
  136. package/dist/js/modules/fields/address-country.d.ts +2 -2
  137. package/dist/js/modules/fields/address-country.d.ts.map +1 -1
  138. package/dist/js/modules/fields/address-state.d.ts +2 -2
  139. package/dist/js/modules/fields/address-state.d.ts.map +1 -1
  140. package/dist/js/modules/fields/calculations.d.ts +2 -2
  141. package/dist/js/modules/fields/calculations.d.ts.map +1 -1
  142. package/dist/js/modules/fields/checkbox-radio.d.ts +2 -2
  143. package/dist/js/modules/fields/checkbox-radio.d.ts.map +1 -1
  144. package/dist/js/modules/fields/combobox.d.ts +2 -2
  145. package/dist/js/modules/fields/combobox.d.ts.map +1 -1
  146. package/dist/js/modules/fields/conditions/config.d.ts.map +1 -1
  147. package/dist/js/modules/fields/conditions/effects.d.ts +1 -0
  148. package/dist/js/modules/fields/conditions/effects.d.ts.map +1 -1
  149. package/dist/js/modules/fields/conditions/evaluator.d.ts +4 -1
  150. package/dist/js/modules/fields/conditions/evaluator.d.ts.map +1 -1
  151. package/dist/js/modules/fields/conditions/references.d.ts.map +1 -1
  152. package/dist/js/modules/fields/conditions/submission-context.d.ts +15 -0
  153. package/dist/js/modules/fields/conditions/submission-context.d.ts.map +1 -0
  154. package/dist/js/modules/fields/conditions/types.d.ts +3 -1
  155. package/dist/js/modules/fields/conditions/types.d.ts.map +1 -1
  156. package/dist/js/modules/fields/conditions/values.d.ts +1 -1
  157. package/dist/js/modules/fields/conditions/values.d.ts.map +1 -1
  158. package/dist/js/modules/fields/conditions.d.ts +2 -2
  159. package/dist/js/modules/fields/conditions.d.ts.map +1 -1
  160. package/dist/js/modules/fields/custom-google-maps.d.ts +2 -2
  161. package/dist/js/modules/fields/custom-google-maps.d.ts.map +1 -1
  162. package/dist/js/modules/fields/custom-link.d.ts +2 -2
  163. package/dist/js/modules/fields/custom-link.d.ts.map +1 -1
  164. package/dist/js/modules/fields/custom-maps.d.ts +2 -2
  165. package/dist/js/modules/fields/custom-maps.d.ts.map +1 -1
  166. package/dist/js/modules/fields/date-picker.d.ts +2 -2
  167. package/dist/js/modules/fields/date-picker.d.ts.map +1 -1
  168. package/dist/js/modules/fields/file-upload.d.ts +2 -2
  169. package/dist/js/modules/fields/file-upload.d.ts.map +1 -1
  170. package/dist/js/modules/fields/hidden.d.ts +2 -2
  171. package/dist/js/modules/fields/hidden.d.ts.map +1 -1
  172. package/dist/js/modules/fields/index.d.ts +2 -2
  173. package/dist/js/modules/fields/index.d.ts.map +1 -1
  174. package/dist/js/modules/fields/password-validation.d.ts +2 -2
  175. package/dist/js/modules/fields/password-validation.d.ts.map +1 -1
  176. package/dist/js/modules/fields/phone-country.d.ts +2 -2
  177. package/dist/js/modules/fields/phone-country.d.ts.map +1 -1
  178. package/dist/js/modules/fields/repeater.d.ts +2 -2
  179. package/dist/js/modules/fields/repeater.d.ts.map +1 -1
  180. package/dist/js/modules/fields/rich-text.d.ts +2 -2
  181. package/dist/js/modules/fields/rich-text.d.ts.map +1 -1
  182. package/dist/js/modules/fields/shared.d.ts +1 -0
  183. package/dist/js/modules/fields/shared.d.ts.map +1 -1
  184. package/dist/js/modules/fields/signature.d.ts +2 -2
  185. package/dist/js/modules/fields/signature.d.ts.map +1 -1
  186. package/dist/js/modules/fields/summary.d.ts +2 -2
  187. package/dist/js/modules/fields/summary.d.ts.map +1 -1
  188. package/dist/js/modules/fields/survey-likert.d.ts +2 -2
  189. package/dist/js/modules/fields/survey-likert.d.ts.map +1 -1
  190. package/dist/js/modules/fields/survey-rank.d.ts +2 -2
  191. package/dist/js/modules/fields/survey-rank.d.ts.map +1 -1
  192. package/dist/js/modules/fields/survey-rating.d.ts +2 -2
  193. package/dist/js/modules/fields/survey-rating.d.ts.map +1 -1
  194. package/dist/js/modules/fields/table.d.ts +2 -2
  195. package/dist/js/modules/fields/table.d.ts.map +1 -1
  196. package/dist/js/modules/fields/text-limit.d.ts +2 -2
  197. package/dist/js/modules/fields/text-limit.d.ts.map +1 -1
  198. package/dist/js/modules/fields/upload-manager.d.ts +2 -2
  199. package/dist/js/modules/fields/upload-manager.d.ts.map +1 -1
  200. package/dist/js/modules/loader.d.ts +10 -4
  201. package/dist/js/modules/loader.d.ts.map +1 -1
  202. package/dist/js/modules/payments/bpoint.d.ts +1 -1
  203. package/dist/js/modules/payments/bpoint.d.ts.map +1 -1
  204. package/dist/js/modules/payments/eway.d.ts +1 -1
  205. package/dist/js/modules/payments/eway.d.ts.map +1 -1
  206. package/dist/js/modules/payments/factories.d.ts +7 -7
  207. package/dist/js/modules/payments/factories.d.ts.map +1 -1
  208. package/dist/js/modules/payments/go-cardless.d.ts +1 -1
  209. package/dist/js/modules/payments/go-cardless.d.ts.map +1 -1
  210. package/dist/js/modules/payments/index.d.ts +2 -2
  211. package/dist/js/modules/payments/index.d.ts.map +1 -1
  212. package/dist/js/modules/payments/mollie.d.ts +1 -1
  213. package/dist/js/modules/payments/mollie.d.ts.map +1 -1
  214. package/dist/js/modules/payments/moneris.d.ts +1 -1
  215. package/dist/js/modules/payments/moneris.d.ts.map +1 -1
  216. package/dist/js/modules/payments/opayo.d.ts +1 -1
  217. package/dist/js/modules/payments/opayo.d.ts.map +1 -1
  218. package/dist/js/modules/payments/paddle.d.ts +1 -1
  219. package/dist/js/modules/payments/paddle.d.ts.map +1 -1
  220. package/dist/js/modules/payments/paypal.d.ts +1 -1
  221. package/dist/js/modules/payments/paypal.d.ts.map +1 -1
  222. package/dist/js/modules/payments/payway.d.ts +1 -1
  223. package/dist/js/modules/payments/payway.d.ts.map +1 -1
  224. package/dist/js/modules/payments/square.d.ts +1 -1
  225. package/dist/js/modules/payments/square.d.ts.map +1 -1
  226. package/dist/js/modules/payments/stripe.d.ts +1 -1
  227. package/dist/js/modules/payments/stripe.d.ts.map +1 -1
  228. package/dist/js/modules/payments/utils.d.ts +6 -0
  229. package/dist/js/modules/payments/utils.d.ts.map +1 -1
  230. package/dist/js/modules/registry.d.ts +6 -4
  231. package/dist/js/modules/registry.d.ts.map +1 -1
  232. package/dist/js/submit/pipeline.d.ts.map +1 -1
  233. package/dist/js/theme/browser-theme-state.generated.d.ts +24 -0
  234. package/dist/js/theme/browser-theme-state.generated.d.ts.map +1 -0
  235. package/dist/js/theme/theme-classes.d.ts +3 -3
  236. package/dist/js/theme/theme-classes.d.ts.map +1 -1
  237. package/dist/js/transport/forms-api.d.ts +5 -3
  238. package/dist/js/transport/forms-api.d.ts.map +1 -1
  239. package/dist/js/utils/async.d.ts +1 -0
  240. package/dist/js/utils/async.d.ts.map +1 -1
  241. package/dist/js/utils/country-from-ip.d.ts +2 -2
  242. package/dist/js/utils/country-from-ip.d.ts.map +1 -1
  243. package/dist/js/utils/csrf.d.ts +17 -0
  244. package/dist/js/utils/csrf.d.ts.map +1 -0
  245. package/dist/js/utils/field-references.parser.d.ts +1 -0
  246. package/dist/js/utils/field-references.parser.d.ts.map +1 -1
  247. package/dist/js/utils/field-references.resolver.d.ts.map +1 -1
  248. package/dist/js/utils/field-references.types.d.ts +1 -0
  249. package/dist/js/utils/field-references.types.d.ts.map +1 -1
  250. package/dist/js/utils/http.d.ts +3 -1
  251. package/dist/js/utils/http.d.ts.map +1 -1
  252. package/dist/js/utils/request-profile.d.ts +4 -0
  253. package/dist/js/utils/request-profile.d.ts.map +1 -0
  254. package/dist/js/utils/unload-warning.d.ts.map +1 -1
  255. package/dist/js/validation/rules/email.d.ts.map +1 -1
  256. package/dist/js/validation/rules/match.d.ts.map +1 -1
  257. package/dist/js/validation/rules/number.d.ts.map +1 -1
  258. package/dist/js/validation/rules/required.d.ts.map +1 -1
  259. package/dist/js/validation/rules/shared.d.ts.map +1 -1
  260. package/dist/js/validation/rules/url.d.ts.map +1 -1
  261. package/dist/js/validation/skip.d.ts +7 -0
  262. package/dist/js/validation/skip.d.ts.map +1 -0
  263. package/dist/js/validation/submit-readiness.d.ts.map +1 -1
  264. package/dist/js/validation/validator.d.ts.map +1 -1
  265. package/package.json +43 -12
  266. package/src/css/formie-base.css +104 -1
  267. package/src/css/theme/_messages.css +2 -0
  268. package/src/css/theme/_tokens.css +31 -25
  269. package/src/css/theme/forms/_form.css +5 -1
  270. package/src/index.ts +13 -8
  271. package/src/js/contracts/client.ts +5 -3
  272. package/src/js/contracts/common.ts +5 -6
  273. package/src/js/contracts/modules.ts +41 -12
  274. package/src/js/contracts/schema.ts +21 -43
  275. package/src/js/contracts/theme.ts +6 -1
  276. package/src/js/core/client-rendered-modules.ts +69 -0
  277. package/src/js/core/create-formie-client.ts +132 -86
  278. package/src/js/core/field-error-aria.ts +93 -0
  279. package/src/js/core/hydrate-modules.ts +54 -29
  280. package/src/js/core/submit-result-state.ts +51 -45
  281. package/src/js/core/submit-result-ui.ts +25 -68
  282. package/src/js/core/validation-focus.ts +20 -20
  283. package/src/js/modules/address/address-finder.ts +1 -1
  284. package/src/js/modules/address/factories.ts +15 -13
  285. package/src/js/modules/address/google-address.ts +102 -40
  286. package/src/js/modules/address/index.ts +2 -2
  287. package/src/js/modules/address/loqate.ts +1 -1
  288. package/src/js/modules/address/place-kit.ts +14 -8
  289. package/src/js/modules/captchas/captcha-eu.ts +2 -2
  290. package/src/js/modules/captchas/factories.ts +66 -42
  291. package/src/js/modules/captchas/friendly-captcha-v1.ts +12 -2
  292. package/src/js/modules/captchas/friendly-captcha-v2.ts +4 -2
  293. package/src/js/modules/captchas/hcaptcha.ts +5 -5
  294. package/src/js/modules/captchas/index.ts +2 -2
  295. package/src/js/modules/captchas/recaptcha-enterprise.ts +2 -2
  296. package/src/js/modules/captchas/recaptcha-v2-checkbox.ts +3 -3
  297. package/src/js/modules/captchas/recaptcha-v2-invisible.ts +2 -2
  298. package/src/js/modules/captchas/recaptcha-v3.ts +2 -2
  299. package/src/js/modules/captchas/snaptcha.ts +1 -1
  300. package/src/js/modules/captchas/turnstile.ts +3 -3
  301. package/src/js/modules/fields/address-country.ts +11 -9
  302. package/src/js/modules/fields/address-state.ts +94 -35
  303. package/src/js/modules/fields/calculations.ts +5 -3
  304. package/src/js/modules/fields/checkbox-radio.ts +24 -42
  305. package/src/js/modules/fields/combobox.ts +28 -9
  306. package/src/js/modules/fields/conditions/config.ts +17 -20
  307. package/src/js/modules/fields/conditions/effects.ts +25 -29
  308. package/src/js/modules/fields/conditions/evaluator.ts +21 -29
  309. package/src/js/modules/fields/conditions/references.ts +16 -5
  310. package/src/js/modules/fields/conditions/submission-context.ts +80 -0
  311. package/src/js/modules/fields/conditions/types.ts +3 -1
  312. package/src/js/modules/fields/conditions/values.ts +31 -6
  313. package/src/js/modules/fields/conditions.ts +65 -18
  314. package/src/js/modules/fields/custom-google-maps.ts +5 -3
  315. package/src/js/modules/fields/custom-link.ts +5 -3
  316. package/src/js/modules/fields/custom-maps.ts +5 -3
  317. package/src/js/modules/fields/date-picker.ts +40 -7
  318. package/src/js/modules/fields/file-upload.ts +62 -23
  319. package/src/js/modules/fields/hidden.ts +5 -3
  320. package/src/js/modules/fields/index.ts +2 -2
  321. package/src/js/modules/fields/password-validation.ts +5 -3
  322. package/src/js/modules/fields/phone-country.ts +35 -8
  323. package/src/js/modules/fields/repeater.ts +60 -7
  324. package/src/js/modules/fields/rich-text.ts +20 -4
  325. package/src/js/modules/fields/shared.ts +13 -0
  326. package/src/js/modules/fields/signature.ts +24 -4
  327. package/src/js/modules/fields/summary.ts +8 -20
  328. package/src/js/modules/fields/survey-likert.ts +5 -3
  329. package/src/js/modules/fields/survey-rank.ts +21 -3
  330. package/src/js/modules/fields/survey-rating.ts +17 -3
  331. package/src/js/modules/fields/table.ts +5 -3
  332. package/src/js/modules/fields/text-limit.ts +5 -3
  333. package/src/js/modules/fields/upload-manager.ts +244 -67
  334. package/src/js/modules/loader.ts +345 -281
  335. package/src/js/modules/payments/bpoint.ts +2 -2
  336. package/src/js/modules/payments/eway.ts +2 -2
  337. package/src/js/modules/payments/factories.ts +53 -52
  338. package/src/js/modules/payments/go-cardless.ts +1 -1
  339. package/src/js/modules/payments/index.ts +2 -2
  340. package/src/js/modules/payments/mollie.ts +1 -1
  341. package/src/js/modules/payments/moneris.ts +2 -2
  342. package/src/js/modules/payments/opayo.ts +21 -8
  343. package/src/js/modules/payments/paddle.ts +10 -6
  344. package/src/js/modules/payments/payment.ts +22 -18
  345. package/src/js/modules/payments/paypal.ts +1 -1
  346. package/src/js/modules/payments/payway.ts +2 -2
  347. package/src/js/modules/payments/square.ts +2 -2
  348. package/src/js/modules/payments/stripe.ts +5 -5
  349. package/src/js/modules/payments/utils.ts +14 -0
  350. package/src/js/modules/registry.ts +19 -11
  351. package/src/js/submit/pipeline.ts +10 -11
  352. package/src/js/theme/browser-theme-state.generated.ts +25 -0
  353. package/src/js/theme/theme-classes.ts +3 -3
  354. package/src/js/transport/forms-api.ts +66 -67
  355. package/src/js/utils/async.ts +34 -0
  356. package/src/js/utils/country-from-ip.ts +14 -9
  357. package/src/js/utils/csrf.ts +136 -0
  358. package/src/js/utils/field-references.parser.ts +13 -113
  359. package/src/js/utils/field-references.resolver.ts +27 -64
  360. package/src/js/utils/field-references.row-scope.ts +1 -1
  361. package/src/js/utils/field-references.types.ts +1 -0
  362. package/src/js/utils/http.ts +5 -5
  363. package/src/js/utils/request-profile.ts +10 -0
  364. package/src/js/utils/unload-warning.ts +12 -4
  365. package/src/js/validation/rules/email.ts +3 -5
  366. package/src/js/validation/rules/match.ts +2 -1
  367. package/src/js/validation/rules/minmax.ts +4 -43
  368. package/src/js/validation/rules/number.ts +3 -47
  369. package/src/js/validation/rules/pattern.ts +3 -8
  370. package/src/js/validation/rules/required.ts +14 -1
  371. package/src/js/validation/rules/shared.ts +5 -1
  372. package/src/js/validation/rules/url.ts +3 -10
  373. package/src/js/validation/skip.ts +9 -0
  374. package/src/js/validation/submit-readiness.ts +9 -2
  375. package/src/js/validation/validator.ts +49 -61
  376. package/dist/chunks/address-state-BwE01m2_.js +0 -344
  377. package/dist/chunks/calculations-Dv3hYb8_.js +0 -299
  378. package/dist/chunks/conditions-CPH1snCx.js +0 -424
  379. package/dist/chunks/country-from-ip-BwxKaBuJ.js +0 -26
  380. package/dist/chunks/field-references.resolver-CHwn0G0L.js +0 -145
  381. package/dist/chunks/friendly-captcha-v1-C_2reOXr.js +0 -31
  382. package/dist/chunks/google-address-BH3Zhi06.js +0 -161
  383. package/dist/chunks/http-D-JExro7.js +0 -27
  384. package/dist/chunks/opayo-CR0DtsLa.js +0 -179
  385. package/dist/chunks/rich-text-Bg_--4TG.js +0 -349
  386. package/dist/js/modules/fields/conditions/transforms.d.ts +0 -3
  387. package/dist/js/modules/fields/conditions/transforms.d.ts.map +0 -1
  388. package/src/js/modules/fields/conditions/transforms.ts +0 -206
  389. package/src/js/modules/payments/stub-payment-module.ts +0 -87
@@ -1,11 +1,14 @@
1
+ import { browserRequestHeaders, type BrowserRequestOptions } from '@verbb/formie-core';
1
2
  import Uppy from '@uppy/core';
2
3
  import XHRUpload from '@uppy/xhr-upload';
3
4
  import uploadManagerCss from '#theme-css/fields/_upload-manager.css?inline';
4
5
 
5
- import type { FormieModuleDefinition } from '#contracts/modules';
6
+ import type { BrowserModuleDefinition } from '#contracts/modules';
6
7
  import { dispatchFieldEvent, releaseFormValidators, retainFormValidators } from '#modules/fields/shared';
7
8
  import { ensureModuleStyles } from '#modules/styles';
8
9
  import { getFieldModuleEventName, getFormStateEventName } from '#utils/event-names';
10
+ import { applyFormCsrfToRecord, appendFormCsrfToFormData, getFormCsrfToken } from '#utils/csrf';
11
+ import { fieldKeyToInputName } from '#utils/field-references';
9
12
  import { requestJson } from '#utils/http';
10
13
  import { createDebug } from '#utils/debug';
11
14
 
@@ -20,6 +23,8 @@ const SORT_UP_SELECTOR = '[data-formie-upload-manager-sort="up"]';
20
23
  const SORT_DOWN_SELECTOR = '[data-formie-upload-manager-sort="down"]';
21
24
  const HIDDEN_INPUT_ANCHOR_ATTR = 'data-formie-file-upload-anchor';
22
25
  const HIDDEN_INPUT_VALUE_ATTR = 'data-formie-file-upload-asset-id';
26
+ const HIDDEN_INPUT_TOKEN_ATTR = 'data-formie-file-upload-token';
27
+ const HIDDEN_INPUT_ENTRY_ATTR = 'data-formie-file-upload-entry';
23
28
  const FORM_RESET_EVENT = getFormStateEventName('reset');
24
29
  const REPEATER_INIT_ROW_EVENT = getFieldModuleEventName('repeater', 'init-row');
25
30
  const MODULE_ID = 'upload-manager';
@@ -37,9 +42,9 @@ type UploadManagerOptions = {
37
42
  uploadEndpoint?: string;
38
43
  deleteEndpoint?: string;
39
44
  hydrateEndpoint?: string;
40
- limitFiles?: number | null;
41
- sizeMinLimit?: number | null;
42
- sizeLimit?: number | null;
45
+ maxFiles?: number | null;
46
+ minFileSize?: number | null;
47
+ maxFileSize?: number | null;
43
48
  accept?: string | null;
44
49
  restrictFiles?: boolean;
45
50
  };
@@ -49,6 +54,10 @@ type UploadResponse = {
49
54
  assetId?: number;
50
55
  filename?: string;
51
56
  url?: string | null;
57
+ uploadToken?: string | null;
58
+ deleteToken?: string | null;
59
+ uploadUid?: string | null;
60
+ attachToken?: string | null;
52
61
  errors?: Record<string, string[]>;
53
62
  };
54
63
 
@@ -62,11 +71,19 @@ type HydrateResponse = {
62
71
  assetId?: number;
63
72
  filename?: string;
64
73
  url?: string | null;
74
+ uploadToken?: string | null;
75
+ deleteToken?: string | null;
76
+ uploadUid?: string | null;
77
+ attachToken?: string | null;
65
78
  }>;
66
79
  };
67
80
 
68
81
  type ManagedFile = {
69
82
  assetId: number | null;
83
+ uploadToken: string | null;
84
+ deleteToken?: string | null;
85
+ uploadUid: string | null;
86
+ attachToken: string | null;
70
87
  filename: string;
71
88
  uppyFileId: string | null;
72
89
  listItem: HTMLElement;
@@ -144,33 +161,85 @@ function getAnchorInput(field: HTMLElement, assetInputName: string): HTMLInputEl
144
161
 
145
162
  function getUploadedAssetInputs(field: HTMLElement, assetInputName: string): HTMLInputElement[] {
146
163
  return getHiddenInputs(field).filter((hiddenInput) => {
147
- return hiddenInput.name === assetInputName && hiddenInput.value.trim() !== '';
164
+ return hiddenInput.hasAttribute(HIDDEN_INPUT_VALUE_ATTR)
165
+ || (hiddenInput.name === assetInputName && hiddenInput.value.trim() !== '');
148
166
  });
149
167
  }
150
168
 
151
169
  function readAssetIdsFromDom(field: HTMLElement, assetInputName: string): number[] {
152
170
  return getUploadedAssetInputs(field, assetInputName).map((input) => {
153
- return toPositiveInt(input.value);
171
+ return toPositiveInt(input.getAttribute(HIDDEN_INPUT_VALUE_ATTR)) ?? toPositiveInt(input.value);
154
172
  }).filter((assetId): assetId is number => {
155
173
  return assetId !== null;
156
174
  });
157
175
  }
158
176
 
159
- function syncHiddenAssetInputs(field: HTMLElement, anchorInput: HTMLInputElement, assetInputName: string, assetIds: number[]): void {
177
+ function readUploadTokensFromDom(field: HTMLElement, assetInputName: string): Record<number, string> {
178
+ const tokens: Record<number, string> = {};
179
+
180
+ getUploadedAssetInputs(field, assetInputName).forEach((input) => {
181
+ const assetId = toPositiveInt(input.getAttribute(HIDDEN_INPUT_VALUE_ATTR)) ?? toPositiveInt(input.value);
182
+ const token = input.getAttribute(HIDDEN_INPUT_TOKEN_ATTR)?.trim() || '';
183
+
184
+ if (assetId && token) {
185
+ tokens[assetId] = token;
186
+ }
187
+ });
188
+
189
+ return tokens;
190
+ }
191
+
192
+ function syncHiddenAssetInputs(
193
+ field: HTMLElement,
194
+ anchorInput: HTMLInputElement,
195
+ assetInputName: string,
196
+ assets: Array<{
197
+ assetId: number;
198
+ uploadToken: string | null;
199
+ uploadUid: string | null;
200
+ attachToken: string | null;
201
+ }>,
202
+ ): void {
160
203
  let insertionPoint: HTMLInputElement = anchorInput;
204
+ const baseName = assetInputName.endsWith('[]') ? assetInputName.slice(0, -2) : assetInputName;
161
205
 
162
- getUploadedAssetInputs(field, assetInputName).forEach((hiddenInput) => {
206
+ getHiddenInputs(field).filter((hiddenInput) => {
207
+ return hiddenInput.hasAttribute(HIDDEN_INPUT_ENTRY_ATTR)
208
+ || (hiddenInput.name === assetInputName && hiddenInput.value.trim() !== '');
209
+ }).forEach((hiddenInput) => {
163
210
  hiddenInput.remove();
164
211
  });
165
212
 
166
- assetIds.forEach((assetId) => {
167
- const hiddenInput = document.createElement('input');
168
- hiddenInput.type = 'hidden';
169
- hiddenInput.name = assetInputName;
170
- hiddenInput.value = String(assetId);
171
- hiddenInput.setAttribute(HIDDEN_INPUT_VALUE_ATTR, 'true');
172
- insertionPoint.insertAdjacentElement('afterend', hiddenInput);
173
- insertionPoint = hiddenInput;
213
+ assets.forEach(({ assetId, uploadToken, uploadUid, attachToken }, index) => {
214
+ const primaryInput = document.createElement('input');
215
+ primaryInput.type = 'hidden';
216
+ primaryInput.setAttribute(HIDDEN_INPUT_ENTRY_ATTR, 'true');
217
+ primaryInput.setAttribute(HIDDEN_INPUT_VALUE_ATTR, String(assetId));
218
+
219
+ if (uploadUid && attachToken) {
220
+ primaryInput.name = `${baseName}[${index}][uploadUid]`;
221
+ primaryInput.value = uploadUid;
222
+ } else {
223
+ primaryInput.name = `${baseName}[${index}][assetId]`;
224
+ primaryInput.value = String(assetId);
225
+ }
226
+
227
+ if (uploadToken) {
228
+ primaryInput.setAttribute(HIDDEN_INPUT_TOKEN_ATTR, uploadToken);
229
+ }
230
+
231
+ insertionPoint.insertAdjacentElement('afterend', primaryInput);
232
+ insertionPoint = primaryInput;
233
+
234
+ if (uploadUid && attachToken) {
235
+ const capabilityInput = document.createElement('input');
236
+ capabilityInput.type = 'hidden';
237
+ capabilityInput.name = `${baseName}[${index}][attachToken]`;
238
+ capabilityInput.value = attachToken;
239
+ capabilityInput.setAttribute(HIDDEN_INPUT_ENTRY_ATTR, 'true');
240
+ insertionPoint.insertAdjacentElement('afterend', capabilityInput);
241
+ insertionPoint = capabilityInput;
242
+ }
174
243
  });
175
244
  }
176
245
 
@@ -189,7 +258,7 @@ function getUploadContext(form: HTMLFormElement | null, field: HTMLElement, drop
189
258
  return context;
190
259
  }
191
260
 
192
- const passthroughNames = ['renderId', 'draftContextToken', 'draftContext', 'submissionId'] as const;
261
+ const passthroughNames = ['renderId', 'draftContextToken', 'draftContext', 'submissionId', 'siteId', 'submissionEditToken', 'resumeToken', 'submissionUid', 'uploadCreateToken'] as const;
193
262
 
194
263
  passthroughNames.forEach((name) => {
195
264
  const input = form.querySelector(`input[name="${name}"]`);
@@ -199,16 +268,18 @@ function getUploadContext(form: HTMLFormElement | null, field: HTMLElement, drop
199
268
  }
200
269
  });
201
270
 
202
- const csrfInput = form.querySelector('input[name="CRAFT_CSRF_TOKEN"]');
203
-
204
- if (csrfInput instanceof HTMLInputElement && csrfInput.value.trim()) {
205
- context.CRAFT_CSRF_TOKEN = csrfInput.value.trim();
206
- }
271
+ // Honour custom Craft csrfTokenName values from the rendered form.
272
+ applyFormCsrfToRecord(context, form);
207
273
 
208
274
  return context;
209
275
  }
210
276
 
211
- function buildHydrateFormData(form: HTMLFormElement | null, field: HTMLElement, assetIds: number[]): FormData {
277
+ function buildHydrateFormData(
278
+ form: HTMLFormElement | null,
279
+ field: HTMLElement,
280
+ assetIds: number[],
281
+ uploadTokens: Record<number, string> = {},
282
+ ): FormData {
212
283
  const body = new FormData();
213
284
  const handle = getFormHandle(form);
214
285
  const fieldHandle = getFieldHandle(field);
@@ -221,16 +292,28 @@ function buildHydrateFormData(form: HTMLFormElement | null, field: HTMLElement,
221
292
  body.append('fieldHandle', fieldHandle);
222
293
  }
223
294
 
224
- const submissionUidInput = form?.querySelector('input[name="submissionUid"]');
295
+ const passthroughNames = ['submissionUid', 'resumeToken', 'submissionEditToken', 'siteId', 'renderId', 'draftContext', 'draftContextToken'] as const;
225
296
 
226
- if (submissionUidInput instanceof HTMLInputElement && submissionUidInput.value.trim()) {
227
- body.append('submissionUid', submissionUidInput.value.trim());
228
- }
297
+ passthroughNames.forEach((name) => {
298
+ const input = form?.querySelector(`input[name="${name}"]`);
299
+
300
+ if (input instanceof HTMLInputElement && input.value.trim()) {
301
+ body.append(name, input.value.trim());
302
+ }
303
+ });
229
304
 
230
305
  assetIds.forEach((assetId) => {
231
306
  body.append('assetIds[]', String(assetId));
307
+
308
+ const token = uploadTokens[assetId];
309
+
310
+ if (token) {
311
+ body.append(`uploadTokens[${assetId}]`, token);
312
+ }
232
313
  });
233
314
 
315
+ appendFormCsrfToFormData(body, form);
316
+
234
317
  return body;
235
318
  }
236
319
 
@@ -425,6 +508,19 @@ function markUploadComplete(listItem: HTMLElement): void {
425
508
  }, UPLOAD_COMPLETE_DISPLAY_MS);
426
509
  }
427
510
 
511
+ function markUploadFailed(listItem: HTMLElement): void {
512
+ const { track, bar, label } = getProgressElements(listItem);
513
+
514
+ listItem.classList.add('is-error');
515
+ listItem.classList.remove('is-uploading', 'is-upload-complete', 'is-processing', 'is-preparing');
516
+ track?.setAttribute('data-indeterminate', 'false');
517
+ bar?.setAttribute('data-progress', 'error');
518
+
519
+ if (label) {
520
+ label.textContent = 'Upload failed';
521
+ }
522
+ }
523
+
428
524
  function createSortButton(direction: 'up' | 'down'): HTMLButtonElement {
429
525
  const label = direction === 'up' ? 'Move file up' : 'Move file down';
430
526
  const button = document.createElement('button');
@@ -524,17 +620,20 @@ function createListItem(field: HTMLElement, filename: string): {
524
620
  }
525
621
 
526
622
  function getAssetInputName(field: HTMLElement): string {
527
- const existingAssetInput = getHiddenInputs(field).find((input) => {
528
- return input.hasAttribute(HIDDEN_INPUT_VALUE_ATTR);
623
+ // Prefer the template anchor name — nested Group/Repeater fields use
624
+ // `fields[group][upload][]`, not a dotted `fields[group.upload][]`.
625
+ const anchorInput = getHiddenInputs(field).find((input) => {
626
+ return input.hasAttribute(HIDDEN_INPUT_ANCHOR_ATTR);
529
627
  });
530
628
 
531
- if (existingAssetInput?.name) {
532
- return existingAssetInput.name;
629
+ if (anchorInput?.name) {
630
+ return anchorInput.name.endsWith('[]') ? anchorInput.name : `${anchorInput.name}[]`;
533
631
  }
534
632
 
535
633
  const fieldHandle = getFieldHandle(field);
634
+ const inputName = fieldHandle ? fieldKeyToInputName(fieldHandle) : '';
536
635
 
537
- return fieldHandle ? `fields[${fieldHandle}][]` : 'fields[fileUpload][]';
636
+ return inputName ? `${inputName}[]` : 'fields[fileUpload][]';
538
637
  }
539
638
 
540
639
  function countManagedAssets(state: UploadManagerState): number {
@@ -544,27 +643,31 @@ function countManagedAssets(state: UploadManagerState): number {
544
643
  }
545
644
 
546
645
  function syncUploadedAssetsEvent(state: UploadManagerState): void {
547
- const assetIds = state.files.map((file) => {
548
- return file.assetId;
549
- }).filter((assetId): assetId is number => {
550
- return assetId !== null;
551
- });
646
+ const assets = state.files
647
+ .filter((file): file is ManagedFile & { assetId: number } => {
648
+ return file.assetId !== null;
649
+ })
650
+ .map((file) => {
651
+ return {
652
+ assetId: file.assetId,
653
+ uploadToken: file.uploadToken,
654
+ uploadUid: file.uploadUid,
655
+ attachToken: file.attachToken,
656
+ filename: file.filename,
657
+ };
658
+ });
552
659
 
553
- syncHiddenAssetInputs(state.field, state.anchorInput, state.assetInputName, assetIds);
660
+ syncHiddenAssetInputs(state.field, state.anchorInput, state.assetInputName, assets);
554
661
 
555
662
  if (state.statusInput) {
556
- state.statusInput.value = assetIds.length ? 'uploaded' : '';
663
+ state.statusInput.value = assets.length ? 'uploaded' : '';
557
664
  }
558
665
 
559
666
  dispatchFieldEvent(state.field, 'file-upload', 'uploaded-assets-sync', {
560
- assets: assetIds.map((assetId) => {
561
- const managed = state.files.find((file) => {
562
- return file.assetId === assetId;
563
- });
564
-
667
+ assets: assets.map(({ assetId, filename }) => {
565
668
  return {
566
669
  assetId,
567
- filename: managed?.filename || '',
670
+ filename,
568
671
  };
569
672
  }),
570
673
  });
@@ -673,9 +776,9 @@ function bindUploadManagerField(field: HTMLElement, form: HTMLFormElement | null
673
776
  const uploadEndpoint = getEndpoint(dropzone, options.uploadEndpoint, 'data-formie-file-upload-upload-endpoint', '/actions/formie/file-upload/upload');
674
777
  const deleteEndpoint = getEndpoint(dropzone, options.deleteEndpoint, 'data-formie-file-upload-delete-endpoint', '/actions/formie/file-upload/delete');
675
778
  const hydrateEndpoint = getEndpoint(dropzone, options.hydrateEndpoint, 'data-formie-file-upload-hydrate-endpoint', '/actions/formie/file-upload/hydrate');
676
- const limitFiles = options.limitFiles ?? toPositiveInt(dropzone.getAttribute('data-formie-file-limit'));
677
- const sizeLimit = options.sizeLimit ?? parseFloat(dropzone.getAttribute('data-formie-size-max-limit') || '');
678
- const sizeMinLimit = options.sizeMinLimit ?? parseFloat(dropzone.getAttribute('data-formie-size-min-limit') || '');
779
+ const maxFiles = options.maxFiles ?? toPositiveInt(dropzone.getAttribute('data-formie-file-limit'));
780
+ const maxFileSize = options.maxFileSize ?? parseFloat(dropzone.getAttribute('data-formie-size-max-limit') || '');
781
+ const minFileSize = options.minFileSize ?? parseFloat(dropzone.getAttribute('data-formie-size-min-limit') || '');
679
782
  const accept = options.accept ?? dropzone.getAttribute('accept') ?? browseInput.accept;
680
783
  const allowedFileTypes = parseAcceptTypes(accept);
681
784
 
@@ -686,16 +789,16 @@ function bindUploadManagerField(field: HTMLElement, form: HTMLFormElement | null
686
789
  allowedFileTypes?: string[] | null;
687
790
  } = {};
688
791
 
689
- if (limitFiles) {
690
- restrictions.maxNumberOfFiles = limitFiles;
792
+ if (maxFiles) {
793
+ restrictions.maxNumberOfFiles = maxFiles;
691
794
  }
692
795
 
693
- if (sizeLimit) {
694
- restrictions.maxFileSize = sizeLimit * 1000 * 1000;
796
+ if (maxFileSize) {
797
+ restrictions.maxFileSize = maxFileSize * 1000 * 1000;
695
798
  }
696
799
 
697
- if (sizeMinLimit) {
698
- restrictions.minFileSize = sizeMinLimit * 1000 * 1000;
800
+ if (minFileSize) {
801
+ restrictions.minFileSize = minFileSize * 1000 * 1000;
699
802
  }
700
803
 
701
804
  if (allowedFileTypes) {
@@ -707,11 +810,36 @@ function bindUploadManagerField(field: HTMLElement, form: HTMLFormElement | null
707
810
  restrictions,
708
811
  });
709
812
 
813
+ const selectionError = document.createElement('div');
814
+ selectionError.className = 'formie-upload-manager-error';
815
+ selectionError.setAttribute('role', 'alert');
816
+ selectionError.hidden = true;
817
+ root.append(selectionError);
818
+
819
+ // Uppy stores restriction messages for UI plugins; this custom UI must render them.
820
+ uppy.on('info-visible', () => {
821
+ const messages = uppy.getState().info.filter((info) => info.type === 'error');
822
+
823
+ if (messages.length) {
824
+ selectionError.textContent = [...new Set(messages.map((info) => info.message))].join(' ');
825
+ selectionError.hidden = false;
826
+ }
827
+ });
828
+
829
+ const clearSelectionError = () => {
830
+ selectionError.textContent = '';
831
+ selectionError.hidden = true;
832
+ };
833
+
834
+ // Resolve once for Uppy's allow-list; per-request meta/header refresh
835
+ // still re-reads the live form token (including custom csrfTokenName).
836
+ const initialCsrf = getFormCsrfToken(resolvedForm);
837
+
710
838
  uppy.use(XHRUpload, {
711
839
  endpoint: uploadEndpoint,
712
840
  fieldName: 'file',
713
841
  formData: true,
714
- withCredentials: true,
842
+ withCredentials: resolvedForm?.dataset.formieRequestProfile !== 'cross-origin-public',
715
843
  timeout: UPLOAD_XHR_TIMEOUT_MS,
716
844
  shouldRetry: shouldRetryUpload,
717
845
  headers: {
@@ -725,7 +853,11 @@ function bindUploadManagerField(field: HTMLElement, form: HTMLFormElement | null
725
853
  'draftContextToken',
726
854
  'draftContext',
727
855
  'submissionId',
728
- 'CRAFT_CSRF_TOKEN',
856
+ 'siteId',
857
+ 'submissionEditToken',
858
+ 'resumeToken',
859
+ 'uploadCreateToken',
860
+ ...(initialCsrf ? [initialCsrf.name] : []),
729
861
  ],
730
862
  getResponseData(xhr) {
731
863
  try {
@@ -735,6 +867,14 @@ function bindUploadManagerField(field: HTMLElement, form: HTMLFormElement | null
735
867
  }
736
868
  },
737
869
  onBeforeRequest(xhr, _retryCount, files) {
870
+ browserRequestHeaders(uploadEndpoint, { profile: resolvedForm?.dataset.formieRequestProfile as BrowserRequestOptions['profile'] }).forEach((value, name) => xhr.setRequestHeader(name, value));
871
+ // Header works regardless of csrfTokenName / allowedMetaFields.
872
+ const csrf = getFormCsrfToken(resolvedForm);
873
+
874
+ if (csrf) {
875
+ xhr.setRequestHeader('X-CSRF-Token', csrf.value);
876
+ }
877
+
738
878
  const uppyFile = files[0];
739
879
 
740
880
  if (!uppyFile?.id || !uppyFile.size) {
@@ -780,11 +920,11 @@ function bindUploadManagerField(field: HTMLElement, form: HTMLFormElement | null
780
920
  };
781
921
 
782
922
  const remainingUploadCapacity = (): number | null => {
783
- if (!limitFiles) {
923
+ if (!maxFiles) {
784
924
  return null;
785
925
  }
786
926
 
787
- return Math.max(0, limitFiles - countManagedAssets(state));
927
+ return Math.max(0, maxFiles - countManagedAssets(state));
788
928
  };
789
929
 
790
930
  const setDropzoneActive = (active: boolean) => {
@@ -888,8 +1028,13 @@ function bindUploadManagerField(field: HTMLElement, form: HTMLFormElement | null
888
1028
 
889
1029
  body.append('assetId', String(managedFile.assetId));
890
1030
 
1031
+ if (managedFile.uploadToken) {
1032
+ body.append('uploadToken', managedFile.deleteToken || '');
1033
+ }
1034
+
891
1035
  try {
892
1036
  await requestJson<DeleteResponse>(deleteEndpoint, {
1037
+ profile: resolvedForm?.dataset.formieRequestProfile as BrowserRequestOptions['profile'],
893
1038
  method: 'POST',
894
1039
  body,
895
1040
  });
@@ -906,13 +1051,24 @@ function bindUploadManagerField(field: HTMLElement, form: HTMLFormElement | null
906
1051
  syncSortControls();
907
1052
  };
908
1053
 
909
- const addManagedFileFromAsset = (assetId: number, filename: string) => {
1054
+ const addManagedFileFromAsset = (
1055
+ assetId: number,
1056
+ filename: string,
1057
+ uploadToken: string | null = null,
1058
+ deleteToken: string | null = null,
1059
+ uploadUid: string | null = null,
1060
+ attachToken: string | null = null,
1061
+ ) => {
910
1062
  const { listItem, removeButton, sortUpButton, sortDownButton } = createListItem(field, filename);
911
1063
  listItem.classList.add('is-complete');
912
1064
  fileList.append(listItem);
913
1065
 
914
1066
  const managedFile: ManagedFile = {
915
1067
  assetId,
1068
+ uploadToken,
1069
+ deleteToken,
1070
+ uploadUid,
1071
+ attachToken,
916
1072
  filename,
917
1073
  uppyFileId: null,
918
1074
  listItem,
@@ -930,10 +1086,13 @@ function bindUploadManagerField(field: HTMLElement, form: HTMLFormElement | null
930
1086
  return;
931
1087
  }
932
1088
 
1089
+ const uploadTokens = readUploadTokensFromDom(field, assetInputName);
1090
+
933
1091
  try {
934
1092
  const response = await requestJson<HydrateResponse>(hydrateEndpoint, {
1093
+ profile: resolvedForm?.dataset.formieRequestProfile as BrowserRequestOptions['profile'],
935
1094
  method: 'POST',
936
- body: buildHydrateFormData(resolvedForm, field, assetIds),
1095
+ body: buildHydrateFormData(resolvedForm, field, assetIds, uploadTokens),
937
1096
  });
938
1097
 
939
1098
  const assets = response.assets || [];
@@ -956,7 +1115,14 @@ function bindUploadManagerField(field: HTMLElement, form: HTMLFormElement | null
956
1115
  return;
957
1116
  }
958
1117
 
959
- addManagedFileFromAsset(assetId, asset.filename || `Asset #${assetId}`);
1118
+ addManagedFileFromAsset(
1119
+ assetId,
1120
+ asset.filename || `Asset #${assetId}`,
1121
+ toTrimmedString(asset.uploadToken) || uploadTokens[assetId] || null,
1122
+ toTrimmedString(asset.deleteToken) || null,
1123
+ toTrimmedString(asset.uploadUid) || null,
1124
+ toTrimmedString(asset.attachToken) || null,
1125
+ );
960
1126
  });
961
1127
 
962
1128
  syncUploadedAssetsEvent(state);
@@ -1015,8 +1181,7 @@ function bindUploadManagerField(field: HTMLElement, form: HTMLFormElement | null
1015
1181
  const assetId = toPositiveInt(body.assetId);
1016
1182
 
1017
1183
  if (!body.success || !assetId) {
1018
- managedFile.listItem.classList.add('is-error');
1019
- managedFile.listItem.classList.remove('is-uploading', 'is-upload-complete', 'is-processing', 'is-preparing');
1184
+ markUploadFailed(managedFile.listItem);
1020
1185
 
1021
1186
  if (errorEl instanceof HTMLElement) {
1022
1187
  errorEl.hidden = false;
@@ -1034,6 +1199,10 @@ function bindUploadManagerField(field: HTMLElement, form: HTMLFormElement | null
1034
1199
  }
1035
1200
 
1036
1201
  managedFile.assetId = assetId;
1202
+ managedFile.uploadToken = toTrimmedString(body.uploadToken) || null;
1203
+ managedFile.deleteToken = toTrimmedString(body.deleteToken) || null;
1204
+ managedFile.uploadUid = toTrimmedString(body.uploadUid) || null;
1205
+ managedFile.attachToken = toTrimmedString(body.attachToken) || null;
1037
1206
  managedFile.filename = body.filename || managedFile.filename;
1038
1207
  markUploadComplete(managedFile.listItem);
1039
1208
  syncUploadedAssetsEvent(state);
@@ -1048,8 +1217,7 @@ function bindUploadManagerField(field: HTMLElement, form: HTMLFormElement | null
1048
1217
  }
1049
1218
 
1050
1219
  const errorEl = managedFile.listItem.querySelector('[data-formie-upload-manager-error]');
1051
- managedFile.listItem.classList.add('is-error');
1052
- managedFile.listItem.classList.remove('is-uploading', 'is-upload-complete', 'is-processing', 'is-preparing');
1220
+ markUploadFailed(managedFile.listItem);
1053
1221
 
1054
1222
  if (errorEl instanceof HTMLElement) {
1055
1223
  errorEl.hidden = false;
@@ -1073,6 +1241,9 @@ function bindUploadManagerField(field: HTMLElement, form: HTMLFormElement | null
1073
1241
 
1074
1242
  const managedFile: ManagedFile = {
1075
1243
  assetId: null,
1244
+ uploadToken: null,
1245
+ uploadUid: null,
1246
+ attachToken: null,
1076
1247
  filename: file.name || 'Upload',
1077
1248
  uppyFileId: file.id,
1078
1249
  listItem,
@@ -1115,6 +1286,7 @@ function bindUploadManagerField(field: HTMLElement, form: HTMLFormElement | null
1115
1286
 
1116
1287
  const files = Array.from(browseInput.files);
1117
1288
  browseInput.value = '';
1289
+ clearSelectionError();
1118
1290
 
1119
1291
  try {
1120
1292
  uppy.addFiles(files.map((file) => {
@@ -1155,6 +1327,7 @@ function bindUploadManagerField(field: HTMLElement, form: HTMLFormElement | null
1155
1327
  }
1156
1328
 
1157
1329
  const files = Array.from(transfer.files);
1330
+ clearSelectionError();
1158
1331
 
1159
1332
  try {
1160
1333
  uppy.addFiles(files.map((file) => {
@@ -1172,6 +1345,7 @@ function bindUploadManagerField(field: HTMLElement, form: HTMLFormElement | null
1172
1345
  });
1173
1346
 
1174
1347
  const resetHandler = () => {
1348
+ clearSelectionError();
1175
1349
  state.files.forEach((managedFile) => {
1176
1350
  managedFile.listItem.remove();
1177
1351
  });
@@ -1187,12 +1361,15 @@ function bindUploadManagerField(field: HTMLElement, form: HTMLFormElement | null
1187
1361
  return () => {
1188
1362
  resolvedForm?.removeEventListener(FORM_RESET_EVENT, resetHandler);
1189
1363
  uppy.destroy();
1364
+ selectionError.remove();
1190
1365
  state.files = [];
1191
1366
  };
1192
1367
  }
1193
1368
 
1194
- export const uploadManagerModule: FormieModuleDefinition = {
1195
- id: MODULE_ID,
1369
+ export const uploadManagerModule: BrowserModuleDefinition = {
1370
+ moduleId: `formie:${MODULE_ID}`,
1371
+ version: 2,
1372
+ surfaces: ['server-rendered', 'client-rendered', 'cp-edit'],
1196
1373
  kind: 'field',
1197
1374
  match: (ctx) => {
1198
1375
  return !!ctx.target.querySelector(ROOT_SELECTOR);