@verbb/formie-browser 1.0.13 → 1.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (389) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/dist/chunks/{address-country-Rx6GQTND.js → address-country-BcEQKw0T.js} +11 -5
  3. package/dist/chunks/{address-finder-k7_BXaRe.js → address-finder-BWGINCSA.js} +3 -3
  4. package/dist/chunks/address-state-DI3ndhMU.js +365 -0
  5. package/dist/chunks/{api-BUb6P-xu.js → api-BK9b340y.js} +93 -63
  6. package/dist/chunks/{api-DqpfkZWL.js → api-Dxl_CKw-.js} +202 -193
  7. package/dist/chunks/{api-sPqGbOww.js → api-ghNr2uxX.js} +15 -9
  8. package/dist/chunks/{async-nPFRNQ06.js → async-2GdXNFCE.js} +18 -1
  9. package/dist/chunks/{bpoint-Dlq34XH1.js → bpoint-BwtuyN_O.js} +3 -3
  10. package/dist/chunks/calculations-YEoVCG2q.js +310 -0
  11. package/dist/chunks/{captcha-eu-CGm8Lbrj.js → captcha-eu-DWLoQFKB.js} +6 -5
  12. package/dist/chunks/{checkbox-radio-BY2aTCOG.js → checkbox-radio-gsm8QPJg.js} +74 -75
  13. package/dist/chunks/{combobox-C0EuExSI.js → combobox-Ba08_cHL.js} +340 -328
  14. package/dist/chunks/conditions-Ceeg6ReZ.js +467 -0
  15. package/dist/chunks/country-from-ip-DDj_mFki.js +29 -0
  16. package/dist/chunks/csrf-DxHg_ZYt.js +61 -0
  17. package/dist/chunks/{custom-google-maps-BsaSirEZ.js → custom-google-maps-C4l2S3GO.js} +9 -3
  18. package/dist/chunks/{custom-link-CJ1-FjEM.js → custom-link-CLazgKYH.js} +8 -2
  19. package/dist/chunks/{custom-maps-DYW_pBid.js → custom-maps-DqcAlD0v.js} +10 -4
  20. package/dist/chunks/{date-picker-F9BUBDSW.js → date-picker-DaPvMrop.js} +467 -443
  21. package/dist/chunks/{dist-D6i-VNgM.js → dist-ZLeW0zZ3.js} +1281 -453
  22. package/dist/chunks/{eway-D9_m8ooj.js → eway-uw0DzU-L.js} +5 -5
  23. package/dist/chunks/field-references.resolver-Ca8MguFv.js +104 -0
  24. package/dist/chunks/{file-upload-rqfZNqlH.js → file-upload-B8_mH012.js} +119 -99
  25. package/dist/chunks/friendly-captcha-v1-CVXaXgDO.js +34 -0
  26. package/dist/chunks/{friendly-captcha-v2-CLSAbkqx.js → friendly-captcha-v2-DkeIVTKI.js} +6 -5
  27. package/dist/chunks/{friendly-challenge-8uPatWqk.js → friendly-challenge-DPG9MJb1.js} +111 -102
  28. package/dist/chunks/{go-cardless-DAT3ZaQf.js → go-cardless-c4wLJdOt.js} +2 -2
  29. package/dist/chunks/google-address-JHYvjwgN.js +168 -0
  30. package/dist/chunks/{hcaptcha-CGLAmgjO.js → hcaptcha-Dt3ELLlP.js} +4 -4
  31. package/dist/chunks/{hidden-D7_Ch-QN.js → hidden-BZhXnNPe.js} +8 -2
  32. package/dist/chunks/http-C2QdHuWO.js +27 -0
  33. package/dist/chunks/{leaflet-src-j-lHNmhR.js → leaflet-src-DE6rv6M-.js} +42 -46
  34. package/dist/chunks/{loqate-CJPzBmSm.js → loqate-m51iPyO1.js} +3 -3
  35. package/dist/chunks/{mollie-Bibhl67p.js → mollie-Bn0PX173.js} +2 -2
  36. package/dist/chunks/{moneris-H2wSqk9h.js → moneris-BRbUvI4t.js} +3 -3
  37. package/dist/chunks/opayo-BwWdInEP.js +188 -0
  38. package/dist/chunks/{paddle-DkvIxQdG.js → paddle-CympHVvd.js} +4 -4
  39. package/dist/chunks/{password-validation-D06uH9va.js → password-validation-C8_uO_c_.js} +18 -12
  40. package/dist/chunks/{paypal-CQpAF7Ua.js → paypal-h75h6wae.js} +8 -6
  41. package/dist/chunks/{payway-CwDkC7YZ.js → payway-C9rHTCC_.js} +4 -4
  42. package/dist/chunks/{phone-country-D3ayr60L.js → phone-country-B8fv-L5_.js} +80 -63
  43. package/dist/chunks/{place-kit-BGHklIZ-.js → place-kit-BnZGQ-L1.js} +11 -11
  44. package/dist/chunks/{placekit-autocomplete.esm-DWVabQlq.js → placekit-autocomplete.esm-CZZERYur.js} +11 -15
  45. package/dist/chunks/{recaptcha-enterprise-XPId5-bS.js → recaptcha-enterprise-CUs8BO6V.js} +4 -4
  46. package/dist/chunks/{recaptcha-shared-CLYJvojk.js → recaptcha-shared-DTbTw-MF.js} +2 -2
  47. package/dist/chunks/{recaptcha-v2-checkbox-Cy-0PEPc.js → recaptcha-v2-checkbox-P1McW4Pv.js} +4 -4
  48. package/dist/chunks/{recaptcha-v2-invisible-BwRH540O.js → recaptcha-v2-invisible-FGDqozSP.js} +4 -4
  49. package/dist/chunks/{recaptcha-v3-No4Ykrhk.js → recaptcha-v3-CflUHeZD.js} +4 -4
  50. package/dist/chunks/{repeater-BVnPUqTj.js → repeater-CyhDbozO.js} +60 -40
  51. package/dist/chunks/request-profile-DhwkeCpS.js +10 -0
  52. package/dist/chunks/rich-text-uV4o_pGk.js +361 -0
  53. package/dist/chunks/{chunk-3b4jIN3o.js → rolldown-runtime-DtPi1Y-2.js} +2 -2
  54. package/dist/chunks/{scripts-CbQ7agX3.js → scripts-DrccjrFv.js} +1 -1
  55. package/dist/chunks/{sdk-BhHAYgga.js → sdk-lkwSvlpM.js} +282 -234
  56. package/dist/chunks/{shared-Bx9s0i0P.js → shared-OKhSay59.js} +27 -21
  57. package/dist/chunks/{signature-IOhuicje.js → signature-7cldFbqj.js} +138 -112
  58. package/dist/chunks/skip-CEW89ExY.js +7 -0
  59. package/dist/chunks/{snaptcha-DKx98oon.js → snaptcha-C3QLYxFT.js} +2 -2
  60. package/dist/chunks/{square-DwdcOI1G.js → square-C1z5DPVw.js} +9 -7
  61. package/dist/chunks/{stripe-DaoG2FT1.js → stripe-Dmkdkq1y.js} +11 -12
  62. package/dist/chunks/{summary-Dks0gXS3.js → summary-Bn-g5SDx.js} +48 -46
  63. package/dist/chunks/{survey-likert-DkE6bR7B.js → survey-likert-fk1hUPff.js} +7 -1
  64. package/dist/chunks/{survey-rank-DN6x4IZM.js → survey-rank-BsLGl2LX.js} +37 -25
  65. package/dist/chunks/{survey-rating-BnsNL9U5.js → survey-rating-DVS6e6fM.js} +17 -5
  66. package/dist/chunks/{table-CAjCJHrL.js → table-j7MlLLCc.js} +22 -16
  67. package/dist/chunks/{text-limit-BGaY0jhI.js → text-limit-LGMPhFuC.js} +40 -34
  68. package/dist/chunks/{theme-classes-Tv7q7ToE.js → theme-classes-DAQuEqdP.js} +1 -1
  69. package/dist/chunks/{turnstile-DJakPzQD.js → turnstile-ptihQfLl.js} +4 -4
  70. package/dist/chunks/{upload-manager-W-QDgxKD.js → upload-manager-BW7l-BhF.js} +459 -387
  71. package/dist/chunks/{utils-Vqp8i_RM.js → utils-DpUBPadZ.js} +20 -14
  72. package/dist/css/formie-base.css +104 -1
  73. package/dist/css/theme/_messages.css +2 -0
  74. package/dist/css/theme/_tokens.css +31 -25
  75. package/dist/css/theme/forms/_form.css +5 -1
  76. package/dist/index.d.ts +5 -4
  77. package/dist/index.d.ts.map +1 -1
  78. package/dist/index.js +1779 -1415
  79. package/dist/js/contracts/client.d.ts +5 -3
  80. package/dist/js/contracts/client.d.ts.map +1 -1
  81. package/dist/js/contracts/common.d.ts +2 -2
  82. package/dist/js/contracts/common.d.ts.map +1 -1
  83. package/dist/js/contracts/modules.d.ts +37 -12
  84. package/dist/js/contracts/modules.d.ts.map +1 -1
  85. package/dist/js/contracts/schema.d.ts +20 -38
  86. package/dist/js/contracts/schema.d.ts.map +1 -1
  87. package/dist/js/contracts/theme.d.ts +4 -1
  88. package/dist/js/contracts/theme.d.ts.map +1 -1
  89. package/dist/js/core/client-rendered-modules.d.ts +17 -0
  90. package/dist/js/core/client-rendered-modules.d.ts.map +1 -0
  91. package/dist/js/core/create-formie-client.d.ts.map +1 -1
  92. package/dist/js/core/field-error-aria.d.ts +23 -0
  93. package/dist/js/core/field-error-aria.d.ts.map +1 -0
  94. package/dist/js/core/hydrate-modules.d.ts +10 -8
  95. package/dist/js/core/hydrate-modules.d.ts.map +1 -1
  96. package/dist/js/core/submit-result-state.d.ts.map +1 -1
  97. package/dist/js/core/submit-result-ui.d.ts +3 -1
  98. package/dist/js/core/submit-result-ui.d.ts.map +1 -1
  99. package/dist/js/core/validation-focus.d.ts.map +1 -1
  100. package/dist/js/modules/address/address-finder.d.ts +1 -1
  101. package/dist/js/modules/address/address-finder.d.ts.map +1 -1
  102. package/dist/js/modules/address/factories.d.ts +3 -3
  103. package/dist/js/modules/address/factories.d.ts.map +1 -1
  104. package/dist/js/modules/address/google-address.d.ts +12 -1
  105. package/dist/js/modules/address/google-address.d.ts.map +1 -1
  106. package/dist/js/modules/address/index.d.ts +2 -2
  107. package/dist/js/modules/address/index.d.ts.map +1 -1
  108. package/dist/js/modules/address/loqate.d.ts +1 -1
  109. package/dist/js/modules/address/loqate.d.ts.map +1 -1
  110. package/dist/js/modules/address/place-kit.d.ts +1 -1
  111. package/dist/js/modules/address/place-kit.d.ts.map +1 -1
  112. package/dist/js/modules/captchas/captcha-eu.d.ts +1 -1
  113. package/dist/js/modules/captchas/captcha-eu.d.ts.map +1 -1
  114. package/dist/js/modules/captchas/factories.d.ts +11 -11
  115. package/dist/js/modules/captchas/factories.d.ts.map +1 -1
  116. package/dist/js/modules/captchas/friendly-captcha-v1.d.ts +1 -1
  117. package/dist/js/modules/captchas/friendly-captcha-v1.d.ts.map +1 -1
  118. package/dist/js/modules/captchas/friendly-captcha-v2.d.ts +1 -1
  119. package/dist/js/modules/captchas/friendly-captcha-v2.d.ts.map +1 -1
  120. package/dist/js/modules/captchas/hcaptcha.d.ts +1 -1
  121. package/dist/js/modules/captchas/hcaptcha.d.ts.map +1 -1
  122. package/dist/js/modules/captchas/index.d.ts +2 -2
  123. package/dist/js/modules/captchas/index.d.ts.map +1 -1
  124. package/dist/js/modules/captchas/recaptcha-enterprise.d.ts +1 -1
  125. package/dist/js/modules/captchas/recaptcha-enterprise.d.ts.map +1 -1
  126. package/dist/js/modules/captchas/recaptcha-v2-checkbox.d.ts +1 -1
  127. package/dist/js/modules/captchas/recaptcha-v2-checkbox.d.ts.map +1 -1
  128. package/dist/js/modules/captchas/recaptcha-v2-invisible.d.ts +1 -1
  129. package/dist/js/modules/captchas/recaptcha-v2-invisible.d.ts.map +1 -1
  130. package/dist/js/modules/captchas/recaptcha-v3.d.ts +1 -1
  131. package/dist/js/modules/captchas/recaptcha-v3.d.ts.map +1 -1
  132. package/dist/js/modules/captchas/snaptcha.d.ts +1 -1
  133. package/dist/js/modules/captchas/snaptcha.d.ts.map +1 -1
  134. package/dist/js/modules/captchas/turnstile.d.ts +1 -1
  135. package/dist/js/modules/captchas/turnstile.d.ts.map +1 -1
  136. package/dist/js/modules/fields/address-country.d.ts +2 -2
  137. package/dist/js/modules/fields/address-country.d.ts.map +1 -1
  138. package/dist/js/modules/fields/address-state.d.ts +2 -2
  139. package/dist/js/modules/fields/address-state.d.ts.map +1 -1
  140. package/dist/js/modules/fields/calculations.d.ts +2 -2
  141. package/dist/js/modules/fields/calculations.d.ts.map +1 -1
  142. package/dist/js/modules/fields/checkbox-radio.d.ts +2 -2
  143. package/dist/js/modules/fields/checkbox-radio.d.ts.map +1 -1
  144. package/dist/js/modules/fields/combobox.d.ts +2 -2
  145. package/dist/js/modules/fields/combobox.d.ts.map +1 -1
  146. package/dist/js/modules/fields/conditions/config.d.ts.map +1 -1
  147. package/dist/js/modules/fields/conditions/effects.d.ts +1 -0
  148. package/dist/js/modules/fields/conditions/effects.d.ts.map +1 -1
  149. package/dist/js/modules/fields/conditions/evaluator.d.ts +4 -1
  150. package/dist/js/modules/fields/conditions/evaluator.d.ts.map +1 -1
  151. package/dist/js/modules/fields/conditions/references.d.ts.map +1 -1
  152. package/dist/js/modules/fields/conditions/submission-context.d.ts +15 -0
  153. package/dist/js/modules/fields/conditions/submission-context.d.ts.map +1 -0
  154. package/dist/js/modules/fields/conditions/types.d.ts +3 -1
  155. package/dist/js/modules/fields/conditions/types.d.ts.map +1 -1
  156. package/dist/js/modules/fields/conditions/values.d.ts +1 -1
  157. package/dist/js/modules/fields/conditions/values.d.ts.map +1 -1
  158. package/dist/js/modules/fields/conditions.d.ts +2 -2
  159. package/dist/js/modules/fields/conditions.d.ts.map +1 -1
  160. package/dist/js/modules/fields/custom-google-maps.d.ts +2 -2
  161. package/dist/js/modules/fields/custom-google-maps.d.ts.map +1 -1
  162. package/dist/js/modules/fields/custom-link.d.ts +2 -2
  163. package/dist/js/modules/fields/custom-link.d.ts.map +1 -1
  164. package/dist/js/modules/fields/custom-maps.d.ts +2 -2
  165. package/dist/js/modules/fields/custom-maps.d.ts.map +1 -1
  166. package/dist/js/modules/fields/date-picker.d.ts +2 -2
  167. package/dist/js/modules/fields/date-picker.d.ts.map +1 -1
  168. package/dist/js/modules/fields/file-upload.d.ts +2 -2
  169. package/dist/js/modules/fields/file-upload.d.ts.map +1 -1
  170. package/dist/js/modules/fields/hidden.d.ts +2 -2
  171. package/dist/js/modules/fields/hidden.d.ts.map +1 -1
  172. package/dist/js/modules/fields/index.d.ts +2 -2
  173. package/dist/js/modules/fields/index.d.ts.map +1 -1
  174. package/dist/js/modules/fields/password-validation.d.ts +2 -2
  175. package/dist/js/modules/fields/password-validation.d.ts.map +1 -1
  176. package/dist/js/modules/fields/phone-country.d.ts +2 -2
  177. package/dist/js/modules/fields/phone-country.d.ts.map +1 -1
  178. package/dist/js/modules/fields/repeater.d.ts +2 -2
  179. package/dist/js/modules/fields/repeater.d.ts.map +1 -1
  180. package/dist/js/modules/fields/rich-text.d.ts +2 -2
  181. package/dist/js/modules/fields/rich-text.d.ts.map +1 -1
  182. package/dist/js/modules/fields/shared.d.ts +1 -0
  183. package/dist/js/modules/fields/shared.d.ts.map +1 -1
  184. package/dist/js/modules/fields/signature.d.ts +2 -2
  185. package/dist/js/modules/fields/signature.d.ts.map +1 -1
  186. package/dist/js/modules/fields/summary.d.ts +2 -2
  187. package/dist/js/modules/fields/summary.d.ts.map +1 -1
  188. package/dist/js/modules/fields/survey-likert.d.ts +2 -2
  189. package/dist/js/modules/fields/survey-likert.d.ts.map +1 -1
  190. package/dist/js/modules/fields/survey-rank.d.ts +2 -2
  191. package/dist/js/modules/fields/survey-rank.d.ts.map +1 -1
  192. package/dist/js/modules/fields/survey-rating.d.ts +2 -2
  193. package/dist/js/modules/fields/survey-rating.d.ts.map +1 -1
  194. package/dist/js/modules/fields/table.d.ts +2 -2
  195. package/dist/js/modules/fields/table.d.ts.map +1 -1
  196. package/dist/js/modules/fields/text-limit.d.ts +2 -2
  197. package/dist/js/modules/fields/text-limit.d.ts.map +1 -1
  198. package/dist/js/modules/fields/upload-manager.d.ts +2 -2
  199. package/dist/js/modules/fields/upload-manager.d.ts.map +1 -1
  200. package/dist/js/modules/loader.d.ts +10 -4
  201. package/dist/js/modules/loader.d.ts.map +1 -1
  202. package/dist/js/modules/payments/bpoint.d.ts +1 -1
  203. package/dist/js/modules/payments/bpoint.d.ts.map +1 -1
  204. package/dist/js/modules/payments/eway.d.ts +1 -1
  205. package/dist/js/modules/payments/eway.d.ts.map +1 -1
  206. package/dist/js/modules/payments/factories.d.ts +7 -7
  207. package/dist/js/modules/payments/factories.d.ts.map +1 -1
  208. package/dist/js/modules/payments/go-cardless.d.ts +1 -1
  209. package/dist/js/modules/payments/go-cardless.d.ts.map +1 -1
  210. package/dist/js/modules/payments/index.d.ts +2 -2
  211. package/dist/js/modules/payments/index.d.ts.map +1 -1
  212. package/dist/js/modules/payments/mollie.d.ts +1 -1
  213. package/dist/js/modules/payments/mollie.d.ts.map +1 -1
  214. package/dist/js/modules/payments/moneris.d.ts +1 -1
  215. package/dist/js/modules/payments/moneris.d.ts.map +1 -1
  216. package/dist/js/modules/payments/opayo.d.ts +1 -1
  217. package/dist/js/modules/payments/opayo.d.ts.map +1 -1
  218. package/dist/js/modules/payments/paddle.d.ts +1 -1
  219. package/dist/js/modules/payments/paddle.d.ts.map +1 -1
  220. package/dist/js/modules/payments/paypal.d.ts +1 -1
  221. package/dist/js/modules/payments/paypal.d.ts.map +1 -1
  222. package/dist/js/modules/payments/payway.d.ts +1 -1
  223. package/dist/js/modules/payments/payway.d.ts.map +1 -1
  224. package/dist/js/modules/payments/square.d.ts +1 -1
  225. package/dist/js/modules/payments/square.d.ts.map +1 -1
  226. package/dist/js/modules/payments/stripe.d.ts +1 -1
  227. package/dist/js/modules/payments/stripe.d.ts.map +1 -1
  228. package/dist/js/modules/payments/utils.d.ts +6 -0
  229. package/dist/js/modules/payments/utils.d.ts.map +1 -1
  230. package/dist/js/modules/registry.d.ts +6 -4
  231. package/dist/js/modules/registry.d.ts.map +1 -1
  232. package/dist/js/submit/pipeline.d.ts.map +1 -1
  233. package/dist/js/theme/browser-theme-state.generated.d.ts +24 -0
  234. package/dist/js/theme/browser-theme-state.generated.d.ts.map +1 -0
  235. package/dist/js/theme/theme-classes.d.ts +3 -3
  236. package/dist/js/theme/theme-classes.d.ts.map +1 -1
  237. package/dist/js/transport/forms-api.d.ts +5 -3
  238. package/dist/js/transport/forms-api.d.ts.map +1 -1
  239. package/dist/js/utils/async.d.ts +1 -0
  240. package/dist/js/utils/async.d.ts.map +1 -1
  241. package/dist/js/utils/country-from-ip.d.ts +2 -2
  242. package/dist/js/utils/country-from-ip.d.ts.map +1 -1
  243. package/dist/js/utils/csrf.d.ts +17 -0
  244. package/dist/js/utils/csrf.d.ts.map +1 -0
  245. package/dist/js/utils/field-references.parser.d.ts +1 -0
  246. package/dist/js/utils/field-references.parser.d.ts.map +1 -1
  247. package/dist/js/utils/field-references.resolver.d.ts.map +1 -1
  248. package/dist/js/utils/field-references.types.d.ts +1 -0
  249. package/dist/js/utils/field-references.types.d.ts.map +1 -1
  250. package/dist/js/utils/http.d.ts +3 -1
  251. package/dist/js/utils/http.d.ts.map +1 -1
  252. package/dist/js/utils/request-profile.d.ts +4 -0
  253. package/dist/js/utils/request-profile.d.ts.map +1 -0
  254. package/dist/js/utils/unload-warning.d.ts.map +1 -1
  255. package/dist/js/validation/rules/email.d.ts.map +1 -1
  256. package/dist/js/validation/rules/match.d.ts.map +1 -1
  257. package/dist/js/validation/rules/number.d.ts.map +1 -1
  258. package/dist/js/validation/rules/required.d.ts.map +1 -1
  259. package/dist/js/validation/rules/shared.d.ts.map +1 -1
  260. package/dist/js/validation/rules/url.d.ts.map +1 -1
  261. package/dist/js/validation/skip.d.ts +7 -0
  262. package/dist/js/validation/skip.d.ts.map +1 -0
  263. package/dist/js/validation/submit-readiness.d.ts.map +1 -1
  264. package/dist/js/validation/validator.d.ts.map +1 -1
  265. package/package.json +43 -12
  266. package/src/css/formie-base.css +104 -1
  267. package/src/css/theme/_messages.css +2 -0
  268. package/src/css/theme/_tokens.css +31 -25
  269. package/src/css/theme/forms/_form.css +5 -1
  270. package/src/index.ts +13 -8
  271. package/src/js/contracts/client.ts +5 -3
  272. package/src/js/contracts/common.ts +5 -6
  273. package/src/js/contracts/modules.ts +41 -12
  274. package/src/js/contracts/schema.ts +21 -43
  275. package/src/js/contracts/theme.ts +6 -1
  276. package/src/js/core/client-rendered-modules.ts +69 -0
  277. package/src/js/core/create-formie-client.ts +132 -86
  278. package/src/js/core/field-error-aria.ts +93 -0
  279. package/src/js/core/hydrate-modules.ts +54 -29
  280. package/src/js/core/submit-result-state.ts +51 -45
  281. package/src/js/core/submit-result-ui.ts +25 -68
  282. package/src/js/core/validation-focus.ts +20 -20
  283. package/src/js/modules/address/address-finder.ts +1 -1
  284. package/src/js/modules/address/factories.ts +15 -13
  285. package/src/js/modules/address/google-address.ts +102 -40
  286. package/src/js/modules/address/index.ts +2 -2
  287. package/src/js/modules/address/loqate.ts +1 -1
  288. package/src/js/modules/address/place-kit.ts +14 -8
  289. package/src/js/modules/captchas/captcha-eu.ts +2 -2
  290. package/src/js/modules/captchas/factories.ts +66 -42
  291. package/src/js/modules/captchas/friendly-captcha-v1.ts +12 -2
  292. package/src/js/modules/captchas/friendly-captcha-v2.ts +4 -2
  293. package/src/js/modules/captchas/hcaptcha.ts +5 -5
  294. package/src/js/modules/captchas/index.ts +2 -2
  295. package/src/js/modules/captchas/recaptcha-enterprise.ts +2 -2
  296. package/src/js/modules/captchas/recaptcha-v2-checkbox.ts +3 -3
  297. package/src/js/modules/captchas/recaptcha-v2-invisible.ts +2 -2
  298. package/src/js/modules/captchas/recaptcha-v3.ts +2 -2
  299. package/src/js/modules/captchas/snaptcha.ts +1 -1
  300. package/src/js/modules/captchas/turnstile.ts +3 -3
  301. package/src/js/modules/fields/address-country.ts +11 -9
  302. package/src/js/modules/fields/address-state.ts +94 -35
  303. package/src/js/modules/fields/calculations.ts +5 -3
  304. package/src/js/modules/fields/checkbox-radio.ts +24 -42
  305. package/src/js/modules/fields/combobox.ts +28 -9
  306. package/src/js/modules/fields/conditions/config.ts +17 -20
  307. package/src/js/modules/fields/conditions/effects.ts +25 -29
  308. package/src/js/modules/fields/conditions/evaluator.ts +21 -29
  309. package/src/js/modules/fields/conditions/references.ts +16 -5
  310. package/src/js/modules/fields/conditions/submission-context.ts +80 -0
  311. package/src/js/modules/fields/conditions/types.ts +3 -1
  312. package/src/js/modules/fields/conditions/values.ts +31 -6
  313. package/src/js/modules/fields/conditions.ts +65 -18
  314. package/src/js/modules/fields/custom-google-maps.ts +5 -3
  315. package/src/js/modules/fields/custom-link.ts +5 -3
  316. package/src/js/modules/fields/custom-maps.ts +5 -3
  317. package/src/js/modules/fields/date-picker.ts +40 -7
  318. package/src/js/modules/fields/file-upload.ts +62 -23
  319. package/src/js/modules/fields/hidden.ts +5 -3
  320. package/src/js/modules/fields/index.ts +2 -2
  321. package/src/js/modules/fields/password-validation.ts +5 -3
  322. package/src/js/modules/fields/phone-country.ts +35 -8
  323. package/src/js/modules/fields/repeater.ts +60 -7
  324. package/src/js/modules/fields/rich-text.ts +20 -4
  325. package/src/js/modules/fields/shared.ts +13 -0
  326. package/src/js/modules/fields/signature.ts +24 -4
  327. package/src/js/modules/fields/summary.ts +8 -20
  328. package/src/js/modules/fields/survey-likert.ts +5 -3
  329. package/src/js/modules/fields/survey-rank.ts +21 -3
  330. package/src/js/modules/fields/survey-rating.ts +17 -3
  331. package/src/js/modules/fields/table.ts +5 -3
  332. package/src/js/modules/fields/text-limit.ts +5 -3
  333. package/src/js/modules/fields/upload-manager.ts +244 -67
  334. package/src/js/modules/loader.ts +345 -281
  335. package/src/js/modules/payments/bpoint.ts +2 -2
  336. package/src/js/modules/payments/eway.ts +2 -2
  337. package/src/js/modules/payments/factories.ts +53 -52
  338. package/src/js/modules/payments/go-cardless.ts +1 -1
  339. package/src/js/modules/payments/index.ts +2 -2
  340. package/src/js/modules/payments/mollie.ts +1 -1
  341. package/src/js/modules/payments/moneris.ts +2 -2
  342. package/src/js/modules/payments/opayo.ts +21 -8
  343. package/src/js/modules/payments/paddle.ts +10 -6
  344. package/src/js/modules/payments/payment.ts +22 -18
  345. package/src/js/modules/payments/paypal.ts +1 -1
  346. package/src/js/modules/payments/payway.ts +2 -2
  347. package/src/js/modules/payments/square.ts +2 -2
  348. package/src/js/modules/payments/stripe.ts +5 -5
  349. package/src/js/modules/payments/utils.ts +14 -0
  350. package/src/js/modules/registry.ts +19 -11
  351. package/src/js/submit/pipeline.ts +10 -11
  352. package/src/js/theme/browser-theme-state.generated.ts +25 -0
  353. package/src/js/theme/theme-classes.ts +3 -3
  354. package/src/js/transport/forms-api.ts +66 -67
  355. package/src/js/utils/async.ts +34 -0
  356. package/src/js/utils/country-from-ip.ts +14 -9
  357. package/src/js/utils/csrf.ts +136 -0
  358. package/src/js/utils/field-references.parser.ts +13 -113
  359. package/src/js/utils/field-references.resolver.ts +27 -64
  360. package/src/js/utils/field-references.row-scope.ts +1 -1
  361. package/src/js/utils/field-references.types.ts +1 -0
  362. package/src/js/utils/http.ts +5 -5
  363. package/src/js/utils/request-profile.ts +10 -0
  364. package/src/js/utils/unload-warning.ts +12 -4
  365. package/src/js/validation/rules/email.ts +3 -5
  366. package/src/js/validation/rules/match.ts +2 -1
  367. package/src/js/validation/rules/minmax.ts +4 -43
  368. package/src/js/validation/rules/number.ts +3 -47
  369. package/src/js/validation/rules/pattern.ts +3 -8
  370. package/src/js/validation/rules/required.ts +14 -1
  371. package/src/js/validation/rules/shared.ts +5 -1
  372. package/src/js/validation/rules/url.ts +3 -10
  373. package/src/js/validation/skip.ts +9 -0
  374. package/src/js/validation/submit-readiness.ts +9 -2
  375. package/src/js/validation/validator.ts +49 -61
  376. package/dist/chunks/address-state-BwE01m2_.js +0 -344
  377. package/dist/chunks/calculations-Dv3hYb8_.js +0 -299
  378. package/dist/chunks/conditions-CPH1snCx.js +0 -424
  379. package/dist/chunks/country-from-ip-BwxKaBuJ.js +0 -26
  380. package/dist/chunks/field-references.resolver-CHwn0G0L.js +0 -145
  381. package/dist/chunks/friendly-captcha-v1-C_2reOXr.js +0 -31
  382. package/dist/chunks/google-address-BH3Zhi06.js +0 -161
  383. package/dist/chunks/http-D-JExro7.js +0 -27
  384. package/dist/chunks/opayo-CR0DtsLa.js +0 -179
  385. package/dist/chunks/rich-text-Bg_--4TG.js +0 -349
  386. package/dist/js/modules/fields/conditions/transforms.d.ts +0 -3
  387. package/dist/js/modules/fields/conditions/transforms.d.ts.map +0 -1
  388. package/src/js/modules/fields/conditions/transforms.ts +0 -206
  389. package/src/js/modules/payments/stub-payment-module.ts +0 -87
@@ -1,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,15 @@ 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
- const isPage = node.hasAttribute('data-formie-page');
50
- const hiddenAttr = isPage ? PAGE_HIDDEN_ATTR : CONDITIONAL_HIDDEN_ATTR;
51
- const hiddenClass = isPage ? PAGE_HIDDEN_CLASS : CONDITIONAL_HIDDEN_CLASS;
50
+ // Navigation owns page-hidden. A matching condition must not reveal an
51
+ // inactive page, or clear its values just because the visitor moved on.
52
+ const hiddenAttr = CONDITIONAL_HIDDEN_ATTR;
53
+ const hiddenClasses = getThemeClasses(node, 'conditionalHidden');
52
54
  const wasHidden = node.hasAttribute(hiddenAttr);
53
55
 
54
56
  if (hidden) {
@@ -56,17 +58,13 @@ function setVisibilityState(node: Element, hidden: boolean): boolean {
56
58
  node.setAttribute(hiddenAttr, 'true');
57
59
  }
58
60
 
59
- if (!node.classList.contains(hiddenClass)) {
60
- node.classList.add(hiddenClass);
61
- }
61
+ node.classList.add(...hiddenClasses);
62
62
  } else {
63
63
  if (wasHidden) {
64
64
  node.removeAttribute(hiddenAttr);
65
65
  }
66
66
 
67
- if (node.classList.contains(hiddenClass)) {
68
- node.classList.remove(hiddenClass);
69
- }
67
+ node.classList.remove(...hiddenClasses);
70
68
  }
71
69
 
72
70
  return wasHidden !== hidden;
@@ -152,6 +150,7 @@ function isFieldVisible(field: Element): boolean {
152
150
  }
153
151
 
154
152
  function syncRowState(row: Element): void {
153
+ const hiddenClasses = getThemeClasses(row, 'rowHidden');
155
154
  const directFields = Array.from(row.querySelectorAll(FIELD_SELECTOR));
156
155
  const visibleFieldCount = directFields.filter((field) => {
157
156
  return isFieldVisible(field);
@@ -168,9 +167,7 @@ function syncRowState(row: Element): void {
168
167
  row.removeAttribute(ROW_HIDDEN_ATTR);
169
168
  }
170
169
 
171
- if (row.classList.contains(ROW_HIDDEN_CLASS)) {
172
- row.classList.remove(ROW_HIDDEN_CLASS);
173
- }
170
+ row.classList.remove(...hiddenClasses);
174
171
 
175
172
  return;
176
173
  }
@@ -183,9 +180,7 @@ function syncRowState(row: Element): void {
183
180
  row.setAttribute(ROW_HIDDEN_ATTR, 'true');
184
181
  }
185
182
 
186
- if (!row.classList.contains(ROW_HIDDEN_CLASS)) {
187
- row.classList.add(ROW_HIDDEN_CLASS);
188
- }
183
+ row.classList.add(...hiddenClasses);
189
184
  }
190
185
 
191
186
  function clearCpMutedState(node: Element): void {
@@ -196,9 +191,7 @@ function clearCpMutedState(node: Element): void {
196
191
 
197
192
  function clearHideState(node: Element): void {
198
193
  node.removeAttribute(CONDITIONAL_HIDDEN_ATTR);
199
- 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'));
202
195
  }
203
196
 
204
197
  function syncAncestorRows(node: Element): void {
@@ -214,8 +207,15 @@ export function applyConditionVisibility(
214
207
  node: Element,
215
208
  hidden: boolean,
216
209
  clearOnHide: boolean,
217
- options: { displayMode?: 'hide' | 'muted' } = {},
210
+ options: { displayMode?: 'hide' | 'muted'; disabledOnly?: boolean } = {},
218
211
  ): boolean {
212
+ if (options.disabledOnly) {
213
+ const changed = node.hasAttribute('data-formie-conditionally-disabled') !== hidden;
214
+ node.toggleAttribute('data-formie-conditionally-disabled', hidden);
215
+ syncDisabledState(node, hidden);
216
+ if (hidden && clearOnHide && changed) clearConditionNodeValues(node);
217
+ return changed;
218
+ }
219
219
  if (options.displayMode === 'muted') {
220
220
  return applyMutedConditionVisibility(node, hidden);
221
221
  }
@@ -246,9 +246,7 @@ function applyMutedConditionVisibility(node: Element, hidden: boolean): boolean
246
246
 
247
247
  if (hidden) {
248
248
  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)) {
249
+ || node.hasAttribute(PAGE_HIDDEN_ATTR)) {
252
250
  clearHideState(node);
253
251
  stateChanged = true;
254
252
  }
@@ -271,9 +269,7 @@ function applyMutedConditionVisibility(node: Element, hidden: boolean): boolean
271
269
  }
272
270
 
273
271
  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)) {
272
+ || node.hasAttribute(PAGE_HIDDEN_ATTR)) {
277
273
  clearHideState(node);
278
274
  stateChanged = true;
279
275
  }
@@ -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,17 @@
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';
13
+ import { getFormStateEventName } from '#utils/event-names';
9
14
 
10
- const MAX_EVALUATION_PASSES = 4;
11
15
  const debug = createDebug('conditions');
12
16
 
13
17
  function uniqueConditionInputs(inputs: ConditionInput[]): ConditionInput[] {
@@ -23,9 +27,11 @@ function uniqueConditionInputs(inputs: ConditionInput[]): ConditionInput[] {
23
27
  });
24
28
  }
25
29
 
26
- export const conditionsModule: FormieModuleDefinition = {
27
- id: 'conditions',
28
- kind: 'field',
30
+ export const conditionsModule: BrowserModuleDefinition = {
31
+ moduleId: 'formie:conditions',
32
+ version: 2,
33
+ surfaces: ['server-rendered', 'client-rendered', 'cp-edit'],
34
+ kind: 'core',
29
35
  match: (ctx) => {
30
36
  return ctx.target instanceof HTMLElement && (
31
37
  ctx.target.matches(CONDITION_SELECTOR) ||
@@ -42,6 +48,7 @@ export const conditionsModule: FormieModuleDefinition = {
42
48
 
43
49
  const sourceUnbinds: Array<() => void> = [];
44
50
  let entries: ConditionEntry[] = [];
51
+ let cycles = new Set<Element>();
45
52
  let evaluationQueued = false;
46
53
  let rebuildQueued = false;
47
54
 
@@ -56,7 +63,7 @@ export const conditionsModule: FormieModuleDefinition = {
56
63
  return getConditionNodes(scopeRoot).flatMap((node) => {
57
64
  const settings = parseConditionSettings(node);
58
65
 
59
- if (!settings || !settings.conditions.length) {
66
+ if (!settings) {
60
67
  return [];
61
68
  }
62
69
 
@@ -72,6 +79,34 @@ export const conditionsModule: FormieModuleDefinition = {
72
79
  });
73
80
  };
74
81
 
82
+ const orderEntries = (items: ConditionEntry[]): ConditionEntry[] => {
83
+ const byNode = new Map(items.map((entry) => [entry.node, entry]));
84
+ const visited = new Set<Element>();
85
+ const visiting: Element[] = [];
86
+ const ordered: ConditionEntry[] = [];
87
+ cycles = new Set();
88
+ const visit = (entry: ConditionEntry): void => {
89
+ if (visited.has(entry.node)) return;
90
+ const index = visiting.indexOf(entry.node);
91
+ if (index >= 0) { visiting.slice(index).forEach((node) => cycles.add(node)); return; }
92
+ visiting.push(entry.node);
93
+ const ancestors = (node: Element | null) => {
94
+ for (let current = node?.closest(CONDITION_SELECTOR); current; current = current.parentElement?.closest(CONDITION_SELECTOR)) {
95
+ const dependency = byNode.get(current);
96
+ if (dependency) visit(dependency);
97
+ }
98
+ };
99
+ ancestors(entry.node.parentElement);
100
+ entry.sourceInputs.forEach((input) => ancestors(input));
101
+ visiting.pop();
102
+ visited.add(entry.node);
103
+ ordered.push(entry);
104
+ };
105
+ items.forEach(visit);
106
+ if (cycles.size) debug.warn('Condition dependency cycle.', { count: cycles.size });
107
+ return ordered;
108
+ };
109
+
75
110
  const cpDisplayMode = ctx.options?.cpDisplayMode === 'muted' ? 'muted' : 'hide';
76
111
  let isApplyingConditions = false;
77
112
 
@@ -79,8 +114,11 @@ export const conditionsModule: FormieModuleDefinition = {
79
114
  let hasStateChanges = false;
80
115
 
81
116
  entries.forEach((entry) => {
82
- const result = evaluateConditionSettings(entry.settings, (condition) => {
117
+ const result = cycles.has(entry.node) ? { finalResult: false, shouldHide: ['show', 'enable'].includes(entry.settings.showRule), diagnostics: [{ code: 'dependencyCycle' }] } : evaluateConditionSettings(entry.settings, (condition) => {
83
118
  return queryConditionInputs(scopeRoot, entry.node, condition);
119
+ }, {
120
+ root: scopeRoot,
121
+ from: entry.node,
84
122
  });
85
123
 
86
124
  const displayMode = entry.node.hasAttribute('data-formie-page')
@@ -91,7 +129,7 @@ export const conditionsModule: FormieModuleDefinition = {
91
129
  entry.node,
92
130
  result.shouldHide,
93
131
  entry.settings.clearOnHide,
94
- { displayMode },
132
+ { displayMode, disabledOnly: ['enable', 'disable'].includes(entry.settings.showRule) },
95
133
  );
96
134
  hasStateChanges = hasStateChanges || stateChanged;
97
135
  debug.log('Condition evaluated.', {
@@ -105,6 +143,7 @@ export const conditionsModule: FormieModuleDefinition = {
105
143
  shouldHide: result.shouldHide,
106
144
  finalResult: result.finalResult,
107
145
  clearOnHide: entry.settings.clearOnHide,
146
+ diagnostics: cycles.has(entry.node) ? [{ code: 'dependencyCycle' }] : [],
108
147
  });
109
148
  });
110
149
 
@@ -119,15 +158,7 @@ export const conditionsModule: FormieModuleDefinition = {
119
158
  isApplyingConditions = true;
120
159
 
121
160
  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
- }
161
+ runEvaluationPass();
131
162
  } finally {
132
163
  isApplyingConditions = false;
133
164
  }
@@ -182,15 +213,30 @@ export const conditionsModule: FormieModuleDefinition = {
182
213
  };
183
214
 
184
215
  ctx.form.addEventListener('reset', resetHandler);
216
+ // Canonical resets have already restored values. Settle conditions
217
+ // before the unload guard captures the form's new clean state.
218
+ const stateResetEvent = getFormStateEventName('reset');
219
+ ctx.form.addEventListener(stateResetEvent, evaluateAll);
185
220
  sourceUnbinds.push(() => {
186
221
  ctx.form?.removeEventListener('reset', resetHandler);
222
+ ctx.form?.removeEventListener(stateResetEvent, evaluateAll);
223
+ });
224
+
225
+ // CP status menu (etc.) updates `data-formie-submission` and fires this event.
226
+ const submissionContextHandler = () => {
227
+ scheduleEvaluateAll();
228
+ };
229
+
230
+ ctx.form.addEventListener(SUBMISSION_CONTEXT_CHANGE_EVENT, submissionContextHandler);
231
+ sourceUnbinds.push(() => {
232
+ ctx.form?.removeEventListener(SUBMISSION_CONTEXT_CHANGE_EVENT, submissionContextHandler);
187
233
  });
188
234
  }
189
235
  };
190
236
 
191
237
  const rebuild = (): void => {
192
238
  cleanupSourceBindings();
193
- entries = buildEntries();
239
+ entries = orderEntries(buildEntries());
194
240
  bindSourceInputs();
195
241
  debug.log('Rebuilt condition graph.', {
196
242
  entryCount: entries.length,
@@ -249,6 +295,7 @@ export const conditionsModule: FormieModuleDefinition = {
249
295
  'data-formie-conditionally-hidden',
250
296
  'data-formie-page-hidden',
251
297
  'data-formie-row-hidden',
298
+ SUBMISSION_CONTEXT_ATTR,
252
299
  ],
253
300
  });
254
301
 
@@ -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 && (