@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
@@ -1,14 +1,13 @@
1
+ import { getThemeClasses } from '#theme/theme-classes';
2
+
1
3
  const CONDITION_DISABLED_ATTR = 'data-formie-conditions-disabled';
2
4
  const PRESERVED_DISABLED_ATTR = 'data-formie-preserve-disabled';
3
5
  const CONDITIONAL_HIDDEN_ATTR = 'data-formie-conditionally-hidden';
4
6
  const PAGE_HIDDEN_ATTR = 'data-formie-page-hidden';
5
- const CONDITIONAL_HIDDEN_CLASS = 'formie-conditionally-hidden';
6
7
  const CP_MUTED_CLASS = 'fui-cp-muted-conditional-field';
7
8
  const CP_MUTED_EXPANDED_CLASS = 'fui-cp-muted-conditional-field--expanded';
8
9
  const CP_MUTED_ATTR = 'data-formie-cp-muted';
9
- const PAGE_HIDDEN_CLASS = 'formie-page-hidden';
10
10
  const ROW_HIDDEN_ATTR = 'data-formie-row-hidden';
11
- const ROW_HIDDEN_CLASS = 'formie-row-hidden';
12
11
  const FIELD_COUNT_ATTR = 'data-formie-field-count';
13
12
  const ROW_SELECTOR = '[data-formie-row], [data-formie-subfield-row], [data-formie-nested-field-row]';
14
13
  const FIELD_SELECTOR = ':scope > [data-formie-field]';
@@ -35,7 +34,7 @@ function clearConditionNodeValues(node: Element): void {
35
34
  option.selected = false;
36
35
  });
37
36
  } else {
38
- element.selectedIndex = 0;
37
+ element.selectedIndex = -1;
39
38
  }
40
39
  }
41
40
 
@@ -43,12 +42,14 @@ function clearConditionNodeValues(node: Element): void {
43
42
  element.value = '';
44
43
  }
45
44
  });
45
+
46
+ node.dispatchEvent(new CustomEvent('formie:field:clear', { bubbles: true }));
46
47
  }
47
48
 
48
49
  function setVisibilityState(node: Element, hidden: boolean): boolean {
49
50
  const isPage = node.hasAttribute('data-formie-page');
50
51
  const hiddenAttr = isPage ? PAGE_HIDDEN_ATTR : CONDITIONAL_HIDDEN_ATTR;
51
- const hiddenClass = isPage ? PAGE_HIDDEN_CLASS : CONDITIONAL_HIDDEN_CLASS;
52
+ const hiddenClasses = getThemeClasses(node, isPage ? 'pageHidden' : 'conditionalHidden');
52
53
  const wasHidden = node.hasAttribute(hiddenAttr);
53
54
 
54
55
  if (hidden) {
@@ -56,17 +57,13 @@ function setVisibilityState(node: Element, hidden: boolean): boolean {
56
57
  node.setAttribute(hiddenAttr, 'true');
57
58
  }
58
59
 
59
- if (!node.classList.contains(hiddenClass)) {
60
- node.classList.add(hiddenClass);
61
- }
60
+ node.classList.add(...hiddenClasses);
62
61
  } else {
63
62
  if (wasHidden) {
64
63
  node.removeAttribute(hiddenAttr);
65
64
  }
66
65
 
67
- if (node.classList.contains(hiddenClass)) {
68
- node.classList.remove(hiddenClass);
69
- }
66
+ node.classList.remove(...hiddenClasses);
70
67
  }
71
68
 
72
69
  return wasHidden !== hidden;
@@ -152,6 +149,7 @@ function isFieldVisible(field: Element): boolean {
152
149
  }
153
150
 
154
151
  function syncRowState(row: Element): void {
152
+ const hiddenClasses = getThemeClasses(row, 'rowHidden');
155
153
  const directFields = Array.from(row.querySelectorAll(FIELD_SELECTOR));
156
154
  const visibleFieldCount = directFields.filter((field) => {
157
155
  return isFieldVisible(field);
@@ -168,9 +166,7 @@ function syncRowState(row: Element): void {
168
166
  row.removeAttribute(ROW_HIDDEN_ATTR);
169
167
  }
170
168
 
171
- if (row.classList.contains(ROW_HIDDEN_CLASS)) {
172
- row.classList.remove(ROW_HIDDEN_CLASS);
173
- }
169
+ row.classList.remove(...hiddenClasses);
174
170
 
175
171
  return;
176
172
  }
@@ -183,9 +179,7 @@ function syncRowState(row: Element): void {
183
179
  row.setAttribute(ROW_HIDDEN_ATTR, 'true');
184
180
  }
185
181
 
186
- if (!row.classList.contains(ROW_HIDDEN_CLASS)) {
187
- row.classList.add(ROW_HIDDEN_CLASS);
188
- }
182
+ row.classList.add(...hiddenClasses);
189
183
  }
190
184
 
191
185
  function clearCpMutedState(node: Element): void {
@@ -197,8 +191,8 @@ function clearCpMutedState(node: Element): void {
197
191
  function clearHideState(node: Element): void {
198
192
  node.removeAttribute(CONDITIONAL_HIDDEN_ATTR);
199
193
  node.removeAttribute(PAGE_HIDDEN_ATTR);
200
- node.classList.remove(CONDITIONAL_HIDDEN_CLASS);
201
- node.classList.remove(PAGE_HIDDEN_CLASS);
194
+ node.classList.remove(...getThemeClasses(node, 'conditionalHidden'));
195
+ node.classList.remove(...getThemeClasses(node, 'pageHidden'));
202
196
  }
203
197
 
204
198
  function syncAncestorRows(node: Element): void {
@@ -214,8 +208,15 @@ export function applyConditionVisibility(
214
208
  node: Element,
215
209
  hidden: boolean,
216
210
  clearOnHide: boolean,
217
- options: { displayMode?: 'hide' | 'muted' } = {},
211
+ options: { displayMode?: 'hide' | 'muted'; disabledOnly?: boolean } = {},
218
212
  ): boolean {
213
+ if (options.disabledOnly) {
214
+ const changed = node.hasAttribute('data-formie-conditionally-disabled') !== hidden;
215
+ node.toggleAttribute('data-formie-conditionally-disabled', hidden);
216
+ syncDisabledState(node, hidden);
217
+ if (hidden && clearOnHide && changed) clearConditionNodeValues(node);
218
+ return changed;
219
+ }
219
220
  if (options.displayMode === 'muted') {
220
221
  return applyMutedConditionVisibility(node, hidden);
221
222
  }
@@ -246,9 +247,7 @@ function applyMutedConditionVisibility(node: Element, hidden: boolean): boolean
246
247
 
247
248
  if (hidden) {
248
249
  if (node.hasAttribute(CONDITIONAL_HIDDEN_ATTR)
249
- || node.hasAttribute(PAGE_HIDDEN_ATTR)
250
- || node.classList.contains(CONDITIONAL_HIDDEN_CLASS)
251
- || node.classList.contains(PAGE_HIDDEN_CLASS)) {
250
+ || node.hasAttribute(PAGE_HIDDEN_ATTR)) {
252
251
  clearHideState(node);
253
252
  stateChanged = true;
254
253
  }
@@ -271,9 +270,7 @@ function applyMutedConditionVisibility(node: Element, hidden: boolean): boolean
271
270
  }
272
271
 
273
272
  if (node.hasAttribute(CONDITIONAL_HIDDEN_ATTR)
274
- || node.hasAttribute(PAGE_HIDDEN_ATTR)
275
- || node.classList.contains(CONDITIONAL_HIDDEN_CLASS)
276
- || node.classList.contains(PAGE_HIDDEN_CLASS)) {
273
+ || node.hasAttribute(PAGE_HIDDEN_ATTR)) {
277
274
  clearHideState(node);
278
275
  stateChanged = true;
279
276
  }
@@ -1,43 +1,35 @@
1
- import { evaluateConditionDefinition, finalizeConditionEvaluation } from '@verbb/formie-core';
1
+ import { evaluateCondition, finalizeConditionEvaluation } from '@verbb/formie-core';
2
2
 
3
- import type { ConditionDefinition, ParsedConditionSettings, ConditionInput } from '#modules/fields/conditions/types';
3
+ import type { ConditionDefinition, ParsedConditionSettings } from '#modules/fields/conditions/types';
4
4
  import { resolveConditionSource } from '#modules/fields/conditions/references';
5
- import { readConditionValues } from '#modules/fields/conditions/values';
6
-
7
- function isInputVisible(input: ConditionInput): boolean {
8
- if (
9
- input.closest('[data-formie-conditionally-hidden]')
10
- || input.closest('[data-formie-page-hidden]')
11
- || input.closest('[hidden]')
12
- || input.closest('[aria-hidden="true"]')
13
- ) {
14
- return false;
15
- }
16
-
17
- return !!(input.offsetWidth || input.offsetHeight || input.getClientRects().length);
18
- }
19
-
20
- function getConditionVisibility(inputs: ConditionInput[]): boolean | null {
21
- if (!inputs.length) {
22
- return null;
23
- }
24
-
25
- return inputs.some((input) => {
26
- return isInputVisible(input);
27
- });
28
- }
5
+ import { readSubmissionConditionValues } from '#modules/fields/conditions/submission-context';
6
+ import { readConditionValues, readConditionProjection } from '#modules/fields/conditions/values';
29
7
 
30
8
  export function evaluateConditionSettings(
31
9
  settings: ParsedConditionSettings,
32
10
  getConditionInputs: (condition: ConditionDefinition) => Array<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>,
11
+ options: {
12
+ root?: Element;
13
+ from?: Element;
14
+ } = {},
33
15
  ): { finalResult: boolean; shouldHide: boolean } {
16
+ const root = options.root;
17
+ const from = options.from || root;
18
+
34
19
  const groupedResults = settings.conditions.map((condition) => {
35
20
  const inputs = getConditionInputs(condition);
36
21
  const source = resolveConditionSource(condition);
37
22
 
38
- return evaluateConditionDefinition(condition, readConditionValues(inputs, source), {
39
- visibility: getConditionVisibility(inputs),
40
- });
23
+ // `{submission:*}` is not a DOM field — read the snapshot emitted on the form.
24
+ const actualValues = source?.target === 'submission' && root && from
25
+ ? readSubmissionConditionValues(root, source, from)
26
+ : readConditionValues(inputs, source);
27
+
28
+ if (condition.browserSafe === false || Boolean(source?.transformerId) || source?.isValid === false || (!inputs.length && source?.target !== 'submission')) return { value: null, diagnostics: [{ code: 'unresolvedReference' }] };
29
+ const type = condition.valueType ?? (actualValues.length > 1 ? 'collection' : 'text');
30
+ const value = source?.target === 'submission' ? (type === 'collection' ? actualValues : actualValues[0] ?? null) : readConditionProjection(inputs, source, type, Number(from?.querySelector('input,select,textarea')?.getAttribute('name')?.match(/\[([0-9]+)\]/)?.[1]));
31
+ if (value && typeof value === 'object' && 'conditionDiagnostic' in value) return { value: null, diagnostics: [{ code: String(value.conditionDiagnostic) }] };
32
+ return evaluateCondition(condition.condition, value, condition.value, type);
41
33
  });
42
34
 
43
35
  return finalizeConditionEvaluation(settings, groupedResults);
@@ -33,7 +33,8 @@ function getRowScope(node: Element): Element | null {
33
33
 
34
34
  function getFieldInputs(fieldNode: Element): ConditionInput[] {
35
35
  return Array.from(fieldNode.querySelectorAll(CONDITION_INPUT_SELECTOR)).filter((element): element is ConditionInput => {
36
- return isConditionInput(element);
36
+ // Enhanced controls add unnamed search/display inputs that are not field values.
37
+ return isConditionInput(element) && Boolean(element.name);
37
38
  });
38
39
  }
39
40
 
@@ -93,7 +94,12 @@ function preferSameRow<TElement extends Element>(targetNode: Element, candidates
93
94
  }
94
95
 
95
96
  export function resolveConditionSource(condition: ConditionDefinition): ConditionSource | null {
96
- if (condition.source?.target === 'field' && condition.source.handle) {
97
+ if (!condition.source?.target || !condition.source.handle) {
98
+ return null;
99
+ }
100
+
101
+ // Field inputs + submission snapshot keys both use `source.handle`.
102
+ if (condition.source.target === 'field' || condition.source.target === 'submission') {
97
103
  return condition.source;
98
104
  }
99
105
 
@@ -112,10 +118,11 @@ export function queryConditionInputs(
112
118
  }
113
119
 
114
120
  const escapedFieldHandle = escapeSelectorValue(source.handle);
121
+ const explicitScope = Boolean(source.transformerParams.scope);
115
122
  const fieldMatches = Array.from(root.querySelectorAll(`[data-formie-field-handle="${escapedFieldHandle}"]`));
116
123
 
117
124
  if (fieldMatches.length) {
118
- return preferSameRow(targetNode, fieldMatches).flatMap((fieldNode) => {
125
+ return (explicitScope ? fieldMatches : preferSameRow(targetNode, fieldMatches)).flatMap((fieldNode) => {
119
126
  return filterInputsBySelector(getFieldInputs(fieldNode), source.selector);
120
127
  });
121
128
  }
@@ -130,7 +137,7 @@ export function queryConditionInputs(
130
137
  });
131
138
 
132
139
  if (direct.length || multi.length) {
133
- return preferSameRow(targetNode, [...direct, ...multi]);
140
+ return explicitScope ? [...direct, ...multi] : preferSameRow(targetNode, [...direct, ...multi]);
134
141
  }
135
142
 
136
143
  if (!source.handle.includes('__ROW__')) {
@@ -139,7 +146,7 @@ export function queryConditionInputs(
139
146
 
140
147
  const rowToken = getNodeRowToken(targetNode);
141
148
 
142
- if (rowToken) {
149
+ if (rowToken && !explicitScope) {
143
150
  const rowFieldName = fieldKeyToInputName(source.handle.replace(/__ROW__/g, rowToken));
144
151
  const escapedRowFieldName = escapeSelectorValue(rowFieldName);
145
152
  const rowDirect = Array.from(root.querySelectorAll(`[name="${escapedRowFieldName}"]`)).filter((element): element is ConditionInput => {
@@ -154,6 +161,10 @@ export function queryConditionInputs(
154
161
  }
155
162
  }
156
163
 
164
+ if (!explicitScope) {
165
+ return [];
166
+ }
167
+
157
168
  const regexString = fieldKeyToInputName(source.handle)
158
169
  .replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
159
170
  .replace(/__ROW__/g, '\\d+');
@@ -0,0 +1,80 @@
1
+ import type { ConditionSource } from '#modules/fields/conditions/types';
2
+
3
+ export const SUBMISSION_CONTEXT_ATTR = 'data-formie-submission';
4
+ export const SUBMISSION_CONTEXT_CHANGE_EVENT = 'formie:submission-context-change';
5
+
6
+ function isRecord(value: unknown): value is Record<string, unknown> {
7
+ return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
8
+ }
9
+
10
+ /**
11
+ * Find the nearest form/host that carries the submission condition snapshot.
12
+ * Prefer ancestors of `from` (the conditioned node), then fall back to `root`.
13
+ */
14
+ export function findSubmissionContextHost(root: Element, from: Element = root): Element | null {
15
+ const closest = from.closest(`[${SUBMISSION_CONTEXT_ATTR}]`);
16
+
17
+ if (closest) {
18
+ return closest;
19
+ }
20
+
21
+ if (root instanceof Element && root.hasAttribute(SUBMISSION_CONTEXT_ATTR)) {
22
+ return root;
23
+ }
24
+
25
+ return root.querySelector(`[${SUBMISSION_CONTEXT_ATTR}]`);
26
+ }
27
+
28
+ export function readSubmissionContext(root: Element, from: Element = root): Record<string, string> {
29
+ const host = findSubmissionContextHost(root, from);
30
+ const raw = host?.getAttribute(SUBMISSION_CONTEXT_ATTR);
31
+
32
+ if (!raw) {
33
+ return {};
34
+ }
35
+
36
+ try {
37
+ const parsed = JSON.parse(raw) as unknown;
38
+
39
+ if (!isRecord(parsed)) {
40
+ return {};
41
+ }
42
+
43
+ return Object.fromEntries(Object.entries(parsed).map(([key, value]) => {
44
+ return [key, value == null ? '' : String(value)];
45
+ }));
46
+ } catch (error) {
47
+ console.error('[formie] Invalid submission context JSON.', error);
48
+ return {};
49
+ }
50
+ }
51
+
52
+ /**
53
+ * Resolve `{submission:status}` (etc.) from the emitted snapshot.
54
+ * Handle is the property key from PHP (`status`, `title`, `formName`, …).
55
+ */
56
+ export function readSubmissionConditionValues(
57
+ root: Element,
58
+ source: ConditionSource,
59
+ from: Element = root,
60
+ ): string[] {
61
+ const context = readSubmissionContext(root, from);
62
+ const key = String(source.handle || '').trim();
63
+ let value = '';
64
+
65
+ if (key !== '') {
66
+ if (Object.prototype.hasOwnProperty.call(context, key)) {
67
+ value = context[key] ?? '';
68
+ } else {
69
+ // Variables map uses camelCase (`submissionStatus`); tolerate that alias.
70
+ const aliased = `submission${key.charAt(0).toUpperCase()}${key.slice(1)}`;
71
+ value = context[aliased] ?? '';
72
+ }
73
+ }
74
+
75
+ if (value === '' && source.defaultValue) {
76
+ value = source.defaultValue;
77
+ }
78
+
79
+ return [value];
80
+ }
@@ -15,11 +15,13 @@ export type ConditionDefinition = {
15
15
  field: string;
16
16
  source?: ConditionSource | null;
17
17
  condition: string;
18
+ valueType?: import('@verbb/formie-core').ConditionValueType;
19
+ browserSafe?: boolean;
18
20
  value?: unknown;
19
21
  };
20
22
 
21
23
  export type ParsedConditionSettings = {
22
- showRule: 'show' | 'hide';
24
+ showRule: 'show' | 'hide' | 'enable' | 'disable';
23
25
  conditionRule: 'all' | 'any';
24
26
  clearOnHide: boolean;
25
27
  isNested: boolean;
@@ -1,4 +1,4 @@
1
- import { applyConditionSource } from '#modules/fields/conditions/transforms';
1
+ import { selectConditionRows } from '@verbb/formie-core';
2
2
  import type { ConditionInput, ConditionSource } from '#modules/fields/conditions/types';
3
3
 
4
4
  function getInputKey(input: ConditionInput, index: number): string {
@@ -105,11 +105,36 @@ export function readConditionValues(inputs: ConditionInput[], source: ConditionS
105
105
  return readInputGroupValues(group, source?.selector || '');
106
106
  });
107
107
 
108
- return applyConditionSource(rawValues, source);
108
+ return (rawValues.length === 0 || rawValues.every((value) => value === '')) && source?.defaultValue ? [source.defaultValue] : rawValues;
109
109
  }
110
110
 
111
- export function isConditionValueEmpty(values: string[]): boolean {
112
- return values.length === 0 || values.every((value) => {
113
- return value.trim() === '';
114
- });
111
+ // DOM controls adapt to the same normalized condition projection as client-rendered values.
112
+ export function readConditionProjection(inputs: ConditionInput[], source: ConditionSource | null, type: import('@verbb/formie-core').ConditionValueType, currentRow?: number): unknown {
113
+ if (source?.transformerParams.scope) {
114
+ const grouped = new Map<string, ConditionInput[]>();
115
+ for (const input of inputs) {
116
+ const row = input.name.match(/\[([0-9]+)\]/)?.[1];
117
+ if (row != null) grouped.set(row, [...(grouped.get(row) ?? []), input]);
118
+ }
119
+ const rows = [...grouped.values()].map((group) => readConditionProjection(group, { ...source, transformerParams: {} }, type === 'collection' ? (group.length > 1 ? 'collection' : 'text') : type));
120
+ const selected = selectConditionRows(rows, source.transformerParams, currentRow);
121
+ if (selected.diagnostic) return { conditionDiagnostic: selected.diagnostic };
122
+ return source.transformerParams.scope === 'rows' && !Array.isArray(selected.value) ? [selected.value] : selected.value;
123
+ }
124
+ if (type === 'boolean') {
125
+ const checkbox = inputs.find((input) => input instanceof HTMLInputElement && input.type === 'checkbox') as HTMLInputElement | undefined;
126
+ if (checkbox) return checkbox.checked;
127
+ }
128
+ if (['date', 'time', 'datetime'].includes(type)) {
129
+ const parts: Record<string, string> = {};
130
+ for (const input of inputs) {
131
+ const key = input.name.match(/\[(year|month|day|hour|minute|second|ampm|timezone)\]$/)?.[1];
132
+ if (key && input.value !== '') parts[key] = input.value;
133
+ }
134
+ if (Object.keys(parts).length) return parts;
135
+ }
136
+ const values = readConditionValues(inputs, source);
137
+ // Empty hidden companions let unchecked groups post a value, but are not
138
+ // selected answers in the server's normalized collection.
139
+ return type === 'collection' ? values.filter((value) => value !== '') : values[0] ?? null;
115
140
  }
@@ -1,13 +1,16 @@
1
- import type { FormieModuleDefinition } from '#contracts/modules';
1
+ import type { BrowserModuleDefinition } from '#contracts/modules';
2
2
  import { CONDITION_SELECTOR, getConditionNodes, parseConditionSettings } from '#modules/fields/conditions/config';
3
3
  import { applyConditionVisibility } from '#modules/fields/conditions/effects';
4
4
  import { evaluateConditionSettings } from '#modules/fields/conditions/evaluator';
5
5
  import { queryConditionInputs } from '#modules/fields/conditions/references';
6
+ import {
7
+ SUBMISSION_CONTEXT_ATTR,
8
+ SUBMISSION_CONTEXT_CHANGE_EVENT,
9
+ } from '#modules/fields/conditions/submission-context';
6
10
  import type { ConditionEntry, ConditionInput } from '#modules/fields/conditions/types';
7
11
  import { getConditionInputEventNames } from '#modules/fields/conditions/values';
8
12
  import { createDebug } from '#utils/debug';
9
13
 
10
- const MAX_EVALUATION_PASSES = 4;
11
14
  const debug = createDebug('conditions');
12
15
 
13
16
  function uniqueConditionInputs(inputs: ConditionInput[]): ConditionInput[] {
@@ -23,9 +26,11 @@ function uniqueConditionInputs(inputs: ConditionInput[]): ConditionInput[] {
23
26
  });
24
27
  }
25
28
 
26
- export const conditionsModule: FormieModuleDefinition = {
27
- id: 'conditions',
28
- kind: 'field',
29
+ export const conditionsModule: BrowserModuleDefinition = {
30
+ moduleId: 'formie:conditions',
31
+ version: 2,
32
+ surfaces: ['server-rendered', 'client-rendered', 'cp-edit'],
33
+ kind: 'core',
29
34
  match: (ctx) => {
30
35
  return ctx.target instanceof HTMLElement && (
31
36
  ctx.target.matches(CONDITION_SELECTOR) ||
@@ -42,6 +47,7 @@ export const conditionsModule: FormieModuleDefinition = {
42
47
 
43
48
  const sourceUnbinds: Array<() => void> = [];
44
49
  let entries: ConditionEntry[] = [];
50
+ let cycles = new Set<Element>();
45
51
  let evaluationQueued = false;
46
52
  let rebuildQueued = false;
47
53
 
@@ -56,7 +62,7 @@ export const conditionsModule: FormieModuleDefinition = {
56
62
  return getConditionNodes(scopeRoot).flatMap((node) => {
57
63
  const settings = parseConditionSettings(node);
58
64
 
59
- if (!settings || !settings.conditions.length) {
65
+ if (!settings) {
60
66
  return [];
61
67
  }
62
68
 
@@ -72,6 +78,34 @@ export const conditionsModule: FormieModuleDefinition = {
72
78
  });
73
79
  };
74
80
 
81
+ const orderEntries = (items: ConditionEntry[]): ConditionEntry[] => {
82
+ const byNode = new Map(items.map((entry) => [entry.node, entry]));
83
+ const visited = new Set<Element>();
84
+ const visiting: Element[] = [];
85
+ const ordered: ConditionEntry[] = [];
86
+ cycles = new Set();
87
+ const visit = (entry: ConditionEntry): void => {
88
+ if (visited.has(entry.node)) return;
89
+ const index = visiting.indexOf(entry.node);
90
+ if (index >= 0) { visiting.slice(index).forEach((node) => cycles.add(node)); return; }
91
+ visiting.push(entry.node);
92
+ const ancestors = (node: Element | null) => {
93
+ for (let current = node?.closest(CONDITION_SELECTOR); current; current = current.parentElement?.closest(CONDITION_SELECTOR)) {
94
+ const dependency = byNode.get(current);
95
+ if (dependency) visit(dependency);
96
+ }
97
+ };
98
+ ancestors(entry.node.parentElement);
99
+ entry.sourceInputs.forEach((input) => ancestors(input));
100
+ visiting.pop();
101
+ visited.add(entry.node);
102
+ ordered.push(entry);
103
+ };
104
+ items.forEach(visit);
105
+ if (cycles.size) debug.warn('Condition dependency cycle.', { count: cycles.size });
106
+ return ordered;
107
+ };
108
+
75
109
  const cpDisplayMode = ctx.options?.cpDisplayMode === 'muted' ? 'muted' : 'hide';
76
110
  let isApplyingConditions = false;
77
111
 
@@ -79,8 +113,11 @@ export const conditionsModule: FormieModuleDefinition = {
79
113
  let hasStateChanges = false;
80
114
 
81
115
  entries.forEach((entry) => {
82
- const result = evaluateConditionSettings(entry.settings, (condition) => {
116
+ const result = cycles.has(entry.node) ? { finalResult: false, shouldHide: ['show', 'enable'].includes(entry.settings.showRule), diagnostics: [{ code: 'dependencyCycle' }] } : evaluateConditionSettings(entry.settings, (condition) => {
83
117
  return queryConditionInputs(scopeRoot, entry.node, condition);
118
+ }, {
119
+ root: scopeRoot,
120
+ from: entry.node,
84
121
  });
85
122
 
86
123
  const displayMode = entry.node.hasAttribute('data-formie-page')
@@ -91,7 +128,7 @@ export const conditionsModule: FormieModuleDefinition = {
91
128
  entry.node,
92
129
  result.shouldHide,
93
130
  entry.settings.clearOnHide,
94
- { displayMode },
131
+ { displayMode, disabledOnly: ['enable', 'disable'].includes(entry.settings.showRule) },
95
132
  );
96
133
  hasStateChanges = hasStateChanges || stateChanged;
97
134
  debug.log('Condition evaluated.', {
@@ -105,6 +142,7 @@ export const conditionsModule: FormieModuleDefinition = {
105
142
  shouldHide: result.shouldHide,
106
143
  finalResult: result.finalResult,
107
144
  clearOnHide: entry.settings.clearOnHide,
145
+ diagnostics: cycles.has(entry.node) ? [{ code: 'dependencyCycle' }] : [],
108
146
  });
109
147
  });
110
148
 
@@ -119,15 +157,7 @@ export const conditionsModule: FormieModuleDefinition = {
119
157
  isApplyingConditions = true;
120
158
 
121
159
  try {
122
- for (let pass = 0; pass < MAX_EVALUATION_PASSES; pass += 1) {
123
- if (!runEvaluationPass()) {
124
- break;
125
- }
126
-
127
- if (pass === MAX_EVALUATION_PASSES - 1) {
128
- debug.warn('Reached max evaluation passes.', { maxPasses: MAX_EVALUATION_PASSES });
129
- }
130
- }
160
+ runEvaluationPass();
131
161
  } finally {
132
162
  isApplyingConditions = false;
133
163
  }
@@ -185,12 +215,22 @@ export const conditionsModule: FormieModuleDefinition = {
185
215
  sourceUnbinds.push(() => {
186
216
  ctx.form?.removeEventListener('reset', resetHandler);
187
217
  });
218
+
219
+ // CP status menu (etc.) updates `data-formie-submission` and fires this event.
220
+ const submissionContextHandler = () => {
221
+ scheduleEvaluateAll();
222
+ };
223
+
224
+ ctx.form.addEventListener(SUBMISSION_CONTEXT_CHANGE_EVENT, submissionContextHandler);
225
+ sourceUnbinds.push(() => {
226
+ ctx.form?.removeEventListener(SUBMISSION_CONTEXT_CHANGE_EVENT, submissionContextHandler);
227
+ });
188
228
  }
189
229
  };
190
230
 
191
231
  const rebuild = (): void => {
192
232
  cleanupSourceBindings();
193
- entries = buildEntries();
233
+ entries = orderEntries(buildEntries());
194
234
  bindSourceInputs();
195
235
  debug.log('Rebuilt condition graph.', {
196
236
  entryCount: entries.length,
@@ -249,6 +289,7 @@ export const conditionsModule: FormieModuleDefinition = {
249
289
  'data-formie-conditionally-hidden',
250
290
  'data-formie-page-hidden',
251
291
  'data-formie-row-hidden',
292
+ SUBMISSION_CONTEXT_ATTR,
252
293
  ],
253
294
  });
254
295
 
@@ -1,4 +1,4 @@
1
- import type { FormieModuleDefinition } from '#contracts/modules';
1
+ import type { BrowserModuleDefinition } from '#contracts/modules';
2
2
  import { getModuleFieldTarget, observeMatchingElements } from '#modules/fields/shared';
3
3
 
4
4
  const MODULE_ID = 'custom-google-maps';
@@ -390,8 +390,10 @@ function initCustomGoogleMaps(root: HTMLElement): () => void {
390
390
  };
391
391
  }
392
392
 
393
- export const customGoogleMapsModule: FormieModuleDefinition = {
394
- id: MODULE_ID,
393
+ export const customGoogleMapsModule: BrowserModuleDefinition = {
394
+ moduleId: `formie:${MODULE_ID}`,
395
+ version: 2,
396
+ surfaces: ['server-rendered', 'client-rendered', 'cp-edit'],
395
397
  kind: 'field',
396
398
  match: ({ target }) => {
397
399
  return target instanceof Element && (
@@ -1,4 +1,4 @@
1
- import type { FormieModuleDefinition } from '#contracts/modules';
1
+ import type { BrowserModuleDefinition } from '#contracts/modules';
2
2
  import { getModuleFieldTarget, observeMatchingElements } from '#modules/fields/shared';
3
3
 
4
4
  const MODULE_ID = 'custom-link';
@@ -69,8 +69,10 @@ function initCustomLink(link: HTMLElement): () => void {
69
69
  };
70
70
  }
71
71
 
72
- export const customLinkModule: FormieModuleDefinition = {
73
- id: MODULE_ID,
72
+ export const customLinkModule: BrowserModuleDefinition = {
73
+ moduleId: `formie:${MODULE_ID}`,
74
+ version: 2,
75
+ surfaces: ['server-rendered', 'client-rendered', 'cp-edit'],
74
76
  kind: 'field',
75
77
  match: ({ target }) => {
76
78
  return target instanceof Element && (
@@ -1,4 +1,4 @@
1
- import type { FormieModuleDefinition } from '#contracts/modules';
1
+ import type { BrowserModuleDefinition } from '#contracts/modules';
2
2
  import type * as Leaflet from 'leaflet';
3
3
  import leafletCss from 'leaflet/dist/leaflet.css?inline';
4
4
  import { getModuleFieldTarget, observeMatchingElements } from '#modules/fields/shared';
@@ -313,8 +313,10 @@ function initCustomMaps(root: HTMLElement): () => void {
313
313
  };
314
314
  }
315
315
 
316
- export const customMapsModule: FormieModuleDefinition = {
317
- id: MODULE_ID,
316
+ export const customMapsModule: BrowserModuleDefinition = {
317
+ moduleId: `formie:${MODULE_ID}`,
318
+ version: 2,
319
+ surfaces: ['server-rendered', 'client-rendered', 'cp-edit'],
318
320
  kind: 'field',
319
321
  match: ({ target }) => {
320
322
  return target instanceof Element && (