@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
@@ -11,7 +11,7 @@ import {
11
11
  // invisible/score flows is that we never trigger execution ourselves; the user
12
12
  // must solve the already-rendered widget before submit succeeds.
13
13
  export const recaptchaV2CheckboxModule = defineCaptchaModule<RecaptchaProviderOptions, RecaptchaGlobal, number | string>({
14
- id: 'recaptcha-v2-checkbox',
14
+ moduleId: 'formie:recaptcha-v2-checkbox',
15
15
  defaultPlaceholderSelector: '[data-recaptcha-placeholder]',
16
16
  defaultTokenFieldNames: ['g-recaptcha-response'],
17
17
  load: ({ options }) => {
@@ -29,7 +29,7 @@ export const recaptchaV2CheckboxModule = defineCaptchaModule<RecaptchaProviderOp
29
29
  callback: (token?: string) => {
30
30
  // Checkbox mode solves interactively before submit, so
31
31
  // the callback is the point where the transport layer
32
- // finally becomes "screen-stage ready".
32
+ // finally becomes "challenge-stage ready".
33
33
  if (typeof token === 'string' && token.trim() !== '') {
34
34
  services.tokens.write(token.trim());
35
35
  }
@@ -47,7 +47,7 @@ export const recaptchaV2CheckboxModule = defineCaptchaModule<RecaptchaProviderOp
47
47
  });
48
48
  });
49
49
  },
50
- screen: ({ placeholder, services, stageCtx }) => {
50
+ challenge: ({ placeholder, services, stageCtx }) => {
51
51
  // Checkbox mode does not execute at submit time. We simply check if the
52
52
  // user already solved it; if not, abort immediately with a field-style
53
53
  // error and let the user interact with the widget.
@@ -35,7 +35,7 @@ async function waitForRecaptchaResponse(api: RecaptchaGlobal, widgetId: number |
35
35
  }
36
36
 
37
37
  export const recaptchaV2InvisibleModule = defineCaptchaModule<RecaptchaProviderOptions, RecaptchaGlobal, RecaptchaWidgetState>({
38
- id: 'recaptcha-v2-invisible',
38
+ moduleId: 'formie:recaptcha-v2-invisible',
39
39
  defaultPlaceholderSelector: '[data-recaptcha-placeholder]',
40
40
  defaultTokenFieldNames: ['g-recaptcha-response'],
41
41
  load: ({ options }) => {
@@ -79,7 +79,7 @@ export const recaptchaV2InvisibleModule = defineCaptchaModule<RecaptchaProviderO
79
79
  });
80
80
  });
81
81
  },
82
- screen: async({ api, widget, placeholder, services, stageCtx }) => {
82
+ challenge: async({ api, widget, placeholder, services, stageCtx }) => {
83
83
  // If we already have a token, do not re-execute the invisible widget.
84
84
  if (services.tokens.has()) {
85
85
  return;
@@ -13,7 +13,7 @@ import {
13
13
  // instance so it can participate in the same submit lifecycle as other
14
14
  // providers, but most of the work happens at screen time.
15
15
  export const recaptchaV3Module = defineCaptchaModule<RecaptchaProviderOptions, RecaptchaGlobal, number | string>({
16
- id: 'recaptcha-v3',
16
+ moduleId: 'formie:recaptcha-v3',
17
17
  defaultPlaceholderSelector: '[data-recaptcha-placeholder]',
18
18
  defaultTokenFieldNames: ['g-recaptcha-response'],
19
19
  load: ({ options }) => {
@@ -31,7 +31,7 @@ export const recaptchaV3Module = defineCaptchaModule<RecaptchaProviderOptions, R
31
31
  });
32
32
  });
33
33
  },
34
- screen: async({ api, provider, placeholder, services, stageCtx }) => {
34
+ challenge: async({ api, provider, placeholder, services, stageCtx }) => {
35
35
  // If a token already exists we can skip execution, which matters for
36
36
  // re-renders or multi-step flows where the same challenge was already
37
37
  // completed very recently.
@@ -5,6 +5,6 @@ import { definePassiveCaptchaModule } from '#modules/captchas/api';
5
5
  // good fit here because the provider is really just about keeping a hidden
6
6
  // transport value in sync across renders and token refreshes.
7
7
  export const snaptchaModule = definePassiveCaptchaModule({
8
- id: 'snaptcha',
8
+ moduleId: 'formie:snaptcha',
9
9
  defaultPlaceholderSelector: '[data-snaptcha-captcha-placeholder]',
10
10
  });
@@ -51,7 +51,7 @@ async function loadTurnstileGlobal(options: TurnstileProviderOptions): Promise<T
51
51
  }
52
52
 
53
53
  export const turnstileModule = defineCaptchaModule<TurnstileProviderOptions, TurnstileGlobal, string>({
54
- id: 'turnstile',
54
+ moduleId: 'formie:turnstile',
55
55
  defaultPlaceholderSelector: '[data-turnstile-placeholder]',
56
56
  defaultTokenFieldNames: ['cf-turnstile-response'],
57
57
  load: ({ options }) => {
@@ -102,7 +102,7 @@ export const turnstileModule = defineCaptchaModule<TurnstileProviderOptions, Tur
102
102
  },
103
103
  });
104
104
  },
105
- screen: ({ api, widget, placeholder, services, provider, stageCtx }) => {
105
+ challenge: ({ api, widget, placeholder, services, provider, stageCtx }) => {
106
106
  // Submit-time rule: if a valid token already exists, do nothing. This
107
107
  // covers cases where Turnstile solved itself on load or before submit.
108
108
  if (services.tokens.has()) {
@@ -115,7 +115,7 @@ export const turnstileModule = defineCaptchaModule<TurnstileProviderOptions, Tur
115
115
  api.execute(widget);
116
116
  return services.tokens.wait(getTurnstileWaitForValueMs(provider)).then((hasToken) => {
117
117
  if (!hasToken) {
118
- // No token arrived in time, so block the screen stage and show
118
+ // No token arrived in time, so block the challenge stage and show
119
119
  // the shared themed inline error next to the active placeholder.
120
120
  const message = services.errors.getDefaultMessage();
121
121
  services.errors.show(message, placeholder);
@@ -1,4 +1,4 @@
1
- import type { FormieModuleDefinition } from '#contracts/modules';
1
+ import type { BrowserModuleDefinition } from '#contracts/modules';
2
2
  import { ADDRESS_SELECTORS, findAddressFieldInput } from '#modules/address/constants';
3
3
  import { getModuleFieldContainers } from '#modules/fields/shared';
4
4
  import { fetchCountryFromIp } from '#utils/country-from-ip';
@@ -85,7 +85,7 @@ async function preselectCountry(
85
85
  return;
86
86
  }
87
87
 
88
- const response = await fetchCountryFromIp(options.countryFromIpAction);
88
+ const response = await fetchCountryFromIp(options.countryFromIpAction, addressRoot.closest('form'));
89
89
 
90
90
  if (!response?.countryCode) {
91
91
  return;
@@ -116,8 +116,10 @@ async function preselectCountry(
116
116
  debug.log('Preselected country from IP.', { selectValue });
117
117
  }
118
118
 
119
- export const addressCountryModule: FormieModuleDefinition = {
120
- id: MODULE_ID,
119
+ export const addressCountryModule: BrowserModuleDefinition = {
120
+ moduleId: `formie:${MODULE_ID}`,
121
+ version: 2,
122
+ surfaces: ['server-rendered', 'client-rendered', 'cp-edit'],
121
123
  kind: 'field',
122
124
  match: (ctx) => {
123
125
  return !!ctx.target.querySelector(COUNTRY_SELECTOR);
@@ -1,7 +1,10 @@
1
- import type { FormieModuleDefinition } from '#contracts/modules';
1
+ import { browserRequest, type BrowserRequestOptions } from '@verbb/formie-core';
2
+ import { getFormBrowserRequestOptions } from '#utils/request-profile';
3
+ import type { BrowserModuleDefinition } from '#contracts/modules';
2
4
  import { ADDRESS_SELECTORS } from '#modules/address/constants';
3
5
  import { initFormieCombobox } from '#modules/fields/combobox';
4
6
  import { dispatchFieldEvent, getModuleFieldContainers } from '#modules/fields/shared';
7
+ import { getThemeClasses, toggleThemeClasses } from '#theme/theme-classes';
5
8
  import { createDebug } from '#utils/debug';
6
9
 
7
10
  const STATE_DYNAMIC_SELECTOR = '[data-formie-address-state-dynamic]';
@@ -212,7 +215,7 @@ function reconcileAutofillValue(fieldState: FieldState): void {
212
215
  }
213
216
 
214
217
  function buildSubdivisionsUrl(action: string, country: string, optionLabel: string, optionValue: string): string {
215
- const url = new URL(action.startsWith('/') ? action : `/actions/${action}`, window.location.origin);
218
+ const url = new URL(/^https?:\/\//.test(action) || action.startsWith('/') ? action : `/actions/${action}`, window.location.origin);
216
219
  url.searchParams.set('country', country);
217
220
  url.searchParams.set('optionLabel', optionLabel);
218
221
  url.searchParams.set('optionValue', optionValue);
@@ -238,6 +241,7 @@ async function fetchSubdivisions(
238
241
  optionLabel: string,
239
242
  optionValue: string,
240
243
  action: string,
244
+ requestOptions: BrowserRequestOptions,
241
245
  ): Promise<SubdivisionsResponse | null> {
242
246
  const cacheKey = getSubdivisionsCacheKey(country, optionLabel, optionValue, action);
243
247
 
@@ -248,11 +252,11 @@ async function fetchSubdivisions(
248
252
  if (!subdivisionInflight.has(cacheKey)) {
249
253
  subdivisionInflight.set(cacheKey, (async() => {
250
254
  try {
251
- const response = await fetch(buildSubdivisionsUrl(action, country, optionLabel, optionValue), {
255
+ const response = await browserRequest(buildSubdivisionsUrl(action, country, optionLabel, optionValue), {
252
256
  headers: {
253
257
  Accept: 'application/json',
254
258
  },
255
- });
259
+ }, requestOptions);
256
260
 
257
261
  if (!response.ok) {
258
262
  subdivisionDataCache.set(cacheKey, null);
@@ -342,9 +346,11 @@ function applyTextThemeClasses(template: AddressStateControl, input: HTMLInputEl
342
346
  function applySelectThemeClasses(template: AddressStateControl, select: HTMLSelectElement): void {
343
347
  const classes: string[] = [...SELECT_THEME_CLASSES];
344
348
 
345
- if (template.classList.contains('formie-input-error')) {
346
- classes.push('formie-input-error');
347
- }
349
+ getThemeClasses(template, 'fieldControlError').forEach((className) => {
350
+ if (template.classList.contains(className)) {
351
+ classes.push(className);
352
+ }
353
+ });
348
354
 
349
355
  select.className = classes.join(' ');
350
356
  }
@@ -454,7 +460,7 @@ function syncDatalist(
454
460
  function setFieldVisibility(fieldState: FieldState, visible: boolean): void {
455
461
  const { stateField, stateControl, required } = fieldState;
456
462
 
457
- stateField.classList.toggle('formie-conditionally-hidden', !visible);
463
+ toggleThemeClasses(stateField, stateField, 'conditionalHidden', !visible);
458
464
  stateField.toggleAttribute('data-formie-conditionally-hidden', !visible);
459
465
 
460
466
  if (!visible) {
@@ -502,7 +508,7 @@ function showFetchingUI(fieldState: FieldState): void {
502
508
  fieldState.stateControl.setAttribute('aria-hidden', 'true');
503
509
  fieldState.stateControl.setAttribute('tabindex', '-1');
504
510
 
505
- fieldState.stateField.classList.remove('formie-conditionally-hidden');
511
+ toggleThemeClasses(fieldState.stateField, fieldState.stateField, 'conditionalHidden', false);
506
512
  fieldState.stateField.removeAttribute('data-formie-conditionally-hidden');
507
513
  fieldState.stateField.setAttribute('data-formie-address-state-skeleton-active', 'true');
508
514
 
@@ -632,7 +638,7 @@ async function applyCountryState(
632
638
  showFetchingUI(fieldState);
633
639
  }
634
640
 
635
- const response = await fetchSubdivisions(country, optionLabel, optionValue, subdivisionsAction);
641
+ const response = await fetchSubdivisions(country, optionLabel, optionValue, subdivisionsAction, getFormBrowserRequestOptions(fieldState.addressRoot.closest('form')));
636
642
 
637
643
  if (fetchGeneration !== fieldState.fetchGeneration) {
638
644
  return;
@@ -923,8 +929,10 @@ function initAddressStateField(field: HTMLElement, options: AddressStateOptions)
923
929
  };
924
930
  }
925
931
 
926
- export const addressStateModule: FormieModuleDefinition = {
927
- id: MODULE_ID,
932
+ export const addressStateModule: BrowserModuleDefinition = {
933
+ moduleId: `formie:${MODULE_ID}`,
934
+ version: 2,
935
+ surfaces: ['server-rendered', 'client-rendered', 'cp-edit'],
928
936
  kind: 'field',
929
937
  match: (ctx) => {
930
938
  return !!ctx.target.querySelector(STATE_DYNAMIC_SELECTOR);
@@ -9,7 +9,7 @@ import {
9
9
  type CalculationVariableEntry,
10
10
  } from '@verbb/formie-core';
11
11
 
12
- import type { FormieModuleDefinition } from '#contracts/modules';
12
+ import type { BrowserModuleDefinition } from '#contracts/modules';
13
13
  import { dispatchFieldEvent, getModuleFieldContainers } from '#modules/fields/shared';
14
14
  import { buildFieldValueRegistry, fieldKeyToInputName, normalizeFieldKey, resolveFieldReferenceLive } from '#utils/field-references';
15
15
  import { getRowScopedWatchNames, resolveRowScopedFieldReference, type RowScopeParams } from '#utils/field-references.row-scope';
@@ -263,8 +263,10 @@ function bindCalculationsField(root: Element, field: HTMLElement, input: HTMLInp
263
263
  };
264
264
  }
265
265
 
266
- export const calculationsModule: FormieModuleDefinition = {
267
- id: MODULE_ID,
266
+ export const calculationsModule: BrowserModuleDefinition = {
267
+ moduleId: `formie:${MODULE_ID}`,
268
+ version: 2,
269
+ surfaces: ['server-rendered', 'client-rendered', 'cp-edit'],
268
270
  kind: 'field',
269
271
  match: (ctx) => {
270
272
  return !!ctx.target.querySelector(INPUT_SELECTOR);
@@ -1,5 +1,5 @@
1
- import type { FormieModuleDefinition } from '#contracts/modules';
2
- import { dispatchFieldEvent, escapeSelectorValue, releaseFormValidators, retainFormValidators } from '#modules/fields/shared';
1
+ import type { BrowserModuleDefinition } from '#contracts/modules';
2
+ import { dispatchFieldEvent, releaseFormValidators, retainFormValidators } from '#modules/fields/shared';
3
3
  import { createDebug } from '#utils/debug';
4
4
 
5
5
  const FIELD_SELECTOR = '[data-formie-checkboxes-field-layout], [data-formie-radio-field-layout]';
@@ -213,19 +213,7 @@ function unregisterValidators(form: HTMLFormElement | null): void {
213
213
  releaseFormValidators(form, VALIDATOR_SCOPE, [CHECKBOX_MINMAX_VALIDATOR, OTHER_OPTION_TEXT_VALIDATOR]);
214
214
  }
215
215
 
216
- function syncCheckedAttribute(input: HTMLInputElement): void {
217
- if (input.checked) {
218
- input.setAttribute('checked', '');
219
- } else {
220
- input.removeAttribute('checked');
221
- }
222
- }
223
-
224
- function syncRequiredCheckboxes(field: HTMLElement): void {
225
- const requiredCheckboxes = Array.from(field.querySelectorAll('input[type="checkbox"][required][data-formie-checkbox-input]')).filter((input): input is HTMLInputElement => {
226
- return input instanceof HTMLInputElement;
227
- });
228
-
216
+ function syncRequiredCheckboxes(requiredCheckboxes: HTMLInputElement[]): void {
229
217
  if (!requiredCheckboxes.length) {
230
218
  return;
231
219
  }
@@ -299,27 +287,11 @@ function toggleCheckboxGroup(field: HTMLElement, toggle: HTMLInputElement): void
299
287
  // Re-emit change/input so downstream modules (conditions, calculations,
300
288
  // validation) react exactly as if the user toggled each box manually.
301
289
  input.checked = toggle.checked;
302
- syncCheckedAttribute(input);
303
290
  input.dispatchEvent(new Event('change', { bubbles: true }));
304
291
  input.dispatchEvent(new Event('input', { bubbles: true }));
305
292
  });
306
293
  }
307
294
 
308
- function syncRadioGroup(input: HTMLInputElement, field: HTMLElement): void {
309
- if (!input.checked || !input.name) {
310
- syncCheckedAttribute(input);
311
- return;
312
- }
313
-
314
- const group = Array.from(field.querySelectorAll(`input[type="radio"][name="${escapeSelectorValue(input.name)}"]`)).filter((radio): radio is HTMLInputElement => {
315
- return radio instanceof HTMLInputElement;
316
- });
317
-
318
- group.forEach((radio) => {
319
- syncCheckedAttribute(radio);
320
- });
321
- }
322
-
323
295
  function bindField(field: HTMLElement): () => void {
324
296
  const inputs = Array.from(field.querySelectorAll('input[type="checkbox"], input[type="radio"]')).filter((input): input is HTMLInputElement => {
325
297
  return input instanceof HTMLInputElement;
@@ -330,20 +302,28 @@ function bindField(field: HTMLElement): () => void {
330
302
  return () => {};
331
303
  }
332
304
 
305
+ const requiredCheckboxes = inputs.filter((input) => input.type === 'checkbox' && input.required);
306
+ const form = field.closest('form');
307
+ const onReset = (event: Event) => {
308
+ // Native reset restores checked properties after the reset event returns.
309
+ queueMicrotask(() => {
310
+ if (!event.defaultPrevented) {
311
+ syncRequiredCheckboxes(requiredCheckboxes);
312
+ enforceMaxOptions(field);
313
+ syncOtherOptionField(field);
314
+ }
315
+ });
316
+ };
317
+ form?.addEventListener('reset', onReset);
318
+
333
319
  const listeners = inputs.map((input) => {
334
320
  const eventName = input.type === 'radio' ? 'change' : 'click';
335
321
  const handler = () => {
336
- syncCheckedAttribute(input);
337
-
338
322
  if (input.type === 'checkbox' && isToggleCheckbox(input)) {
339
323
  toggleCheckboxGroup(field, input);
340
324
  }
341
325
 
342
- if (input.type === 'radio') {
343
- syncRadioGroup(input, field);
344
- }
345
-
346
- syncRequiredCheckboxes(field);
326
+ syncRequiredCheckboxes(requiredCheckboxes);
347
327
  enforceMaxOptions(field);
348
328
  queueMicrotask(() => {
349
329
  syncOtherOptionField(field);
@@ -356,7 +336,6 @@ function bindField(field: HTMLElement): () => void {
356
336
  };
357
337
 
358
338
  input.addEventListener(eventName, handler);
359
- syncCheckedAttribute(input);
360
339
 
361
340
  return () => {
362
341
  input.removeEventListener(eventName, handler);
@@ -365,7 +344,7 @@ function bindField(field: HTMLElement): () => void {
365
344
 
366
345
  const destroyOtherOptionBinding = bindOtherOptionField(field);
367
346
 
368
- syncRequiredCheckboxes(field);
347
+ syncRequiredCheckboxes(requiredCheckboxes);
369
348
  enforceMaxOptions(field);
370
349
  syncOtherOptionField(field);
371
350
  dispatchFieldEvent(field, MODULE_ID, 'init', {
@@ -376,12 +355,15 @@ function bindField(field: HTMLElement): () => void {
376
355
  listeners.forEach((unbind) => {
377
356
  unbind();
378
357
  });
358
+ form?.removeEventListener('reset', onReset);
379
359
  destroyOtherOptionBinding();
380
360
  };
381
361
  }
382
362
 
383
- export const checkboxRadioModule: FormieModuleDefinition = {
384
- id: MODULE_ID,
363
+ export const checkboxRadioModule: BrowserModuleDefinition = {
364
+ moduleId: `formie:${MODULE_ID}`,
365
+ version: 2,
366
+ surfaces: ['server-rendered', 'client-rendered', 'cp-edit'],
385
367
  kind: 'field',
386
368
  match: (ctx) => {
387
369
  return ctx.target instanceof HTMLElement && (
@@ -1,9 +1,10 @@
1
1
  import TomSelect from 'tom-select/dist/esm/tom-select.complete.js';
2
2
 
3
- import type { FormieModuleDefinition } from '#contracts/modules';
3
+ import type { BrowserModuleDefinition } from '#contracts/modules';
4
4
  import comboboxThemeCss from '#theme-css/fields/_combobox.css?inline';
5
5
  import { dispatchFieldEvent, getModuleFieldContainers } from '#modules/fields/shared';
6
6
  import { ensureModuleStyles } from '#modules/styles';
7
+ import { getThemeClasses } from '#theme/theme-classes';
7
8
  import { createDebug } from '#utils/debug';
8
9
 
9
10
  const SELECT_SELECTOR = 'select[data-formie-combobox-input]';
@@ -15,7 +16,6 @@ ensureModuleStyles(MODULE_ID, [comboboxThemeCss]);
15
16
  const NATIVE_THEME_CLASSES = [
16
17
  'formie-select',
17
18
  'formie-dropdown-input',
18
- 'formie-input-error',
19
19
  ] as const;
20
20
 
21
21
  export type FormieComboboxOptions = {
@@ -35,7 +35,7 @@ type SelectElement = HTMLSelectElement & {
35
35
  function stripNativeThemeClasses(select: HTMLSelectElement): string[] {
36
36
  const removed: string[] = [];
37
37
 
38
- NATIVE_THEME_CLASSES.forEach((className) => {
38
+ [...NATIVE_THEME_CLASSES, ...getThemeClasses(select, 'fieldControlError')].forEach((className) => {
39
39
  if (select.classList.contains(className)) {
40
40
  select.classList.remove(className);
41
41
  removed.push(className);
@@ -51,8 +51,8 @@ function restoreNativeThemeClasses(select: HTMLSelectElement, classNames: string
51
51
  });
52
52
  }
53
53
 
54
- function cleanLeakedThemeClasses(element: HTMLElement): void {
55
- NATIVE_THEME_CLASSES.forEach((className) => {
54
+ function cleanLeakedThemeClasses(element: HTMLElement, source: HTMLSelectElement): void {
55
+ [...NATIVE_THEME_CLASSES, ...getThemeClasses(source, 'fieldControlError')].forEach((className) => {
56
56
  element.classList.remove(className);
57
57
  });
58
58
  }
@@ -78,6 +78,8 @@ function removeEmptyOptionFromCombobox(instance: TomSelectInstance): void {
78
78
  export function initFormieCombobox(select: SelectElement, options: FormieComboboxOptions = {}): () => void {
79
79
  select._formieTomSelect?.destroy();
80
80
 
81
+ const initialValues = Array.from(select.selectedOptions, (option) => option.value).filter(Boolean);
82
+ const form = select.form;
81
83
  const multiple = options.multiple === true;
82
84
  const restoredClasses = stripNativeThemeClasses(select);
83
85
  const placeholder = resolvePlaceholder(select, options.placeholder);
@@ -115,10 +117,10 @@ export function initFormieCombobox(select: SelectElement, options: FormieCombobo
115
117
 
116
118
  const instance = new TomSelect(select, mergedOptions) as TomSelectInstance;
117
119
  removeEmptyOptionFromCombobox(instance);
118
- cleanLeakedThemeClasses(instance.wrapper);
120
+ cleanLeakedThemeClasses(instance.wrapper, select);
119
121
 
120
122
  if (instance.dropdown) {
121
- cleanLeakedThemeClasses(instance.dropdown);
123
+ cleanLeakedThemeClasses(instance.dropdown, select);
122
124
  }
123
125
 
124
126
  // Tom Select keeps the native select as a preceding sibling; ensure it never
@@ -127,6 +129,17 @@ export function initFormieCombobox(select: SelectElement, options: FormieCombobo
127
129
 
128
130
  select._formieTomSelect = instance;
129
131
 
132
+ const onReset = (event: Event) => {
133
+ // Tom Select replaces native options, so retain the original selection
134
+ // and restore its display after the browser resets the backing select.
135
+ queueMicrotask(() => {
136
+ if (!event.defaultPrevented) {
137
+ instance.setValue(initialValues);
138
+ }
139
+ });
140
+ };
141
+ form?.addEventListener('reset', onReset);
142
+
130
143
  debug.log('Initialized.', {
131
144
  inputName: select.name,
132
145
  multiple,
@@ -138,6 +151,7 @@ export function initFormieCombobox(select: SelectElement, options: FormieCombobo
138
151
  });
139
152
 
140
153
  return () => {
154
+ form?.removeEventListener('reset', onReset);
141
155
  instance.destroy();
142
156
  select.style.removeProperty('display');
143
157
  restoreNativeThemeClasses(select, restoredClasses);
@@ -148,8 +162,10 @@ export function initFormieCombobox(select: SelectElement, options: FormieCombobo
148
162
  };
149
163
  }
150
164
 
151
- export const comboboxModule: FormieModuleDefinition = {
152
- id: MODULE_ID,
165
+ export const comboboxModule: BrowserModuleDefinition = {
166
+ moduleId: `formie:${MODULE_ID}`,
167
+ version: 2,
168
+ surfaces: ['server-rendered', 'client-rendered', 'cp-edit'],
153
169
  kind: 'field',
154
170
  match: (ctx) => {
155
171
  return !!ctx.target.querySelector(SELECT_SELECTOR);
@@ -13,7 +13,7 @@ function parseConditionSource(value: unknown): ConditionSource | null {
13
13
  return {
14
14
  raw: typeof candidate.raw === 'string' ? candidate.raw : '',
15
15
  target: typeof candidate.target === 'string' ? candidate.target : '',
16
- handle: typeof candidate.handle === 'string' ? candidate.handle : '',
16
+ handle: typeof candidate.domHandle === 'string' ? candidate.domHandle : typeof candidate.handle === 'string' ? candidate.handle : '',
17
17
  selector: typeof candidate.selector === 'string' ? candidate.selector : '',
18
18
  defaultValue: typeof candidate.defaultValue === 'string' ? candidate.defaultValue : '',
19
19
  transformerId: typeof candidate.transformerId === 'string' ? candidate.transformerId : '',
@@ -45,35 +45,32 @@ export function parseConditionSettings(node: Element): ParsedConditionSettings |
45
45
 
46
46
  try {
47
47
  const parsed = JSON.parse(raw) as Record<string, unknown>;
48
- const conditions = Array.isArray(parsed.conditions)
49
- ? parsed.conditions.filter((condition): condition is ConditionDefinition => {
50
- if (!condition || typeof condition !== 'object') {
51
- return false;
52
- }
53
-
54
- const candidate = condition as Record<string, unknown>;
55
- return typeof candidate.field === 'string' && typeof candidate.condition === 'string';
56
- }).map((condition) => {
57
- const candidate = condition as Record<string, unknown>;
58
-
48
+ const effect = String(parsed.effect ?? parsed.showRule ?? 'show');
49
+ const valid = (parsed.version == null || parsed.version === 1) && ['all', 'any'].includes(String(parsed.mode ?? parsed.conditionRule ?? 'all')) && ['show', 'hide', 'enable', 'disable'].includes(effect);
50
+ const rawRules = valid ? parsed.rules ?? parsed.conditions : [null];
51
+ const conditions = Array.isArray(rawRules)
52
+ ? rawRules.map((row) => {
53
+ const candidate = row && typeof row === 'object' ? row as Record<string, unknown> : {};
59
54
  return {
60
- field: condition.field,
55
+ field: typeof candidate.field === 'string' ? candidate.field : '',
61
56
  source: parseConditionSource(candidate.source),
62
- condition: condition.condition,
63
- value: condition.value,
57
+ condition: String(candidate.operator ?? candidate.condition ?? ''),
58
+ valueType: candidate.valueType as ConditionDefinition['valueType'],
59
+ browserSafe: candidate.browserSafe !== false,
60
+ value: candidate.value,
64
61
  };
65
62
  })
66
- : [];
63
+ : [{ field: '', condition: '', value: null, browserSafe: false }];
67
64
 
68
65
  return {
69
- showRule: parsed.showRule === 'hide' ? 'hide' : 'show',
70
- conditionRule: parsed.conditionRule === 'any' ? 'any' : 'all',
66
+ showRule: ['hide', 'enable', 'disable'].includes(effect) ? effect as ParsedConditionSettings['showRule'] : 'show',
67
+ conditionRule: (parsed.mode ?? parsed.conditionRule) === 'any' ? 'any' : 'all',
71
68
  clearOnHide: parsed.clearOnHide !== false,
72
69
  isNested: Boolean(parsed.isNested),
73
70
  conditions,
74
71
  };
75
72
  } catch (error) {
76
- console.error('[formie] Invalid condition JSON.', error);
77
- return null;
73
+ console.error('[formie] Invalid condition JSON.');
74
+ return { showRule: 'show', conditionRule: 'all', clearOnHide: true, isNested: false, conditions: [{ field: '', condition: '', browserSafe: false }] };
78
75
  }
79
76
  }