@verbb/formie-browser 1.0.13 → 1.0.14

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 (381) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/dist/chunks/{address-country-Rx6GQTND.js → address-country-Dn71jroa.js} +10 -4
  3. package/dist/chunks/{address-finder-k7_BXaRe.js → address-finder-O49uDRoR.js} +2 -2
  4. package/dist/chunks/{address-state-BwE01m2_.js → address-state-ByYatUur.js} +154 -143
  5. package/dist/chunks/{api-DqpfkZWL.js → api-D6kJ7kXZ.js} +183 -179
  6. package/dist/chunks/{api-BUb6P-xu.js → api-DYYsVIub.js} +77 -47
  7. package/dist/chunks/{api-sPqGbOww.js → api-ghNr2uxX.js} +15 -9
  8. package/dist/chunks/{bpoint-Dlq34XH1.js → bpoint-D0RKFM4F.js} +3 -3
  9. package/dist/chunks/calculations-YEoVCG2q.js +310 -0
  10. package/dist/chunks/{captcha-eu-CGm8Lbrj.js → captcha-eu-DERJbXnH.js} +5 -4
  11. package/dist/chunks/{checkbox-radio-BY2aTCOG.js → checkbox-radio-gsm8QPJg.js} +74 -75
  12. package/dist/chunks/{combobox-C0EuExSI.js → combobox-CWNdx4Fk.js} +290 -279
  13. package/dist/chunks/conditions-DqNHLTbN.js +464 -0
  14. package/dist/chunks/country-from-ip-DDj_mFki.js +29 -0
  15. package/dist/chunks/csrf-DxHg_ZYt.js +61 -0
  16. package/dist/chunks/{custom-google-maps-BsaSirEZ.js → custom-google-maps-C4l2S3GO.js} +9 -3
  17. package/dist/chunks/{custom-link-CJ1-FjEM.js → custom-link-CLazgKYH.js} +8 -2
  18. package/dist/chunks/{custom-maps-DYW_pBid.js → custom-maps-DqcAlD0v.js} +10 -4
  19. package/dist/chunks/{date-picker-F9BUBDSW.js → date-picker-RUnevF7l.js} +455 -432
  20. package/dist/chunks/{dist-D6i-VNgM.js → dist-ZLeW0zZ3.js} +1281 -453
  21. package/dist/chunks/{eway-D9_m8ooj.js → eway-or6dtjoT.js} +3 -3
  22. package/dist/chunks/field-references.resolver-Ca8MguFv.js +104 -0
  23. package/dist/chunks/{file-upload-rqfZNqlH.js → file-upload-Bm-TXyNB.js} +104 -96
  24. package/dist/chunks/friendly-captcha-v1-GFqCt1Mh.js +34 -0
  25. package/dist/chunks/{friendly-captcha-v2-CLSAbkqx.js → friendly-captcha-v2-WoW246JG.js} +6 -5
  26. package/dist/chunks/{friendly-challenge-8uPatWqk.js → friendly-challenge-DPG9MJb1.js} +111 -102
  27. package/dist/chunks/{go-cardless-DAT3ZaQf.js → go-cardless-DzJ-0FKg.js} +2 -2
  28. package/dist/chunks/google-address-C1P1nTDM.js +163 -0
  29. package/dist/chunks/{hcaptcha-CGLAmgjO.js → hcaptcha-D0T8aIHz.js} +3 -3
  30. package/dist/chunks/{hidden-D7_Ch-QN.js → hidden-BZhXnNPe.js} +8 -2
  31. package/dist/chunks/http-C2QdHuWO.js +27 -0
  32. package/dist/chunks/{leaflet-src-j-lHNmhR.js → leaflet-src-DE6rv6M-.js} +42 -46
  33. package/dist/chunks/{loqate-CJPzBmSm.js → loqate-DD1S7PY9.js} +2 -2
  34. package/dist/chunks/{mollie-Bibhl67p.js → mollie-DG8Ju83x.js} +2 -2
  35. package/dist/chunks/{moneris-H2wSqk9h.js → moneris-C8m3Fvqu.js} +3 -3
  36. package/dist/chunks/opayo-B3EvrVxw.js +188 -0
  37. package/dist/chunks/{paddle-DkvIxQdG.js → paddle-BIYR9Um3.js} +3 -3
  38. package/dist/chunks/{password-validation-D06uH9va.js → password-validation-C8_uO_c_.js} +18 -12
  39. package/dist/chunks/{paypal-CQpAF7Ua.js → paypal-B_yxIo2d.js} +7 -5
  40. package/dist/chunks/{payway-CwDkC7YZ.js → payway-CeOzS0sL.js} +3 -3
  41. package/dist/chunks/{phone-country-D3ayr60L.js → phone-country-bAqje17P.js} +80 -63
  42. package/dist/chunks/{place-kit-BGHklIZ-.js → place-kit-BE5gi3vo.js} +3 -3
  43. package/dist/chunks/{placekit-autocomplete.esm-DWVabQlq.js → placekit-autocomplete.esm-CZZERYur.js} +11 -15
  44. package/dist/chunks/{recaptcha-enterprise-XPId5-bS.js → recaptcha-enterprise-CruXddZq.js} +4 -4
  45. package/dist/chunks/{recaptcha-shared-CLYJvojk.js → recaptcha-shared-AQRMDMme.js} +1 -1
  46. package/dist/chunks/{recaptcha-v2-checkbox-Cy-0PEPc.js → recaptcha-v2-checkbox-CCnJYCnG.js} +4 -4
  47. package/dist/chunks/{recaptcha-v2-invisible-BwRH540O.js → recaptcha-v2-invisible-BuVqRRYn.js} +4 -4
  48. package/dist/chunks/{recaptcha-v3-No4Ykrhk.js → recaptcha-v3-CloqhO2A.js} +4 -4
  49. package/dist/chunks/{repeater-BVnPUqTj.js → repeater-DwE27jI1.js} +25 -19
  50. package/dist/chunks/request-profile-DhwkeCpS.js +10 -0
  51. package/dist/chunks/rich-text-uV4o_pGk.js +361 -0
  52. package/dist/chunks/{chunk-3b4jIN3o.js → rolldown-runtime-DtPi1Y-2.js} +2 -2
  53. package/dist/chunks/{sdk-BhHAYgga.js → sdk-lkwSvlpM.js} +282 -234
  54. package/dist/chunks/{shared-Bx9s0i0P.js → shared-OKhSay59.js} +27 -21
  55. package/dist/chunks/{signature-IOhuicje.js → signature-7cldFbqj.js} +138 -112
  56. package/dist/chunks/{snaptcha-DKx98oon.js → snaptcha-C04kNGYQ.js} +2 -2
  57. package/dist/chunks/{square-DwdcOI1G.js → square-DEzxv9D9.js} +8 -6
  58. package/dist/chunks/{stripe-DaoG2FT1.js → stripe-CVPQGDz3.js} +10 -11
  59. package/dist/chunks/{summary-Dks0gXS3.js → summary-BF_8mrXI.js} +47 -45
  60. package/dist/chunks/{survey-likert-DkE6bR7B.js → survey-likert-fk1hUPff.js} +7 -1
  61. package/dist/chunks/{survey-rank-DN6x4IZM.js → survey-rank-BsLGl2LX.js} +37 -25
  62. package/dist/chunks/{survey-rating-BnsNL9U5.js → survey-rating-DVS6e6fM.js} +17 -5
  63. package/dist/chunks/{table-CAjCJHrL.js → table-DnIBdeKF.js} +21 -15
  64. package/dist/chunks/{text-limit-BGaY0jhI.js → text-limit-LGMPhFuC.js} +40 -34
  65. package/dist/chunks/{theme-classes-Tv7q7ToE.js → theme-classes-DAQuEqdP.js} +1 -1
  66. package/dist/chunks/{turnstile-DJakPzQD.js → turnstile-n9DNyPxi.js} +3 -3
  67. package/dist/chunks/{upload-manager-W-QDgxKD.js → upload-manager-BbiUosZq.js} +410 -350
  68. package/dist/chunks/{utils-Vqp8i_RM.js → utils-DpUBPadZ.js} +20 -14
  69. package/dist/css/formie-base.css +104 -1
  70. package/dist/css/theme/_messages.css +2 -0
  71. package/dist/css/theme/_tokens.css +31 -25
  72. package/dist/css/theme/forms/_form.css +5 -1
  73. package/dist/index.d.ts +5 -4
  74. package/dist/index.d.ts.map +1 -1
  75. package/dist/index.js +1778 -1427
  76. package/dist/js/contracts/client.d.ts +5 -3
  77. package/dist/js/contracts/client.d.ts.map +1 -1
  78. package/dist/js/contracts/common.d.ts +2 -2
  79. package/dist/js/contracts/common.d.ts.map +1 -1
  80. package/dist/js/contracts/modules.d.ts +37 -12
  81. package/dist/js/contracts/modules.d.ts.map +1 -1
  82. package/dist/js/contracts/schema.d.ts +20 -38
  83. package/dist/js/contracts/schema.d.ts.map +1 -1
  84. package/dist/js/contracts/theme.d.ts +4 -1
  85. package/dist/js/contracts/theme.d.ts.map +1 -1
  86. package/dist/js/core/client-rendered-modules.d.ts +17 -0
  87. package/dist/js/core/client-rendered-modules.d.ts.map +1 -0
  88. package/dist/js/core/create-formie-client.d.ts.map +1 -1
  89. package/dist/js/core/field-error-aria.d.ts +23 -0
  90. package/dist/js/core/field-error-aria.d.ts.map +1 -0
  91. package/dist/js/core/hydrate-modules.d.ts +10 -8
  92. package/dist/js/core/hydrate-modules.d.ts.map +1 -1
  93. package/dist/js/core/submit-result-state.d.ts.map +1 -1
  94. package/dist/js/core/submit-result-ui.d.ts.map +1 -1
  95. package/dist/js/core/validation-focus.d.ts.map +1 -1
  96. package/dist/js/modules/address/address-finder.d.ts +1 -1
  97. package/dist/js/modules/address/address-finder.d.ts.map +1 -1
  98. package/dist/js/modules/address/factories.d.ts +3 -3
  99. package/dist/js/modules/address/factories.d.ts.map +1 -1
  100. package/dist/js/modules/address/google-address.d.ts +2 -1
  101. package/dist/js/modules/address/google-address.d.ts.map +1 -1
  102. package/dist/js/modules/address/index.d.ts +2 -2
  103. package/dist/js/modules/address/index.d.ts.map +1 -1
  104. package/dist/js/modules/address/loqate.d.ts +1 -1
  105. package/dist/js/modules/address/loqate.d.ts.map +1 -1
  106. package/dist/js/modules/address/place-kit.d.ts +1 -1
  107. package/dist/js/modules/address/place-kit.d.ts.map +1 -1
  108. package/dist/js/modules/captchas/captcha-eu.d.ts +1 -1
  109. package/dist/js/modules/captchas/captcha-eu.d.ts.map +1 -1
  110. package/dist/js/modules/captchas/factories.d.ts +11 -11
  111. package/dist/js/modules/captchas/factories.d.ts.map +1 -1
  112. package/dist/js/modules/captchas/friendly-captcha-v1.d.ts +1 -1
  113. package/dist/js/modules/captchas/friendly-captcha-v1.d.ts.map +1 -1
  114. package/dist/js/modules/captchas/friendly-captcha-v2.d.ts +1 -1
  115. package/dist/js/modules/captchas/friendly-captcha-v2.d.ts.map +1 -1
  116. package/dist/js/modules/captchas/hcaptcha.d.ts +1 -1
  117. package/dist/js/modules/captchas/hcaptcha.d.ts.map +1 -1
  118. package/dist/js/modules/captchas/index.d.ts +2 -2
  119. package/dist/js/modules/captchas/index.d.ts.map +1 -1
  120. package/dist/js/modules/captchas/recaptcha-enterprise.d.ts +1 -1
  121. package/dist/js/modules/captchas/recaptcha-enterprise.d.ts.map +1 -1
  122. package/dist/js/modules/captchas/recaptcha-v2-checkbox.d.ts +1 -1
  123. package/dist/js/modules/captchas/recaptcha-v2-checkbox.d.ts.map +1 -1
  124. package/dist/js/modules/captchas/recaptcha-v2-invisible.d.ts +1 -1
  125. package/dist/js/modules/captchas/recaptcha-v2-invisible.d.ts.map +1 -1
  126. package/dist/js/modules/captchas/recaptcha-v3.d.ts +1 -1
  127. package/dist/js/modules/captchas/recaptcha-v3.d.ts.map +1 -1
  128. package/dist/js/modules/captchas/snaptcha.d.ts +1 -1
  129. package/dist/js/modules/captchas/snaptcha.d.ts.map +1 -1
  130. package/dist/js/modules/captchas/turnstile.d.ts +1 -1
  131. package/dist/js/modules/captchas/turnstile.d.ts.map +1 -1
  132. package/dist/js/modules/fields/address-country.d.ts +2 -2
  133. package/dist/js/modules/fields/address-country.d.ts.map +1 -1
  134. package/dist/js/modules/fields/address-state.d.ts +2 -2
  135. package/dist/js/modules/fields/address-state.d.ts.map +1 -1
  136. package/dist/js/modules/fields/calculations.d.ts +2 -2
  137. package/dist/js/modules/fields/calculations.d.ts.map +1 -1
  138. package/dist/js/modules/fields/checkbox-radio.d.ts +2 -2
  139. package/dist/js/modules/fields/checkbox-radio.d.ts.map +1 -1
  140. package/dist/js/modules/fields/combobox.d.ts +2 -2
  141. package/dist/js/modules/fields/combobox.d.ts.map +1 -1
  142. package/dist/js/modules/fields/conditions/config.d.ts.map +1 -1
  143. package/dist/js/modules/fields/conditions/effects.d.ts +1 -0
  144. package/dist/js/modules/fields/conditions/effects.d.ts.map +1 -1
  145. package/dist/js/modules/fields/conditions/evaluator.d.ts +4 -1
  146. package/dist/js/modules/fields/conditions/evaluator.d.ts.map +1 -1
  147. package/dist/js/modules/fields/conditions/references.d.ts.map +1 -1
  148. package/dist/js/modules/fields/conditions/submission-context.d.ts +15 -0
  149. package/dist/js/modules/fields/conditions/submission-context.d.ts.map +1 -0
  150. package/dist/js/modules/fields/conditions/types.d.ts +3 -1
  151. package/dist/js/modules/fields/conditions/types.d.ts.map +1 -1
  152. package/dist/js/modules/fields/conditions/values.d.ts +1 -1
  153. package/dist/js/modules/fields/conditions/values.d.ts.map +1 -1
  154. package/dist/js/modules/fields/conditions.d.ts +2 -2
  155. package/dist/js/modules/fields/conditions.d.ts.map +1 -1
  156. package/dist/js/modules/fields/custom-google-maps.d.ts +2 -2
  157. package/dist/js/modules/fields/custom-google-maps.d.ts.map +1 -1
  158. package/dist/js/modules/fields/custom-link.d.ts +2 -2
  159. package/dist/js/modules/fields/custom-link.d.ts.map +1 -1
  160. package/dist/js/modules/fields/custom-maps.d.ts +2 -2
  161. package/dist/js/modules/fields/custom-maps.d.ts.map +1 -1
  162. package/dist/js/modules/fields/date-picker.d.ts +2 -2
  163. package/dist/js/modules/fields/date-picker.d.ts.map +1 -1
  164. package/dist/js/modules/fields/file-upload.d.ts +2 -2
  165. package/dist/js/modules/fields/file-upload.d.ts.map +1 -1
  166. package/dist/js/modules/fields/hidden.d.ts +2 -2
  167. package/dist/js/modules/fields/hidden.d.ts.map +1 -1
  168. package/dist/js/modules/fields/index.d.ts +2 -2
  169. package/dist/js/modules/fields/index.d.ts.map +1 -1
  170. package/dist/js/modules/fields/password-validation.d.ts +2 -2
  171. package/dist/js/modules/fields/password-validation.d.ts.map +1 -1
  172. package/dist/js/modules/fields/phone-country.d.ts +2 -2
  173. package/dist/js/modules/fields/phone-country.d.ts.map +1 -1
  174. package/dist/js/modules/fields/repeater.d.ts +2 -2
  175. package/dist/js/modules/fields/repeater.d.ts.map +1 -1
  176. package/dist/js/modules/fields/rich-text.d.ts +2 -2
  177. package/dist/js/modules/fields/rich-text.d.ts.map +1 -1
  178. package/dist/js/modules/fields/shared.d.ts +1 -0
  179. package/dist/js/modules/fields/shared.d.ts.map +1 -1
  180. package/dist/js/modules/fields/signature.d.ts +2 -2
  181. package/dist/js/modules/fields/signature.d.ts.map +1 -1
  182. package/dist/js/modules/fields/summary.d.ts +2 -2
  183. package/dist/js/modules/fields/summary.d.ts.map +1 -1
  184. package/dist/js/modules/fields/survey-likert.d.ts +2 -2
  185. package/dist/js/modules/fields/survey-likert.d.ts.map +1 -1
  186. package/dist/js/modules/fields/survey-rank.d.ts +2 -2
  187. package/dist/js/modules/fields/survey-rank.d.ts.map +1 -1
  188. package/dist/js/modules/fields/survey-rating.d.ts +2 -2
  189. package/dist/js/modules/fields/survey-rating.d.ts.map +1 -1
  190. package/dist/js/modules/fields/table.d.ts +2 -2
  191. package/dist/js/modules/fields/table.d.ts.map +1 -1
  192. package/dist/js/modules/fields/text-limit.d.ts +2 -2
  193. package/dist/js/modules/fields/text-limit.d.ts.map +1 -1
  194. package/dist/js/modules/fields/upload-manager.d.ts +2 -2
  195. package/dist/js/modules/fields/upload-manager.d.ts.map +1 -1
  196. package/dist/js/modules/loader.d.ts +10 -4
  197. package/dist/js/modules/loader.d.ts.map +1 -1
  198. package/dist/js/modules/payments/bpoint.d.ts +1 -1
  199. package/dist/js/modules/payments/bpoint.d.ts.map +1 -1
  200. package/dist/js/modules/payments/eway.d.ts +1 -1
  201. package/dist/js/modules/payments/eway.d.ts.map +1 -1
  202. package/dist/js/modules/payments/factories.d.ts +7 -7
  203. package/dist/js/modules/payments/factories.d.ts.map +1 -1
  204. package/dist/js/modules/payments/go-cardless.d.ts +1 -1
  205. package/dist/js/modules/payments/go-cardless.d.ts.map +1 -1
  206. package/dist/js/modules/payments/index.d.ts +2 -2
  207. package/dist/js/modules/payments/index.d.ts.map +1 -1
  208. package/dist/js/modules/payments/mollie.d.ts +1 -1
  209. package/dist/js/modules/payments/mollie.d.ts.map +1 -1
  210. package/dist/js/modules/payments/moneris.d.ts +1 -1
  211. package/dist/js/modules/payments/moneris.d.ts.map +1 -1
  212. package/dist/js/modules/payments/opayo.d.ts +1 -1
  213. package/dist/js/modules/payments/opayo.d.ts.map +1 -1
  214. package/dist/js/modules/payments/paddle.d.ts +1 -1
  215. package/dist/js/modules/payments/paddle.d.ts.map +1 -1
  216. package/dist/js/modules/payments/paypal.d.ts +1 -1
  217. package/dist/js/modules/payments/paypal.d.ts.map +1 -1
  218. package/dist/js/modules/payments/payway.d.ts +1 -1
  219. package/dist/js/modules/payments/payway.d.ts.map +1 -1
  220. package/dist/js/modules/payments/square.d.ts +1 -1
  221. package/dist/js/modules/payments/square.d.ts.map +1 -1
  222. package/dist/js/modules/payments/stripe.d.ts +1 -1
  223. package/dist/js/modules/payments/stripe.d.ts.map +1 -1
  224. package/dist/js/modules/payments/utils.d.ts +6 -0
  225. package/dist/js/modules/payments/utils.d.ts.map +1 -1
  226. package/dist/js/modules/registry.d.ts +6 -4
  227. package/dist/js/modules/registry.d.ts.map +1 -1
  228. package/dist/js/submit/pipeline.d.ts.map +1 -1
  229. package/dist/js/theme/browser-theme-state.generated.d.ts +24 -0
  230. package/dist/js/theme/browser-theme-state.generated.d.ts.map +1 -0
  231. package/dist/js/theme/theme-classes.d.ts +3 -3
  232. package/dist/js/theme/theme-classes.d.ts.map +1 -1
  233. package/dist/js/transport/forms-api.d.ts +5 -3
  234. package/dist/js/transport/forms-api.d.ts.map +1 -1
  235. package/dist/js/utils/country-from-ip.d.ts +2 -2
  236. package/dist/js/utils/country-from-ip.d.ts.map +1 -1
  237. package/dist/js/utils/csrf.d.ts +17 -0
  238. package/dist/js/utils/csrf.d.ts.map +1 -0
  239. package/dist/js/utils/field-references.parser.d.ts +1 -0
  240. package/dist/js/utils/field-references.parser.d.ts.map +1 -1
  241. package/dist/js/utils/field-references.resolver.d.ts.map +1 -1
  242. package/dist/js/utils/field-references.types.d.ts +1 -0
  243. package/dist/js/utils/field-references.types.d.ts.map +1 -1
  244. package/dist/js/utils/http.d.ts +3 -1
  245. package/dist/js/utils/http.d.ts.map +1 -1
  246. package/dist/js/utils/request-profile.d.ts +4 -0
  247. package/dist/js/utils/request-profile.d.ts.map +1 -0
  248. package/dist/js/utils/unload-warning.d.ts.map +1 -1
  249. package/dist/js/validation/rules/email.d.ts.map +1 -1
  250. package/dist/js/validation/rules/match.d.ts.map +1 -1
  251. package/dist/js/validation/rules/number.d.ts.map +1 -1
  252. package/dist/js/validation/rules/required.d.ts.map +1 -1
  253. package/dist/js/validation/rules/shared.d.ts.map +1 -1
  254. package/dist/js/validation/rules/url.d.ts.map +1 -1
  255. package/dist/js/validation/skip.d.ts +7 -0
  256. package/dist/js/validation/skip.d.ts.map +1 -0
  257. package/dist/js/validation/submit-readiness.d.ts.map +1 -1
  258. package/dist/js/validation/validator.d.ts.map +1 -1
  259. package/package.json +43 -12
  260. package/src/css/formie-base.css +104 -1
  261. package/src/css/theme/_messages.css +2 -0
  262. package/src/css/theme/_tokens.css +31 -25
  263. package/src/css/theme/forms/_form.css +5 -1
  264. package/src/index.ts +13 -8
  265. package/src/js/contracts/client.ts +5 -3
  266. package/src/js/contracts/common.ts +5 -6
  267. package/src/js/contracts/modules.ts +41 -12
  268. package/src/js/contracts/schema.ts +21 -43
  269. package/src/js/contracts/theme.ts +6 -1
  270. package/src/js/core/client-rendered-modules.ts +69 -0
  271. package/src/js/core/create-formie-client.ts +116 -77
  272. package/src/js/core/field-error-aria.ts +93 -0
  273. package/src/js/core/hydrate-modules.ts +54 -29
  274. package/src/js/core/submit-result-state.ts +34 -45
  275. package/src/js/core/submit-result-ui.ts +21 -65
  276. package/src/js/core/validation-focus.ts +20 -20
  277. package/src/js/modules/address/address-finder.ts +1 -1
  278. package/src/js/modules/address/factories.ts +15 -13
  279. package/src/js/modules/address/google-address.ts +10 -6
  280. package/src/js/modules/address/index.ts +2 -2
  281. package/src/js/modules/address/loqate.ts +1 -1
  282. package/src/js/modules/address/place-kit.ts +1 -1
  283. package/src/js/modules/captchas/captcha-eu.ts +2 -2
  284. package/src/js/modules/captchas/factories.ts +66 -42
  285. package/src/js/modules/captchas/friendly-captcha-v1.ts +12 -2
  286. package/src/js/modules/captchas/friendly-captcha-v2.ts +4 -2
  287. package/src/js/modules/captchas/hcaptcha.ts +5 -5
  288. package/src/js/modules/captchas/index.ts +2 -2
  289. package/src/js/modules/captchas/recaptcha-enterprise.ts +2 -2
  290. package/src/js/modules/captchas/recaptcha-v2-checkbox.ts +3 -3
  291. package/src/js/modules/captchas/recaptcha-v2-invisible.ts +2 -2
  292. package/src/js/modules/captchas/recaptcha-v3.ts +2 -2
  293. package/src/js/modules/captchas/snaptcha.ts +1 -1
  294. package/src/js/modules/captchas/turnstile.ts +3 -3
  295. package/src/js/modules/fields/address-country.ts +6 -4
  296. package/src/js/modules/fields/address-state.ts +20 -12
  297. package/src/js/modules/fields/calculations.ts +5 -3
  298. package/src/js/modules/fields/checkbox-radio.ts +24 -42
  299. package/src/js/modules/fields/combobox.ts +25 -9
  300. package/src/js/modules/fields/conditions/config.ts +17 -20
  301. package/src/js/modules/fields/conditions/effects.ts +23 -26
  302. package/src/js/modules/fields/conditions/evaluator.ts +21 -29
  303. package/src/js/modules/fields/conditions/references.ts +16 -5
  304. package/src/js/modules/fields/conditions/submission-context.ts +80 -0
  305. package/src/js/modules/fields/conditions/types.ts +3 -1
  306. package/src/js/modules/fields/conditions/values.ts +31 -6
  307. package/src/js/modules/fields/conditions.ts +59 -18
  308. package/src/js/modules/fields/custom-google-maps.ts +5 -3
  309. package/src/js/modules/fields/custom-link.ts +5 -3
  310. package/src/js/modules/fields/custom-maps.ts +5 -3
  311. package/src/js/modules/fields/date-picker.ts +34 -4
  312. package/src/js/modules/fields/file-upload.ts +19 -10
  313. package/src/js/modules/fields/hidden.ts +5 -3
  314. package/src/js/modules/fields/index.ts +2 -2
  315. package/src/js/modules/fields/password-validation.ts +5 -3
  316. package/src/js/modules/fields/phone-country.ts +33 -6
  317. package/src/js/modules/fields/repeater.ts +5 -3
  318. package/src/js/modules/fields/rich-text.ts +20 -4
  319. package/src/js/modules/fields/shared.ts +13 -0
  320. package/src/js/modules/fields/signature.ts +24 -4
  321. package/src/js/modules/fields/summary.ts +8 -20
  322. package/src/js/modules/fields/survey-likert.ts +5 -3
  323. package/src/js/modules/fields/survey-rank.ts +21 -3
  324. package/src/js/modules/fields/survey-rating.ts +17 -3
  325. package/src/js/modules/fields/table.ts +5 -3
  326. package/src/js/modules/fields/text-limit.ts +5 -3
  327. package/src/js/modules/fields/upload-manager.ts +190 -49
  328. package/src/js/modules/loader.ts +345 -281
  329. package/src/js/modules/payments/bpoint.ts +2 -2
  330. package/src/js/modules/payments/eway.ts +2 -2
  331. package/src/js/modules/payments/factories.ts +53 -52
  332. package/src/js/modules/payments/go-cardless.ts +1 -1
  333. package/src/js/modules/payments/index.ts +2 -2
  334. package/src/js/modules/payments/mollie.ts +1 -1
  335. package/src/js/modules/payments/moneris.ts +2 -2
  336. package/src/js/modules/payments/opayo.ts +21 -8
  337. package/src/js/modules/payments/paddle.ts +10 -6
  338. package/src/js/modules/payments/payment.ts +22 -18
  339. package/src/js/modules/payments/paypal.ts +1 -1
  340. package/src/js/modules/payments/payway.ts +2 -2
  341. package/src/js/modules/payments/square.ts +2 -2
  342. package/src/js/modules/payments/stripe.ts +5 -5
  343. package/src/js/modules/payments/utils.ts +14 -0
  344. package/src/js/modules/registry.ts +19 -11
  345. package/src/js/submit/pipeline.ts +10 -11
  346. package/src/js/theme/browser-theme-state.generated.ts +25 -0
  347. package/src/js/theme/theme-classes.ts +3 -3
  348. package/src/js/transport/forms-api.ts +66 -67
  349. package/src/js/utils/country-from-ip.ts +14 -9
  350. package/src/js/utils/csrf.ts +136 -0
  351. package/src/js/utils/field-references.parser.ts +13 -113
  352. package/src/js/utils/field-references.resolver.ts +27 -64
  353. package/src/js/utils/field-references.row-scope.ts +1 -1
  354. package/src/js/utils/field-references.types.ts +1 -0
  355. package/src/js/utils/http.ts +5 -5
  356. package/src/js/utils/request-profile.ts +10 -0
  357. package/src/js/utils/unload-warning.ts +12 -4
  358. package/src/js/validation/rules/email.ts +3 -5
  359. package/src/js/validation/rules/match.ts +2 -1
  360. package/src/js/validation/rules/minmax.ts +4 -43
  361. package/src/js/validation/rules/number.ts +3 -47
  362. package/src/js/validation/rules/pattern.ts +3 -8
  363. package/src/js/validation/rules/required.ts +2 -1
  364. package/src/js/validation/rules/shared.ts +5 -1
  365. package/src/js/validation/rules/url.ts +3 -10
  366. package/src/js/validation/skip.ts +9 -0
  367. package/src/js/validation/submit-readiness.ts +9 -2
  368. package/src/js/validation/validator.ts +35 -59
  369. package/dist/chunks/calculations-Dv3hYb8_.js +0 -299
  370. package/dist/chunks/conditions-CPH1snCx.js +0 -424
  371. package/dist/chunks/country-from-ip-BwxKaBuJ.js +0 -26
  372. package/dist/chunks/field-references.resolver-CHwn0G0L.js +0 -145
  373. package/dist/chunks/friendly-captcha-v1-C_2reOXr.js +0 -31
  374. package/dist/chunks/google-address-BH3Zhi06.js +0 -161
  375. package/dist/chunks/http-D-JExro7.js +0 -27
  376. package/dist/chunks/opayo-CR0DtsLa.js +0 -179
  377. package/dist/chunks/rich-text-Bg_--4TG.js +0 -349
  378. package/dist/js/modules/fields/conditions/transforms.d.ts +0 -3
  379. package/dist/js/modules/fields/conditions/transforms.d.ts.map +0 -1
  380. package/src/js/modules/fields/conditions/transforms.ts +0 -206
  381. package/src/js/modules/payments/stub-payment-module.ts +0 -87
@@ -0,0 +1,136 @@
1
+ export type FormCsrfToken = {
2
+ name: string;
3
+ value: string;
4
+ };
5
+
6
+ type CraftGlobal = {
7
+ csrfTokenName?: string;
8
+ csrfTokenValue?: string;
9
+ };
10
+
11
+ const DEFAULT_CRAFT_CSRF_TOKEN_NAME = 'CRAFT_CSRF_TOKEN';
12
+ const FORMIE_CSRF_PARAM_ATTR = 'data-formie-csrf-param';
13
+ const FORMIE_CSRF_INPUT_ATTR = 'data-formie-csrf';
14
+
15
+ function getCraftCsrfTokenName(): string | null {
16
+ const craft = (globalThis as { Craft?: CraftGlobal }).Craft;
17
+ const name = craft?.csrfTokenName;
18
+
19
+ return typeof name === 'string' && name.trim() ? name.trim() : null;
20
+ }
21
+
22
+ function escapeAttributeSelectorValue(value: string): string {
23
+ if (typeof CSS !== 'undefined' && typeof CSS.escape === 'function') {
24
+ return CSS.escape(value);
25
+ }
26
+
27
+ // Attribute-selector fallback for environments without CSS.escape.
28
+ return value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
29
+ }
30
+
31
+ function queryNamedInput(root: ParentNode, name: string): HTMLInputElement | null {
32
+ const input = root.querySelector(`input[name="${escapeAttributeSelectorValue(name)}"]`);
33
+
34
+ return input instanceof HTMLInputElement ? input : null;
35
+ }
36
+
37
+ /**
38
+ * Resolve the Craft CSRF hidden input for a Formie form.
39
+ *
40
+ * Prefer Formie markers / declared param names so custom `csrfTokenName`
41
+ * values in `config/general.php` keep working. Fall back to Craft's CP
42
+ * global and the default token name for older or custom templates.
43
+ */
44
+ export function getFormCsrfInput(form: ParentNode | null | undefined): HTMLInputElement | null {
45
+ if (!form) {
46
+ return null;
47
+ }
48
+
49
+ const marked = form.querySelector(`input[${FORMIE_CSRF_INPUT_ATTR}]`);
50
+
51
+ if (marked instanceof HTMLInputElement && marked.name.trim()) {
52
+ return marked;
53
+ }
54
+
55
+ if (form instanceof Element) {
56
+ const declaredParam = form.getAttribute(FORMIE_CSRF_PARAM_ATTR)?.trim();
57
+
58
+ if (declaredParam) {
59
+ const declaredInput = queryNamedInput(form, declaredParam);
60
+
61
+ if (declaredInput) {
62
+ return declaredInput;
63
+ }
64
+ }
65
+ }
66
+
67
+ const craftName = getCraftCsrfTokenName();
68
+
69
+ if (craftName) {
70
+ const craftInput = queryNamedInput(form, craftName);
71
+
72
+ if (craftInput) {
73
+ return craftInput;
74
+ }
75
+ }
76
+
77
+ return queryNamedInput(form, DEFAULT_CRAFT_CSRF_TOKEN_NAME);
78
+ }
79
+
80
+ export function getFormCsrfToken(form: ParentNode | null | undefined): FormCsrfToken | null {
81
+ const input = getFormCsrfInput(form);
82
+ const name = input?.name?.trim() || '';
83
+ const value = input?.value?.trim() || '';
84
+
85
+ if (!name || !value) {
86
+ return null;
87
+ }
88
+
89
+ return { name, value };
90
+ }
91
+
92
+ export function appendFormCsrfToFormData(body: FormData, form: ParentNode | null | undefined): void {
93
+ const csrf = getFormCsrfToken(form);
94
+
95
+ if (csrf) {
96
+ body.append(csrf.name, csrf.value);
97
+ }
98
+ }
99
+
100
+ export function applyFormCsrfToRecord(target: Record<string, string>, form: ParentNode | null | undefined): void {
101
+ const csrf = getFormCsrfToken(form);
102
+
103
+ if (csrf) {
104
+ target[csrf.name] = csrf.value;
105
+ }
106
+ }
107
+
108
+ export function isFormCsrfFieldName(name: string, form?: ParentNode | null): boolean {
109
+ const normalizedName = name.endsWith('[]') ? name.slice(0, -2) : name;
110
+
111
+ if (!normalizedName) {
112
+ return false;
113
+ }
114
+
115
+ if (normalizedName === DEFAULT_CRAFT_CSRF_TOKEN_NAME) {
116
+ return true;
117
+ }
118
+
119
+ const craftName = getCraftCsrfTokenName();
120
+
121
+ if (craftName && normalizedName === craftName) {
122
+ return true;
123
+ }
124
+
125
+ if (form instanceof Element) {
126
+ const declaredParam = form.getAttribute(FORMIE_CSRF_PARAM_ATTR)?.trim();
127
+
128
+ if (declaredParam && normalizedName === declaredParam) {
129
+ return true;
130
+ }
131
+ }
132
+
133
+ const csrf = getFormCsrfToken(form);
134
+
135
+ return !!csrf && normalizedName === csrf.name;
136
+ }
@@ -1,121 +1,21 @@
1
- import type { FieldReferenceTransform, ParsedFieldReference } from '#utils/field-references.types';
1
+ import { parseReference } from '@verbb/formie-core';
2
+ import type { ParsedFieldReference } from '#utils/field-references.types';
2
3
  import { normalizeFieldKey } from '#utils/field-references.keys';
3
4
 
4
- function parseTransforms(body: string): { source: string; transforms: FieldReferenceTransform[] } {
5
- const parts = body.split(';').map((part) => {
6
- return part.trim();
7
- }).filter(Boolean);
8
-
9
- if (!parts.length) {
10
- return {
11
- source: '',
12
- transforms: [],
13
- };
14
- }
15
-
16
- const [source, ...metadata] = parts;
17
- const transforms: FieldReferenceTransform[] = [];
18
- let current: FieldReferenceTransform | null = null;
19
-
20
- metadata.forEach((entry) => {
21
- if (entry.startsWith('transform=')) {
22
- if (current) {
23
- transforms.push(current);
24
- }
25
-
26
- current = {
27
- id: decodeURIComponent(entry.slice('transform='.length) || '').trim(),
28
- params: {},
29
- };
30
- return;
31
- }
32
-
33
- if (!current || !entry.includes('=')) {
34
- return;
35
- }
36
-
37
- const [rawKey, rawValue] = entry.split('=', 2);
38
- const key = (rawKey || '').trim();
39
-
40
- if (!key || key === 'transform') {
41
- return;
42
- }
43
-
44
- current.params[key] = decodeURIComponent(rawValue || '').trim();
45
- });
46
-
47
- if (current) {
48
- transforms.push(current);
49
- }
50
-
51
- return {
52
- source: source || '',
53
- transforms,
54
- };
55
- }
56
-
5
+ /** Browser field slots adapt the shared grammar; plain keys are legacy field operands. */
57
6
  export function parseFieldReference(rawValue: string): ParsedFieldReference {
58
7
  const raw = String(rawValue || '').trim();
59
-
60
- if (!raw) {
61
- return {
62
- raw,
63
- target: '',
64
- key: '',
65
- selector: '',
66
- defaultValue: '',
67
- transforms: [],
68
- isToken: false,
69
- isValid: false,
70
- };
71
- }
72
-
73
- const tokenMatch = raw.match(/^\{([a-zA-Z]+)(?::(.*))?\}$/);
74
-
75
- if (!tokenMatch) {
76
- return {
77
- raw,
78
- target: '',
79
- key: normalizeFieldKey(raw),
80
- selector: '',
81
- defaultValue: '',
82
- transforms: [],
83
- isToken: false,
84
- isValid: true,
85
- };
86
- }
87
-
88
- const targetRaw = (tokenMatch[1] || '').trim().toLowerCase();
89
- const bodyRaw = (tokenMatch[2] || '').trim();
90
- const [beforeDefault, defaultRaw = ''] = bodyRaw.split('|', 2);
91
- const { source, transforms } = parseTransforms(beforeDefault || '');
92
-
93
- if (targetRaw !== 'field') {
94
- return {
95
- raw,
96
- target: '',
97
- key: '',
98
- selector: '',
99
- defaultValue: defaultRaw.trim(),
100
- transforms,
101
- isToken: true,
102
- isValid: false,
103
- };
104
- }
105
-
106
- const separatorIndex = source.indexOf(':');
107
- const keyRaw = separatorIndex === -1 ? source : source.slice(0, separatorIndex);
108
- const selectorRaw = separatorIndex === -1 ? '' : source.slice(separatorIndex + 1);
109
- const key = normalizeFieldKey(keyRaw);
110
-
8
+ const expression = parseReference(raw);
9
+ const isToken = raw.startsWith('{');
10
+ const field = expression.isValid && expression.target === 'field';
111
11
  return {
112
12
  raw,
113
- target: 'field',
114
- key,
115
- selector: selectorRaw.trim(),
116
- defaultValue: defaultRaw.trim(),
117
- transforms,
118
- isToken: true,
119
- isValid: key !== '',
13
+ target: field ? 'field' : '',
14
+ key: field ? normalizeFieldKey(expression.identifier) : (isToken ? '' : normalizeFieldKey(raw)),
15
+ selector: expression.selector,
16
+ defaultValue: expression.default,
17
+ transforms: expression.transformerId ? [{ id: expression.transformerId, params: expression.transformerParams }] : [],
18
+ isToken,
19
+ isValid: isToken ? field : raw !== '',
120
20
  };
121
21
  }
@@ -1,3 +1,4 @@
1
+ import { parseReference, resolveReference } from '@verbb/formie-core';
1
2
  import { fieldKeyToInputName, normalizeFieldKey } from '#utils/field-references.keys';
2
3
  import { parseFieldReference } from '#utils/field-references.parser';
3
4
  import type {
@@ -42,74 +43,36 @@ function getEntry(registry: FieldValueRegistry, key: string) {
42
43
  return registry.get(normalizeFieldKey(key)) || null;
43
44
  }
44
45
 
45
- export function resolveFieldReferenceLive(
46
- reference: string,
47
- registry: FieldValueRegistry,
48
- ): ResolveFieldValueResult {
46
+ function resolvedProjection(reference: string, key: string, value: string | string[]): ResolveFieldValueResult {
47
+ const token = reference.trim().startsWith('{') ? reference : `{field:${encodeURIComponent(key)}}`;
48
+ const expression = parseReference(token);
49
+ const id = `field:${expression.identifier}`;
50
+ const valueId = expression.selector ? `${id}:${expression.selector}` : id;
51
+ const resolved = resolveReference(token, {
52
+ definitions: { [id]: { id, selectors: expression.selector ? [expression.selector] : [], availability: { server: true, browser: true } } },
53
+ values: { [valueId]: value },
54
+ });
55
+ return { key, value: resolved.diagnostic ? '' : resolved.value as string | string[], found: !resolved.diagnostic, diagnostic: resolved.diagnostic };
56
+ }
57
+
58
+ export function resolveFieldReferenceLive(reference: string, registry: FieldValueRegistry): ResolveFieldValueResult {
49
59
  const parsed = parseFieldReference(reference);
50
60
  const key = parsed.key;
51
- const entry = getEntry(registry, key);
52
-
53
- if (!entry) {
54
- return {
55
- key,
56
- value: parsed.defaultValue,
57
- found: false,
58
- };
59
- }
60
-
61
- const value = readInputsValue(entry.inputs);
62
-
63
- return {
64
- key,
65
- value: value === '' && parsed.defaultValue !== '' ? parsed.defaultValue : value,
66
- found: true,
67
- };
61
+ const lookup = parsed.selector ? `${key}.${parsed.selector.replace(/:/g, '.')}` : key;
62
+ const entry = parsed.isValid ? getEntry(registry, lookup) : null;
63
+ if (!entry) return { key, value: '', found: false, diagnostic: !parsed.isValid ? 'invalidExpression' : parsed.selector ? 'invalidSelector' : 'missingField' };
64
+ return resolvedProjection(reference, key, readInputsValue(entry.inputs));
68
65
  }
69
66
 
70
- export function resolveFieldReferenceFromFormData(
71
- reference: string,
72
- formData: FormData,
73
- registry?: FieldValueRegistry,
74
- ): ResolveFieldValueResult {
67
+ export function resolveFieldReferenceFromFormData(reference: string, formData: FormData, registry?: FieldValueRegistry): ResolveFieldValueResult {
75
68
  const parsed = parseFieldReference(reference);
76
69
  const key = parsed.key;
77
-
78
- if (!key) {
79
- return {
80
- key,
81
- value: parsed.defaultValue,
82
- found: false,
83
- };
84
- }
85
-
86
- const entry = registry ? getEntry(registry, key) : null;
87
- const names = entry?.names?.length ? entry.names : [fieldKeyToInputName(key)];
88
- const values = names.flatMap((name) => {
89
- const collected = formData.getAll(name).map((value) => {
90
- return String(value ?? '');
91
- });
92
-
93
- if (collected.length) {
94
- return collected;
95
- }
96
-
97
- return formData.getAll(`${name}[]`).map((value) => {
98
- return String(value ?? '');
99
- });
100
- }).filter((value) => value !== '');
101
-
102
- if (!values.length) {
103
- return {
104
- key,
105
- value: parsed.defaultValue,
106
- found: false,
107
- };
108
- }
109
-
110
- return {
111
- key,
112
- value: values.length > 1 ? values : values[0],
113
- found: true,
114
- };
70
+ const lookup = parsed.selector ? `${key}.${parsed.selector.replace(/:/g, '.')}` : key;
71
+ const entry = registry ? getEntry(registry, lookup) : null;
72
+ if (!parsed.isValid || (registry && !entry)) return { key, value: '', found: false, diagnostic: parsed.isValid ? 'missingField' : 'invalidExpression' };
73
+ const names = entry?.names?.length ? entry.names : [fieldKeyToInputName(lookup)];
74
+ const present = !!entry || names.some((name) => formData.has(name) || formData.has(`${name}[]`));
75
+ if (!present) return { key, value: '', found: false, diagnostic: 'missingField' };
76
+ const values = names.flatMap((name) => [...formData.getAll(name), ...formData.getAll(`${name}[]`)]).map((value) => String(value ?? ''));
77
+ return resolvedProjection(reference, key, values.length > 1 ? values : values[0] ?? '');
115
78
  }
@@ -78,7 +78,7 @@ export function parseRowsExpression(expression: string, rowCount: number): numbe
78
78
  [start, end] = [end, start];
79
79
  }
80
80
 
81
- for (let row = start; row <= end; row++) {
81
+ for (let row = Math.max(1, start); row <= Math.min(rowCount, end); row++) {
82
82
  if (row >= 1 && row <= rowCount) {
83
83
  indices.push(row - 1);
84
84
  }
@@ -28,4 +28,5 @@ export type ResolveFieldValueResult = {
28
28
  key: string;
29
29
  value: string | string[];
30
30
  found: boolean;
31
+ diagnostic?: string;
31
32
  };
@@ -1,11 +1,12 @@
1
- export type RequestJsonOptions = {
1
+ import { browserRequest, type BrowserRequestOptions } from '@verbb/formie-core';
2
+ export type RequestJsonOptions = BrowserRequestOptions & {
2
3
  method?: string;
3
4
  body?: BodyInit | null;
4
5
  headers?: Record<string, string>;
5
6
  signal?: AbortSignal;
6
7
  };
7
8
 
8
- async function request(url: string | URL, options: RequestJsonOptions = {}): Promise<Response> {
9
+ export async function request(url: string | URL, options: RequestJsonOptions = {}): Promise<Response> {
9
10
  // Do not send `X-Requested-With` here: it is not CORS-safelisted, and Craft GraphQL CORS
10
11
  // often omits it from `Access-Control-Allow-Headers` (breaks localhost → ddev, starters, etc.).
11
12
  // `Accept` + JSON `Content-Type` are enough for Formie/Craft JSON endpoints.
@@ -16,7 +17,7 @@ async function request(url: string | URL, options: RequestJsonOptions = {}): Pro
16
17
  delete headers['X-Requested-With'];
17
18
  delete headers['x-requested-with'];
18
19
 
19
- return fetch(String(url), {
20
+ return browserRequest(String(url), {
20
21
  method: options.method || 'GET',
21
22
  body: options.body ?? null,
22
23
  signal: options.signal,
@@ -26,8 +27,7 @@ async function request(url: string | URL, options: RequestJsonOptions = {}): Pro
26
27
  // `include` + `Access-Control-Allow-Origin: *` is invalid; many Craft GraphQL setups use `*`.
27
28
  // `same-origin` keeps cookies for same-host deployments and avoids credentialed cross-origin
28
29
  // fetches (e.g. Vite on localhost → ddev HTTPS) so wildcard CORS can succeed.
29
- credentials: 'same-origin',
30
- });
30
+ }, options);
31
31
  }
32
32
 
33
33
  export async function requestJson<T>(url: string | URL, options: RequestJsonOptions = {}): Promise<T> {
@@ -0,0 +1,10 @@
1
+ import type { BrowserRequestOptions } from '@verbb/formie-core';
2
+
3
+ const formRequests = new WeakMap<HTMLFormElement, BrowserRequestOptions>();
4
+ export function setFormBrowserRequestOptions(form: HTMLFormElement, options: BrowserRequestOptions): void {
5
+ formRequests.set(form, { ...options });
6
+ form.dataset.formieRequestProfile = options.profile ?? 'same-origin-browser';
7
+ }
8
+ export function getFormBrowserRequestOptions(form: HTMLFormElement | null | undefined): BrowserRequestOptions {
9
+ return form && formRequests.get(form) || { profile: form?.dataset.formieRequestProfile as BrowserRequestOptions['profile'] };
10
+ }
@@ -1,15 +1,17 @@
1
+ import { isFormCsrfFieldName } from '#utils/csrf';
2
+
1
3
  const DIRTY_TRACKING_IGNORED_FIELD_NAMES = new Set([
2
- 'CRAFT_CSRF_TOKEN',
3
4
  'action',
4
5
  'redirect',
5
6
  'requestToken',
7
+ 'uploadCreateToken',
6
8
  'renderId',
7
9
  'formStartedAt',
8
10
  'submitAction',
9
11
  'pageId',
10
12
  'draftContextToken',
11
13
  'draftContext',
12
- 'continuationToken',
14
+ 'progressId',
13
15
  ]);
14
16
 
15
17
  function serializeStableValue(value: unknown, seen: WeakSet<object>): string {
@@ -64,19 +66,25 @@ function stableSerialize(value: unknown): string {
64
66
  return serializeStableValue(value, new WeakSet<object>());
65
67
  }
66
68
 
67
- function shouldTrackFieldName(name: string): boolean {
69
+ function shouldTrackFieldName(name: string, form: HTMLFormElement): boolean {
68
70
  if (!name) {
69
71
  return false;
70
72
  }
71
73
 
72
74
  const normalizedName = name.endsWith('[]') ? name.slice(0, -2) : name;
73
75
 
76
+ // Ignore CSRF regardless of custom csrfTokenName so token refresh
77
+ // does not mark the form dirty.
78
+ if (isFormCsrfFieldName(normalizedName, form)) {
79
+ return false;
80
+ }
81
+
74
82
  return !DIRTY_TRACKING_IGNORED_FIELD_NAMES.has(normalizedName);
75
83
  }
76
84
 
77
85
  function buildTrackedSnapshot(form: HTMLFormElement): string {
78
86
  const entries = Array.from(new FormData(form).entries()).filter(([name]) => {
79
- return shouldTrackFieldName(String(name || ''));
87
+ return shouldTrackFieldName(String(name || ''), form);
80
88
  });
81
89
 
82
90
  return stableSerialize(entries);
@@ -1,12 +1,10 @@
1
+ import { validateBrowserValue } from '@verbb/formie-core';
1
2
  import type { ValidationRuleDefinition } from '#validation/types';
2
3
 
3
4
  const email: ValidationRuleDefinition = {
4
5
  rule: ({ input, getRule }) => {
5
- if (!getRule('email') || !input.value || input.value.length < 1) {
6
- return true;
7
- }
8
-
9
- return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(input.value);
6
+ const rule = getRule('email');
7
+ return !rule || validateBrowserValue(input.value, { ...(typeof rule === 'object' ? rule : {}), type: 'email' }) === null;
10
8
  },
11
9
  message: ({ input, label, t }) => {
12
10
  return input.getAttribute('data-formie-validation-email-message')
@@ -1,3 +1,4 @@
1
+ import { validateBrowserValue } from '@verbb/formie-core';
1
2
  import type { ValidationRuleDefinition } from '#validation/types';
2
3
  import { getComparableInput, getLabelText } from '#validation/rules/shared';
3
4
 
@@ -9,7 +10,7 @@ const match: ValidationRuleDefinition = {
9
10
  return true;
10
11
  }
11
12
 
12
- return sourceInput.value === ctx.input.value;
13
+ return validateBrowserValue(ctx.input.value, { type: 'match' }, { comparison: sourceInput.value }) === null;
13
14
  },
14
15
  message: (ctx) => {
15
16
  const sourceInput = getComparableInput(ctx);
@@ -1,47 +1,8 @@
1
+ import { validateBrowserValue } from '@verbb/formie-core';
1
2
  import type { ValidationRuleDefinition } from '#validation/types';
2
-
3
+ const bounds = (input: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement) => ({ type: 'number', min: input.hasAttribute('min') ? Number(input.getAttribute('min')) : null, max: input.hasAttribute('max') ? Number(input.getAttribute('max')) : null });
3
4
  const minmax: ValidationRuleDefinition = {
4
- rule: ({ input }) => {
5
- if (input.type !== 'number' || input.value.trim() === '') {
6
- return true;
7
- }
8
-
9
- const value = parseFloat(input.value);
10
- const min = input.hasAttribute('min') ? parseFloat(input.getAttribute('min') || '') : null;
11
- const max = input.hasAttribute('max') ? parseFloat(input.getAttribute('max') || '') : null;
12
-
13
- if (Number.isNaN(value)) {
14
- return false;
15
- }
16
-
17
- if (min !== null && value < min) {
18
- return false;
19
- }
20
-
21
- if (max !== null && value > max) {
22
- return false;
23
- }
24
-
25
- return true;
26
- },
27
- message: ({ input, label, t }) => {
28
- const min = input.hasAttribute('min') ? parseFloat(input.getAttribute('min') || '') : null;
29
- const max = input.hasAttribute('max') ? parseFloat(input.getAttribute('max') || '') : null;
30
-
31
- if (min !== null && max !== null) {
32
- return t('{label} must be no less than {min}.', { label, min });
33
- }
34
-
35
- if (min !== null) {
36
- return t('{label} must be no less than {min}.', { label, min });
37
- }
38
-
39
- if (max !== null) {
40
- return t('{label} must be no greater than {max}.', { label, max });
41
- }
42
-
43
- return t('{label} is not a valid number.', { label });
44
- },
5
+ rule: ({ input }) => input.type !== 'number' || validateBrowserValue(input.value, bounds(input)) === null,
6
+ message: ({ input, label, t }) => validateBrowserValue(input.value, bounds(input), { label }) ?? t('{label} is not a valid number.', { label }),
45
7
  };
46
-
47
8
  export default minmax;
@@ -1,58 +1,14 @@
1
+ import { validateBrowserValue } from '@verbb/formie-core';
1
2
  import type { ValidationRuleDefinition } from '#validation/types';
2
3
 
3
4
  const number: ValidationRuleDefinition = {
4
5
  rule: ({ input, getRule }) => {
5
6
  const rule = getRule('number');
6
-
7
- if (!rule || !input.value || input.value.trim() === '') {
8
- return true;
9
- }
10
-
11
- const value = parseFloat(input.value);
12
-
13
- if (Number.isNaN(value)) {
14
- return false;
15
- }
16
-
17
- if (rule !== true && typeof rule === 'object') {
18
- const min = typeof rule.min === 'number' ? rule.min : null;
19
- const max = typeof rule.max === 'number' ? rule.max : null;
20
-
21
- if (min !== null && value < min) {
22
- return false;
23
- }
24
-
25
- if (max !== null && value > max) {
26
- return false;
27
- }
28
- }
29
-
30
- return true;
7
+ return !rule || validateBrowserValue(input.value, { ...(typeof rule === 'object' ? rule : {}), type: 'number' }) === null;
31
8
  },
32
9
  message: ({ input, label, getRule, t }) => {
33
10
  const rule = getRule('number');
34
- const min = rule !== true && rule && typeof rule === 'object' && typeof rule.min === 'number' ? rule.min : null;
35
- const max = rule !== true && rule && typeof rule === 'object' && typeof rule.max === 'number' ? rule.max : null;
36
-
37
- if (min !== null && max !== null) {
38
- return input.getAttribute('data-formie-validation-number-min-message')
39
- ?? t('{label} must be no less than {min}.', { label, min });
40
- }
41
-
42
- if (min !== null) {
43
- return input.getAttribute('data-formie-validation-number-min-message')
44
- ?? t('{label} must be no less than {min}.', { label, min });
45
- }
46
-
47
- if (max !== null) {
48
- return input.getAttribute('data-formie-validation-number-max-message')
49
- ?? t('{label} must be no greater than {max}.', { label, max });
50
- }
51
-
52
- return input.getAttribute('data-formie-validation-number-message')
53
- ?? input.getAttribute('data-formie-pattern-number-message')
54
- ?? input.getAttribute('data-pattern-number-message')
55
- ?? t('{label} is not a valid number.', { label });
11
+ return validateBrowserValue(input.value, { ...(typeof rule === 'object' ? rule : {}), type: 'number' }, { label }) ?? t('{label} is not a valid number.', { label });
56
12
  },
57
13
  };
58
14
 
@@ -1,15 +1,10 @@
1
+ import { validateBrowserValue } from '@verbb/formie-core';
1
2
  import type { ValidationRuleDefinition } from '#validation/types';
2
3
 
3
4
  const pattern: ValidationRuleDefinition = {
4
5
  rule: ({ input, config }) => {
5
- const rawPattern = input.getAttribute('pattern');
6
- const patternToMatch = rawPattern ? new RegExp(`^(?:${rawPattern})$`) : config.patterns[input.type];
7
-
8
- if (!patternToMatch || !input.value || input.value.length < 1) {
9
- return true;
10
- }
11
-
12
- return patternToMatch.test(input.value);
6
+ const pattern = input.getAttribute('pattern') || config.patterns[input.type];
7
+ return validateBrowserValue(input.value, { type: 'pattern', pattern }) === null;
13
8
  },
14
9
  message: ({ input, label, t }) => {
15
10
  const messages = {
@@ -1,3 +1,4 @@
1
+ import { validateBrowserValue } from '@verbb/formie-core';
1
2
  import type { ValidationRuleDefinition } from '#validation/types';
2
3
 
3
4
  const required: ValidationRuleDefinition = {
@@ -18,7 +19,7 @@ const required: ValidationRuleDefinition = {
18
19
  return input instanceof HTMLInputElement ? input.checked : true;
19
20
  }
20
21
 
21
- return input.value.trim() !== '';
22
+ return validateBrowserValue(input.value, { type: 'required' }) === null;
22
23
  },
23
24
  message: ({ input, label, t }) => {
24
25
  return input.getAttribute('data-formie-required-message')