@verbb/formie-browser 1.0.12 → 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 (383) hide show
  1. package/CHANGELOG.md +57 -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-5CA_-zGb.js → date-picker-RUnevF7l.js} +456 -430
  20. package/dist/chunks/{dist-BdUy8m_p.js → dist-ZLeW0zZ3.js} +1280 -452
  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-T0vDQPCr.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-xz4QO7CR.js → signature-7cldFbqj.js} +160 -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-Bn18WrPU.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/fields/_signature.css +2 -1
  73. package/dist/css/theme/forms/_form.css +5 -1
  74. package/dist/index.d.ts +5 -4
  75. package/dist/index.d.ts.map +1 -1
  76. package/dist/index.js +1778 -1425
  77. package/dist/js/contracts/client.d.ts +5 -3
  78. package/dist/js/contracts/client.d.ts.map +1 -1
  79. package/dist/js/contracts/common.d.ts +2 -2
  80. package/dist/js/contracts/common.d.ts.map +1 -1
  81. package/dist/js/contracts/modules.d.ts +37 -12
  82. package/dist/js/contracts/modules.d.ts.map +1 -1
  83. package/dist/js/contracts/schema.d.ts +20 -38
  84. package/dist/js/contracts/schema.d.ts.map +1 -1
  85. package/dist/js/contracts/theme.d.ts +4 -1
  86. package/dist/js/contracts/theme.d.ts.map +1 -1
  87. package/dist/js/core/client-rendered-modules.d.ts +17 -0
  88. package/dist/js/core/client-rendered-modules.d.ts.map +1 -0
  89. package/dist/js/core/create-formie-client.d.ts.map +1 -1
  90. package/dist/js/core/field-error-aria.d.ts +23 -0
  91. package/dist/js/core/field-error-aria.d.ts.map +1 -0
  92. package/dist/js/core/hydrate-modules.d.ts +10 -8
  93. package/dist/js/core/hydrate-modules.d.ts.map +1 -1
  94. package/dist/js/core/submit-result-state.d.ts.map +1 -1
  95. package/dist/js/core/submit-result-ui.d.ts.map +1 -1
  96. package/dist/js/core/validation-focus.d.ts.map +1 -1
  97. package/dist/js/modules/address/address-finder.d.ts +1 -1
  98. package/dist/js/modules/address/address-finder.d.ts.map +1 -1
  99. package/dist/js/modules/address/factories.d.ts +3 -3
  100. package/dist/js/modules/address/factories.d.ts.map +1 -1
  101. package/dist/js/modules/address/google-address.d.ts +2 -1
  102. package/dist/js/modules/address/google-address.d.ts.map +1 -1
  103. package/dist/js/modules/address/index.d.ts +2 -2
  104. package/dist/js/modules/address/index.d.ts.map +1 -1
  105. package/dist/js/modules/address/loqate.d.ts +1 -1
  106. package/dist/js/modules/address/loqate.d.ts.map +1 -1
  107. package/dist/js/modules/address/place-kit.d.ts +1 -1
  108. package/dist/js/modules/address/place-kit.d.ts.map +1 -1
  109. package/dist/js/modules/captchas/captcha-eu.d.ts +1 -1
  110. package/dist/js/modules/captchas/captcha-eu.d.ts.map +1 -1
  111. package/dist/js/modules/captchas/factories.d.ts +11 -11
  112. package/dist/js/modules/captchas/factories.d.ts.map +1 -1
  113. package/dist/js/modules/captchas/friendly-captcha-v1.d.ts +1 -1
  114. package/dist/js/modules/captchas/friendly-captcha-v1.d.ts.map +1 -1
  115. package/dist/js/modules/captchas/friendly-captcha-v2.d.ts +1 -1
  116. package/dist/js/modules/captchas/friendly-captcha-v2.d.ts.map +1 -1
  117. package/dist/js/modules/captchas/hcaptcha.d.ts +1 -1
  118. package/dist/js/modules/captchas/hcaptcha.d.ts.map +1 -1
  119. package/dist/js/modules/captchas/index.d.ts +2 -2
  120. package/dist/js/modules/captchas/index.d.ts.map +1 -1
  121. package/dist/js/modules/captchas/recaptcha-enterprise.d.ts +1 -1
  122. package/dist/js/modules/captchas/recaptcha-enterprise.d.ts.map +1 -1
  123. package/dist/js/modules/captchas/recaptcha-v2-checkbox.d.ts +1 -1
  124. package/dist/js/modules/captchas/recaptcha-v2-checkbox.d.ts.map +1 -1
  125. package/dist/js/modules/captchas/recaptcha-v2-invisible.d.ts +1 -1
  126. package/dist/js/modules/captchas/recaptcha-v2-invisible.d.ts.map +1 -1
  127. package/dist/js/modules/captchas/recaptcha-v3.d.ts +1 -1
  128. package/dist/js/modules/captchas/recaptcha-v3.d.ts.map +1 -1
  129. package/dist/js/modules/captchas/snaptcha.d.ts +1 -1
  130. package/dist/js/modules/captchas/snaptcha.d.ts.map +1 -1
  131. package/dist/js/modules/captchas/turnstile.d.ts +1 -1
  132. package/dist/js/modules/captchas/turnstile.d.ts.map +1 -1
  133. package/dist/js/modules/fields/address-country.d.ts +2 -2
  134. package/dist/js/modules/fields/address-country.d.ts.map +1 -1
  135. package/dist/js/modules/fields/address-state.d.ts +2 -2
  136. package/dist/js/modules/fields/address-state.d.ts.map +1 -1
  137. package/dist/js/modules/fields/calculations.d.ts +2 -2
  138. package/dist/js/modules/fields/calculations.d.ts.map +1 -1
  139. package/dist/js/modules/fields/checkbox-radio.d.ts +2 -2
  140. package/dist/js/modules/fields/checkbox-radio.d.ts.map +1 -1
  141. package/dist/js/modules/fields/combobox.d.ts +2 -2
  142. package/dist/js/modules/fields/combobox.d.ts.map +1 -1
  143. package/dist/js/modules/fields/conditions/config.d.ts.map +1 -1
  144. package/dist/js/modules/fields/conditions/effects.d.ts +1 -0
  145. package/dist/js/modules/fields/conditions/effects.d.ts.map +1 -1
  146. package/dist/js/modules/fields/conditions/evaluator.d.ts +4 -1
  147. package/dist/js/modules/fields/conditions/evaluator.d.ts.map +1 -1
  148. package/dist/js/modules/fields/conditions/references.d.ts.map +1 -1
  149. package/dist/js/modules/fields/conditions/submission-context.d.ts +15 -0
  150. package/dist/js/modules/fields/conditions/submission-context.d.ts.map +1 -0
  151. package/dist/js/modules/fields/conditions/types.d.ts +3 -1
  152. package/dist/js/modules/fields/conditions/types.d.ts.map +1 -1
  153. package/dist/js/modules/fields/conditions/values.d.ts +1 -1
  154. package/dist/js/modules/fields/conditions/values.d.ts.map +1 -1
  155. package/dist/js/modules/fields/conditions.d.ts +2 -2
  156. package/dist/js/modules/fields/conditions.d.ts.map +1 -1
  157. package/dist/js/modules/fields/custom-google-maps.d.ts +2 -2
  158. package/dist/js/modules/fields/custom-google-maps.d.ts.map +1 -1
  159. package/dist/js/modules/fields/custom-link.d.ts +2 -2
  160. package/dist/js/modules/fields/custom-link.d.ts.map +1 -1
  161. package/dist/js/modules/fields/custom-maps.d.ts +2 -2
  162. package/dist/js/modules/fields/custom-maps.d.ts.map +1 -1
  163. package/dist/js/modules/fields/date-picker.d.ts +2 -2
  164. package/dist/js/modules/fields/date-picker.d.ts.map +1 -1
  165. package/dist/js/modules/fields/file-upload.d.ts +2 -2
  166. package/dist/js/modules/fields/file-upload.d.ts.map +1 -1
  167. package/dist/js/modules/fields/hidden.d.ts +2 -2
  168. package/dist/js/modules/fields/hidden.d.ts.map +1 -1
  169. package/dist/js/modules/fields/index.d.ts +2 -2
  170. package/dist/js/modules/fields/index.d.ts.map +1 -1
  171. package/dist/js/modules/fields/password-validation.d.ts +2 -2
  172. package/dist/js/modules/fields/password-validation.d.ts.map +1 -1
  173. package/dist/js/modules/fields/phone-country.d.ts +2 -2
  174. package/dist/js/modules/fields/phone-country.d.ts.map +1 -1
  175. package/dist/js/modules/fields/repeater.d.ts +2 -2
  176. package/dist/js/modules/fields/repeater.d.ts.map +1 -1
  177. package/dist/js/modules/fields/rich-text.d.ts +2 -2
  178. package/dist/js/modules/fields/rich-text.d.ts.map +1 -1
  179. package/dist/js/modules/fields/shared.d.ts +1 -0
  180. package/dist/js/modules/fields/shared.d.ts.map +1 -1
  181. package/dist/js/modules/fields/signature.d.ts +2 -2
  182. package/dist/js/modules/fields/signature.d.ts.map +1 -1
  183. package/dist/js/modules/fields/summary.d.ts +2 -2
  184. package/dist/js/modules/fields/summary.d.ts.map +1 -1
  185. package/dist/js/modules/fields/survey-likert.d.ts +2 -2
  186. package/dist/js/modules/fields/survey-likert.d.ts.map +1 -1
  187. package/dist/js/modules/fields/survey-rank.d.ts +2 -2
  188. package/dist/js/modules/fields/survey-rank.d.ts.map +1 -1
  189. package/dist/js/modules/fields/survey-rating.d.ts +2 -2
  190. package/dist/js/modules/fields/survey-rating.d.ts.map +1 -1
  191. package/dist/js/modules/fields/table.d.ts +2 -2
  192. package/dist/js/modules/fields/table.d.ts.map +1 -1
  193. package/dist/js/modules/fields/text-limit.d.ts +2 -2
  194. package/dist/js/modules/fields/text-limit.d.ts.map +1 -1
  195. package/dist/js/modules/fields/upload-manager.d.ts +2 -2
  196. package/dist/js/modules/fields/upload-manager.d.ts.map +1 -1
  197. package/dist/js/modules/loader.d.ts +10 -4
  198. package/dist/js/modules/loader.d.ts.map +1 -1
  199. package/dist/js/modules/payments/bpoint.d.ts +1 -1
  200. package/dist/js/modules/payments/bpoint.d.ts.map +1 -1
  201. package/dist/js/modules/payments/eway.d.ts +1 -1
  202. package/dist/js/modules/payments/eway.d.ts.map +1 -1
  203. package/dist/js/modules/payments/factories.d.ts +7 -7
  204. package/dist/js/modules/payments/factories.d.ts.map +1 -1
  205. package/dist/js/modules/payments/go-cardless.d.ts +1 -1
  206. package/dist/js/modules/payments/go-cardless.d.ts.map +1 -1
  207. package/dist/js/modules/payments/index.d.ts +2 -2
  208. package/dist/js/modules/payments/index.d.ts.map +1 -1
  209. package/dist/js/modules/payments/mollie.d.ts +1 -1
  210. package/dist/js/modules/payments/mollie.d.ts.map +1 -1
  211. package/dist/js/modules/payments/moneris.d.ts +1 -1
  212. package/dist/js/modules/payments/moneris.d.ts.map +1 -1
  213. package/dist/js/modules/payments/opayo.d.ts +1 -1
  214. package/dist/js/modules/payments/opayo.d.ts.map +1 -1
  215. package/dist/js/modules/payments/paddle.d.ts +1 -1
  216. package/dist/js/modules/payments/paddle.d.ts.map +1 -1
  217. package/dist/js/modules/payments/paypal.d.ts +1 -1
  218. package/dist/js/modules/payments/paypal.d.ts.map +1 -1
  219. package/dist/js/modules/payments/payway.d.ts +1 -1
  220. package/dist/js/modules/payments/payway.d.ts.map +1 -1
  221. package/dist/js/modules/payments/square.d.ts +1 -1
  222. package/dist/js/modules/payments/square.d.ts.map +1 -1
  223. package/dist/js/modules/payments/stripe.d.ts +1 -1
  224. package/dist/js/modules/payments/stripe.d.ts.map +1 -1
  225. package/dist/js/modules/payments/utils.d.ts +6 -0
  226. package/dist/js/modules/payments/utils.d.ts.map +1 -1
  227. package/dist/js/modules/registry.d.ts +6 -4
  228. package/dist/js/modules/registry.d.ts.map +1 -1
  229. package/dist/js/submit/pipeline.d.ts.map +1 -1
  230. package/dist/js/theme/browser-theme-state.generated.d.ts +24 -0
  231. package/dist/js/theme/browser-theme-state.generated.d.ts.map +1 -0
  232. package/dist/js/theme/theme-classes.d.ts +3 -3
  233. package/dist/js/theme/theme-classes.d.ts.map +1 -1
  234. package/dist/js/transport/forms-api.d.ts +5 -3
  235. package/dist/js/transport/forms-api.d.ts.map +1 -1
  236. package/dist/js/utils/country-from-ip.d.ts +2 -2
  237. package/dist/js/utils/country-from-ip.d.ts.map +1 -1
  238. package/dist/js/utils/csrf.d.ts +17 -0
  239. package/dist/js/utils/csrf.d.ts.map +1 -0
  240. package/dist/js/utils/field-references.parser.d.ts +1 -0
  241. package/dist/js/utils/field-references.parser.d.ts.map +1 -1
  242. package/dist/js/utils/field-references.resolver.d.ts.map +1 -1
  243. package/dist/js/utils/field-references.types.d.ts +1 -0
  244. package/dist/js/utils/field-references.types.d.ts.map +1 -1
  245. package/dist/js/utils/http.d.ts +3 -1
  246. package/dist/js/utils/http.d.ts.map +1 -1
  247. package/dist/js/utils/request-profile.d.ts +4 -0
  248. package/dist/js/utils/request-profile.d.ts.map +1 -0
  249. package/dist/js/utils/unload-warning.d.ts.map +1 -1
  250. package/dist/js/validation/rules/email.d.ts.map +1 -1
  251. package/dist/js/validation/rules/match.d.ts.map +1 -1
  252. package/dist/js/validation/rules/number.d.ts.map +1 -1
  253. package/dist/js/validation/rules/required.d.ts.map +1 -1
  254. package/dist/js/validation/rules/shared.d.ts.map +1 -1
  255. package/dist/js/validation/rules/url.d.ts.map +1 -1
  256. package/dist/js/validation/skip.d.ts +7 -0
  257. package/dist/js/validation/skip.d.ts.map +1 -0
  258. package/dist/js/validation/submit-readiness.d.ts.map +1 -1
  259. package/dist/js/validation/validator.d.ts.map +1 -1
  260. package/package.json +43 -12
  261. package/src/css/formie-base.css +104 -1
  262. package/src/css/theme/_messages.css +2 -0
  263. package/src/css/theme/_tokens.css +31 -25
  264. package/src/css/theme/fields/_signature.css +2 -1
  265. package/src/css/theme/forms/_form.css +5 -1
  266. package/src/index.ts +13 -8
  267. package/src/js/contracts/client.ts +5 -3
  268. package/src/js/contracts/common.ts +5 -6
  269. package/src/js/contracts/modules.ts +41 -12
  270. package/src/js/contracts/schema.ts +21 -43
  271. package/src/js/contracts/theme.ts +6 -1
  272. package/src/js/core/client-rendered-modules.ts +69 -0
  273. package/src/js/core/create-formie-client.ts +119 -73
  274. package/src/js/core/field-error-aria.ts +93 -0
  275. package/src/js/core/hydrate-modules.ts +54 -29
  276. package/src/js/core/submit-result-state.ts +34 -45
  277. package/src/js/core/submit-result-ui.ts +21 -65
  278. package/src/js/core/validation-focus.ts +20 -20
  279. package/src/js/modules/address/address-finder.ts +1 -1
  280. package/src/js/modules/address/factories.ts +15 -13
  281. package/src/js/modules/address/google-address.ts +10 -6
  282. package/src/js/modules/address/index.ts +2 -2
  283. package/src/js/modules/address/loqate.ts +1 -1
  284. package/src/js/modules/address/place-kit.ts +1 -1
  285. package/src/js/modules/captchas/captcha-eu.ts +2 -2
  286. package/src/js/modules/captchas/factories.ts +66 -42
  287. package/src/js/modules/captchas/friendly-captcha-v1.ts +12 -2
  288. package/src/js/modules/captchas/friendly-captcha-v2.ts +4 -2
  289. package/src/js/modules/captchas/hcaptcha.ts +5 -5
  290. package/src/js/modules/captchas/index.ts +2 -2
  291. package/src/js/modules/captchas/recaptcha-enterprise.ts +2 -2
  292. package/src/js/modules/captchas/recaptcha-v2-checkbox.ts +3 -3
  293. package/src/js/modules/captchas/recaptcha-v2-invisible.ts +2 -2
  294. package/src/js/modules/captchas/recaptcha-v3.ts +2 -2
  295. package/src/js/modules/captchas/snaptcha.ts +1 -1
  296. package/src/js/modules/captchas/turnstile.ts +3 -3
  297. package/src/js/modules/fields/address-country.ts +6 -4
  298. package/src/js/modules/fields/address-state.ts +20 -12
  299. package/src/js/modules/fields/calculations.ts +5 -3
  300. package/src/js/modules/fields/checkbox-radio.ts +24 -42
  301. package/src/js/modules/fields/combobox.ts +25 -9
  302. package/src/js/modules/fields/conditions/config.ts +17 -20
  303. package/src/js/modules/fields/conditions/effects.ts +23 -26
  304. package/src/js/modules/fields/conditions/evaluator.ts +21 -29
  305. package/src/js/modules/fields/conditions/references.ts +16 -5
  306. package/src/js/modules/fields/conditions/submission-context.ts +80 -0
  307. package/src/js/modules/fields/conditions/types.ts +3 -1
  308. package/src/js/modules/fields/conditions/values.ts +31 -6
  309. package/src/js/modules/fields/conditions.ts +59 -18
  310. package/src/js/modules/fields/custom-google-maps.ts +5 -3
  311. package/src/js/modules/fields/custom-link.ts +5 -3
  312. package/src/js/modules/fields/custom-maps.ts +5 -3
  313. package/src/js/modules/fields/date-picker.ts +40 -4
  314. package/src/js/modules/fields/file-upload.ts +19 -10
  315. package/src/js/modules/fields/hidden.ts +5 -3
  316. package/src/js/modules/fields/index.ts +2 -2
  317. package/src/js/modules/fields/password-validation.ts +5 -3
  318. package/src/js/modules/fields/phone-country.ts +33 -6
  319. package/src/js/modules/fields/repeater.ts +5 -3
  320. package/src/js/modules/fields/rich-text.ts +20 -4
  321. package/src/js/modules/fields/shared.ts +13 -0
  322. package/src/js/modules/fields/signature.ts +64 -6
  323. package/src/js/modules/fields/summary.ts +8 -20
  324. package/src/js/modules/fields/survey-likert.ts +5 -3
  325. package/src/js/modules/fields/survey-rank.ts +21 -3
  326. package/src/js/modules/fields/survey-rating.ts +17 -3
  327. package/src/js/modules/fields/table.ts +5 -3
  328. package/src/js/modules/fields/text-limit.ts +5 -3
  329. package/src/js/modules/fields/upload-manager.ts +190 -49
  330. package/src/js/modules/loader.ts +345 -281
  331. package/src/js/modules/payments/bpoint.ts +2 -2
  332. package/src/js/modules/payments/eway.ts +2 -2
  333. package/src/js/modules/payments/factories.ts +53 -52
  334. package/src/js/modules/payments/go-cardless.ts +1 -1
  335. package/src/js/modules/payments/index.ts +2 -2
  336. package/src/js/modules/payments/mollie.ts +1 -1
  337. package/src/js/modules/payments/moneris.ts +2 -2
  338. package/src/js/modules/payments/opayo.ts +21 -8
  339. package/src/js/modules/payments/paddle.ts +10 -6
  340. package/src/js/modules/payments/payment.ts +22 -18
  341. package/src/js/modules/payments/paypal.ts +1 -1
  342. package/src/js/modules/payments/payway.ts +2 -2
  343. package/src/js/modules/payments/square.ts +2 -2
  344. package/src/js/modules/payments/stripe.ts +5 -5
  345. package/src/js/modules/payments/utils.ts +14 -0
  346. package/src/js/modules/registry.ts +19 -11
  347. package/src/js/submit/pipeline.ts +10 -11
  348. package/src/js/theme/browser-theme-state.generated.ts +25 -0
  349. package/src/js/theme/theme-classes.ts +3 -3
  350. package/src/js/transport/forms-api.ts +66 -67
  351. package/src/js/utils/country-from-ip.ts +14 -9
  352. package/src/js/utils/csrf.ts +136 -0
  353. package/src/js/utils/field-references.parser.ts +13 -113
  354. package/src/js/utils/field-references.resolver.ts +27 -64
  355. package/src/js/utils/field-references.row-scope.ts +1 -1
  356. package/src/js/utils/field-references.types.ts +1 -0
  357. package/src/js/utils/http.ts +5 -5
  358. package/src/js/utils/request-profile.ts +10 -0
  359. package/src/js/utils/unload-warning.ts +12 -4
  360. package/src/js/validation/rules/email.ts +3 -5
  361. package/src/js/validation/rules/match.ts +2 -1
  362. package/src/js/validation/rules/minmax.ts +4 -43
  363. package/src/js/validation/rules/number.ts +3 -47
  364. package/src/js/validation/rules/pattern.ts +3 -8
  365. package/src/js/validation/rules/required.ts +2 -1
  366. package/src/js/validation/rules/shared.ts +5 -1
  367. package/src/js/validation/rules/url.ts +3 -10
  368. package/src/js/validation/skip.ts +9 -0
  369. package/src/js/validation/submit-readiness.ts +9 -2
  370. package/src/js/validation/validator.ts +35 -59
  371. package/dist/chunks/calculations-DERi2xaC.js +0 -299
  372. package/dist/chunks/conditions-65kBcFWW.js +0 -424
  373. package/dist/chunks/country-from-ip-BwxKaBuJ.js +0 -26
  374. package/dist/chunks/field-references.resolver-CHwn0G0L.js +0 -145
  375. package/dist/chunks/friendly-captcha-v1-C_2reOXr.js +0 -31
  376. package/dist/chunks/google-address-BH3Zhi06.js +0 -161
  377. package/dist/chunks/http-D-JExro7.js +0 -27
  378. package/dist/chunks/opayo-CR0DtsLa.js +0 -179
  379. package/dist/chunks/rich-text-Bg_--4TG.js +0 -349
  380. package/dist/js/modules/fields/conditions/transforms.d.ts +0 -3
  381. package/dist/js/modules/fields/conditions/transforms.d.ts.map +0 -1
  382. package/src/js/modules/fields/conditions/transforms.ts +0 -206
  383. package/src/js/modules/payments/stub-payment-module.ts +0 -87
@@ -2,8 +2,8 @@ import flatpickr from 'flatpickr';
2
2
  import * as flatpickrLocales from 'flatpickr/dist/l10n/index.js';
3
3
  import flatpickrCss from 'flatpickr/dist/flatpickr.css?inline';
4
4
 
5
- import type { FormieModuleDefinition } from '#contracts/modules';
6
- import { dispatchFieldEvent, getModuleFieldContainers } from '#modules/fields/shared';
5
+ import type { BrowserModuleDefinition } from '#contracts/modules';
6
+ import { bindConditionalClear, dispatchFieldEvent, getModuleFieldContainers } from '#modules/fields/shared';
7
7
  import { ensureModuleStyles } from '#modules/styles';
8
8
  import { createDebug } from '#utils/debug';
9
9
 
@@ -30,6 +30,8 @@ type DatePickerOptions = {
30
30
 
31
31
  type FlatpickrInstanceLike = {
32
32
  destroy: () => void;
33
+ selectedDates: Date[];
34
+ setDate: (dates: Date[], triggerChange?: boolean) => void;
33
35
  };
34
36
 
35
37
  type FlatpickrInput = HTMLInputElement & {
@@ -43,6 +45,7 @@ type FlatpickrChangeInstance = {
43
45
 
44
46
  function attributesPlugin() {
45
47
  return (instance: { input: HTMLInputElement; altInput?: HTMLInputElement | undefined; loadedPlugins: string[] }) => {
48
+ const originalAttributes = new Map<string, string>();
46
49
  return {
47
50
  onReady: () => {
48
51
  if (!instance.altInput) {
@@ -60,6 +63,7 @@ function attributesPlugin() {
60
63
 
61
64
  const value = instance.input.getAttribute(attribute);
62
65
  if (value !== null) {
66
+ originalAttributes.set(attribute, value);
63
67
  instance.altInput?.setAttribute(attribute, value);
64
68
  }
65
69
 
@@ -68,6 +72,15 @@ function attributesPlugin() {
68
72
 
69
73
  instance.loadedPlugins.push('formie-attributes');
70
74
  },
75
+ onDestroy: () => {
76
+ // Conditional fields and page navigation can mount this input again.
77
+ // Restore the markers and labels moved onto the temporary alt input.
78
+ originalAttributes.forEach((value, attribute) => {
79
+ if (!instance.input.hasAttribute(attribute)) {
80
+ instance.input.setAttribute(attribute, value);
81
+ }
82
+ });
83
+ },
71
84
  };
72
85
  };
73
86
  }
@@ -285,6 +298,12 @@ function initDatePicker(input: FlatpickrInput, options: DatePickerOptions): () =
285
298
  if (startDate) {
286
299
  defaultOptions.defaultDate = endDate ? [startDate, endDate] : [startDate];
287
300
  }
301
+ } else if (input.value) {
302
+ const defaultDate = parseSubmissionDate(input.value);
303
+
304
+ if (defaultDate) {
305
+ defaultOptions.defaultDate = defaultDate;
306
+ }
288
307
  }
289
308
 
290
309
  const mergedOptions = {
@@ -303,6 +322,19 @@ function initDatePicker(input: FlatpickrInput, options: DatePickerOptions): () =
303
322
 
304
323
  const instance = flatpickr(input, mergedOptions) as FlatpickrInstanceLike;
305
324
  input._formieFlatpickr = instance;
325
+ const initialDates = instance.selectedDates.map((date) => new Date(date.getTime()));
326
+ const form = input.form;
327
+ const onReset = (event: Event) => {
328
+ // Flatpickr uses hidden transport inputs, whose values survive native reset.
329
+ // Restore the picker and its range inputs together after the native controls.
330
+ queueMicrotask(() => {
331
+ if (!event.defaultPrevented) {
332
+ instance.setDate(initialDates, true);
333
+ }
334
+ });
335
+ };
336
+ form?.addEventListener('reset', onReset);
337
+ const unbindConditionalClear = bindConditionalClear(input, () => instance.setDate([], true));
306
338
  debug.log('Initialized.', {
307
339
  inputName: input.name,
308
340
  isRange,
@@ -314,6 +346,8 @@ function initDatePicker(input: FlatpickrInput, options: DatePickerOptions): () =
314
346
  });
315
347
 
316
348
  return () => {
349
+ unbindConditionalClear();
350
+ form?.removeEventListener('reset', onReset);
317
351
  instance.destroy();
318
352
  delete input._formieFlatpickr;
319
353
  debug.log('Destroyed.', {
@@ -322,8 +356,10 @@ function initDatePicker(input: FlatpickrInput, options: DatePickerOptions): () =
322
356
  };
323
357
  }
324
358
 
325
- export const datePickerModule: FormieModuleDefinition = {
326
- id: MODULE_ID,
359
+ export const datePickerModule: BrowserModuleDefinition = {
360
+ moduleId: `formie:${MODULE_ID}`,
361
+ version: 2,
362
+ surfaces: ['server-rendered', 'client-rendered', 'cp-edit'],
327
363
  kind: 'field',
328
364
  match: (ctx) => {
329
365
  return !!ctx.target.querySelector(INPUT_SELECTOR);
@@ -1,6 +1,6 @@
1
1
  import fileUploadCss from '#theme-css/fields/_file.css?inline';
2
2
 
3
- import type { FormieModuleDefinition } from '#contracts/modules';
3
+ import type { BrowserModuleDefinition } from '#contracts/modules';
4
4
  import { dispatchFieldEvent, releaseFormValidators, retainFormValidators } from '#modules/fields/shared';
5
5
  import { ensureModuleStyles } from '#modules/styles';
6
6
  import { getFieldModuleEventName, getFileUploadEventName, getFormStateEventName } from '#utils/event-names';
@@ -13,6 +13,7 @@ const FILE_UPLOAD_KEY_ATTR = 'data-formie-file-upload-key';
13
13
  const HYDRATE_ENDPOINT_ATTR = 'data-formie-file-upload-hydrate-endpoint';
14
14
  const HIDDEN_INPUT_ANCHOR_ATTR = 'data-formie-file-upload-anchor';
15
15
  const HIDDEN_INPUT_VALUE_ATTR = 'data-formie-file-upload-asset-id';
16
+ const HIDDEN_INPUT_ENTRY_ATTR = 'data-formie-file-upload-entry';
16
17
  const FILE_VALIDATORS = [
17
18
  'fileLimit',
18
19
  'fileSizeMinLimit',
@@ -93,7 +94,8 @@ function getUploadedAssetInputs(field: HTMLElement, input: HTMLInputElement): HT
93
94
  const assetInputName = getUploadedAssetInputName(input);
94
95
 
95
96
  return getHiddenInputs(field).filter((hiddenInput) => {
96
- return hiddenInput.name === assetInputName && hiddenInput.value.trim() !== '';
97
+ return hiddenInput.hasAttribute(HIDDEN_INPUT_VALUE_ATTR)
98
+ || (hiddenInput.name === assetInputName && hiddenInput.value.trim() !== '');
97
99
  });
98
100
  }
99
101
 
@@ -186,7 +188,7 @@ function readSummaryItems(summaryRoot: HTMLElement | null): UploadedAsset[] {
186
188
  function readUploadedAssetsFromHiddenInputs(field: HTMLElement, input: HTMLInputElement): UploadedAsset[] {
187
189
  return getUploadedAssetInputs(field, input).map((hiddenInput) => {
188
190
  return {
189
- assetId: toPositiveInt(hiddenInput.value),
191
+ assetId: toPositiveInt(hiddenInput.getAttribute(HIDDEN_INPUT_VALUE_ATTR)) ?? toPositiveInt(hiddenInput.value),
190
192
  filename: '',
191
193
  };
192
194
  }).filter((asset) => {
@@ -349,21 +351,25 @@ function updateUploadedAssetInputs(field: HTMLElement, input: HTMLInputElement,
349
351
  let insertionPoint: HTMLInputElement = anchor;
350
352
  // The upload event returns persisted asset ids; convert those back into the
351
353
  // hidden-input shape the backend expects on subsequent submit/save actions.
352
- const anchorName = getUploadedAssetInputName(input);
353
- getUploadedAssetInputs(field, input).forEach((hiddenInput) => {
354
+ const baseName = getFileValueName(input);
355
+ getHiddenInputs(field).filter((hiddenInput) => {
356
+ return hiddenInput.hasAttribute(HIDDEN_INPUT_ENTRY_ATTR)
357
+ || (hiddenInput.name === `${baseName}[]` && hiddenInput.value.trim() !== '');
358
+ }).forEach((hiddenInput) => {
354
359
  hiddenInput.remove();
355
360
  });
356
361
 
357
- uploadedAssets.forEach((asset) => {
362
+ uploadedAssets.forEach((asset, index) => {
358
363
  if (!asset.assetId) {
359
364
  return;
360
365
  }
361
366
 
362
367
  const hiddenInput = document.createElement('input');
363
368
  hiddenInput.type = 'hidden';
364
- hiddenInput.name = anchorName;
369
+ hiddenInput.name = `${baseName}[${index}][assetId]`;
365
370
  hiddenInput.value = String(asset.assetId);
366
- hiddenInput.setAttribute(HIDDEN_INPUT_VALUE_ATTR, 'true');
371
+ hiddenInput.setAttribute(HIDDEN_INPUT_ENTRY_ATTR, 'true');
372
+ hiddenInput.setAttribute(HIDDEN_INPUT_VALUE_ATTR, String(asset.assetId));
367
373
  insertionPoint.insertAdjacentElement('afterend', hiddenInput);
368
374
  insertionPoint = hiddenInput;
369
375
  });
@@ -425,6 +431,7 @@ async function hydrateUploadedAssets(field: HTMLElement, input: HTMLInputElement
425
431
 
426
432
  const hydrateEndpoint = input.getAttribute(HYDRATE_ENDPOINT_ATTR)?.trim() || '/actions/formie/file-upload/hydrate';
427
433
  const response = await requestJson<FileUploadHydrateResponse>(hydrateEndpoint, {
434
+ profile: field.closest('form')?.dataset.formieRequestProfile as import('@verbb/formie-core').BrowserRequestOptions['profile'],
428
435
  method: 'POST',
429
436
  body: buildHydrateFormData(field, input, assetIds),
430
437
  });
@@ -657,8 +664,10 @@ function bindFileUploadInput(field: HTMLElement, input: HTMLInputElement, form:
657
664
  };
658
665
  }
659
666
 
660
- export const fileUploadModule: FormieModuleDefinition = {
661
- id: MODULE_ID,
667
+ export const fileUploadModule: BrowserModuleDefinition = {
668
+ moduleId: `formie:${MODULE_ID}`,
669
+ version: 2,
670
+ surfaces: ['server-rendered', 'client-rendered', 'cp-edit'],
662
671
  kind: 'field',
663
672
  match: (ctx) => {
664
673
  return !!ctx.target.querySelector(INPUT_SELECTOR);
@@ -1,4 +1,4 @@
1
- import type { FormieModuleDefinition } from '#contracts/modules';
1
+ import type { BrowserModuleDefinition } from '#contracts/modules';
2
2
  import { getModuleFieldContainers } from '#modules/fields/shared';
3
3
 
4
4
  const INPUT_SELECTOR = 'input[data-formie-hidden-input]';
@@ -22,8 +22,10 @@ function getCookieValue(name: string): string | null {
22
22
  return null;
23
23
  }
24
24
 
25
- export const hiddenModule: FormieModuleDefinition = {
26
- id: 'hidden',
25
+ export const hiddenModule: BrowserModuleDefinition = {
26
+ moduleId: 'formie:hidden',
27
+ version: 2,
28
+ surfaces: ['server-rendered', 'client-rendered', 'cp-edit'],
27
29
  kind: 'field',
28
30
  match: (ctx) => {
29
31
  return !!ctx.target.querySelector(INPUT_SELECTOR);
@@ -1,6 +1,6 @@
1
- import type { FormieModuleDefinition } from '#contracts/modules';
1
+ import type { BrowserModuleDefinition } from '#contracts/modules';
2
2
 
3
- export const builtinFieldModuleLoaders: Record<string, () => Promise<FormieModuleDefinition>> = {
3
+ export const builtinFieldModuleLoaders: Record<string, () => Promise<BrowserModuleDefinition>> = {
4
4
  // Keep the builtin map flat and explicit so manifest ids remain the source of
5
5
  // truth for lazy-loading first-party field enhancements.
6
6
  'calculations': () => import('#modules/fields/calculations').then((module) => module.calculationsModule),
@@ -1,6 +1,6 @@
1
1
  import { getTextLimitMetrics } from '@verbb/formie-core';
2
2
 
3
- import type { FormieModuleDefinition } from '#contracts/modules';
3
+ import type { BrowserModuleDefinition } from '#contracts/modules';
4
4
  import { getModuleFieldTarget, releaseFormValidators, retainFormValidators } from '#modules/fields/shared';
5
5
 
6
6
  const INPUT_SELECTOR = 'input[data-formie-password-input]';
@@ -104,8 +104,10 @@ function unregisterValidators(form: HTMLFormElement | null): void {
104
104
  releaseFormValidators(form, VALIDATOR_SCOPE, PASSWORD_VALIDATORS);
105
105
  }
106
106
 
107
- export const passwordValidationModule: FormieModuleDefinition = {
108
- id: 'password-validation',
107
+ export const passwordValidationModule: BrowserModuleDefinition = {
108
+ moduleId: 'formie:password-validation',
109
+ version: 2,
110
+ surfaces: ['server-rendered', 'client-rendered', 'cp-edit'],
109
111
  kind: 'field',
110
112
  match: (ctx) => {
111
113
  return !!ctx.target.querySelector(`${INPUT_SELECTOR}[data-formie-password-min-length], ${INPUT_SELECTOR}[data-formie-password-require-uppercase], ${INPUT_SELECTOR}[data-formie-password-require-lowercase], ${INPUT_SELECTOR}[data-formie-password-require-special-character]`);
@@ -1,7 +1,7 @@
1
1
  import intlTelInput from 'intl-tel-input';
2
2
  import intlTelInputCss from 'intl-tel-input/styles?inline';
3
3
 
4
- import type { FormieModuleDefinition } from '#contracts/modules';
4
+ import type { BrowserModuleDefinition } from '#contracts/modules';
5
5
  import { dispatchFieldEvent, getModuleFieldContainers, releaseFormValidators, retainFormValidators } from '#modules/fields/shared';
6
6
  import { ensureModuleStyles } from '#modules/styles';
7
7
  import { createGeoIpLookup } from '#utils/country-from-ip';
@@ -81,7 +81,7 @@ function unregisterValidators(form: HTMLFormElement | null): void {
81
81
  releaseFormValidators(form, VALIDATOR_SCOPE, [PHONE_COUNTRY_VALIDATOR]);
82
82
  }
83
83
 
84
- function buildOptions(options: PhoneCountryOptions): Record<string, unknown> {
84
+ function buildOptions(options: PhoneCountryOptions, form: HTMLFormElement | null): Record<string, unknown> {
85
85
  const intlOptions: Record<string, unknown> = {
86
86
  allowDropdown: true,
87
87
  nationalMode: false,
@@ -116,7 +116,7 @@ function buildOptions(options: PhoneCountryOptions): Record<string, unknown> {
116
116
  intlOptions.initialCountry = options.countryDefaultValue.toLowerCase();
117
117
  } else if (options.countryPreselectFromIp) {
118
118
  intlOptions.initialCountry = 'auto';
119
- intlOptions.geoIpLookup = createGeoIpLookup(options.countryFromIpAction);
119
+ intlOptions.geoIpLookup = createGeoIpLookup(options.countryFromIpAction, form);
120
120
  }
121
121
 
122
122
  if (Array.isArray(intlOptions.onlyCountries) && typeof intlOptions.initialCountry === 'string') {
@@ -130,7 +130,7 @@ function buildOptions(options: PhoneCountryOptions): Record<string, unknown> {
130
130
  }
131
131
 
132
132
  function initPhoneField(phoneInput: PhoneInput, countryInput: HTMLInputElement, options: PhoneCountryOptions): () => void {
133
- const intlOptions = buildOptions(options);
133
+ const intlOptions = buildOptions(options, phoneInput.closest('form'));
134
134
 
135
135
  dispatchFieldEvent(phoneInput, MODULE_ID, 'before-init', {
136
136
  phoneCountry: phoneInput,
@@ -163,6 +163,30 @@ function initPhoneField(phoneInput: PhoneInput, countryInput: HTMLInputElement,
163
163
  phoneInput.addEventListener('countrychange', syncCountry);
164
164
  phoneInput.addEventListener('blur', syncCountry);
165
165
  syncCountry();
166
+
167
+ // Keep the country dropdown button in sync when the tel input is enabled/disabled after
168
+ // init (multi-page page-hidden, or conditions). intl-tel-input disables the button to match
169
+ // a disabled input at init, but won't re-enable it when `disabled` is later removed.
170
+ const syncCountryButton = () => {
171
+ const button = phoneInput.closest('.iti')?.querySelector('.iti__selected-country');
172
+
173
+ if (!(button instanceof HTMLElement)) {
174
+ return;
175
+ }
176
+
177
+ if (phoneInput.disabled) {
178
+ button.setAttribute('disabled', 'true');
179
+ } else {
180
+ button.removeAttribute('disabled');
181
+ }
182
+ };
183
+
184
+ syncCountryButton();
185
+ const countryButtonObserver = new MutationObserver(() => {
186
+ syncCountryButton();
187
+ });
188
+ countryButtonObserver.observe(phoneInput, { attributes: true, attributeFilter: ['disabled'] });
189
+
166
190
  debug.log('Initialized.', {
167
191
  inputName: phoneInput.name,
168
192
  restrictedCountries: phoneInput.restrictedCountries,
@@ -177,6 +201,7 @@ function initPhoneField(phoneInput: PhoneInput, countryInput: HTMLInputElement,
177
201
  return () => {
178
202
  phoneInput.removeEventListener('countrychange', syncCountry);
179
203
  phoneInput.removeEventListener('blur', syncCountry);
204
+ countryButtonObserver.disconnect();
180
205
  validator.destroy();
181
206
  delete phoneInput.allowedCountries;
182
207
  delete phoneInput.validator;
@@ -188,8 +213,10 @@ function initPhoneField(phoneInput: PhoneInput, countryInput: HTMLInputElement,
188
213
  };
189
214
  }
190
215
 
191
- export const phoneCountryModule: FormieModuleDefinition = {
192
- id: MODULE_ID,
216
+ export const phoneCountryModule: BrowserModuleDefinition = {
217
+ moduleId: `formie:${MODULE_ID}`,
218
+ version: 2,
219
+ surfaces: ['server-rendered', 'client-rendered', 'cp-edit'],
193
220
  kind: 'field',
194
221
  match: (ctx) => {
195
222
  return !!ctx.target.querySelector(PHONE_SELECTOR);
@@ -1,6 +1,6 @@
1
1
  import repeaterCss from '#theme-css/fields/_repeater.css?inline';
2
2
 
3
- import type { FormieModuleDefinition } from '#contracts/modules';
3
+ import type { BrowserModuleDefinition } from '#contracts/modules';
4
4
  import { dispatchFieldEvent, getTemplateSource, getTemplateSourceHtml } from '#modules/fields/shared';
5
5
  import { ensureModuleStyles } from '#modules/styles';
6
6
  import { sleep } from '#utils/async';
@@ -188,8 +188,10 @@ function bindRepeaterField(field: HTMLElement): () => void {
188
188
  };
189
189
  }
190
190
 
191
- export const repeaterModule: FormieModuleDefinition = {
192
- id: MODULE_ID,
191
+ export const repeaterModule: BrowserModuleDefinition = {
192
+ moduleId: `formie:${MODULE_ID}`,
193
+ version: 2,
194
+ surfaces: ['server-rendered', 'client-rendered', 'cp-edit'],
193
195
  kind: 'field',
194
196
  match: (ctx) => {
195
197
  return ctx.target instanceof HTMLElement && (
@@ -21,7 +21,7 @@ import strikethroughIcon from '#icons/rich-text/strikethrough.svg?raw';
21
21
  import ulistIcon from '#icons/rich-text/ulist.svg?raw';
22
22
  import underlineIcon from '#icons/rich-text/underline.svg?raw';
23
23
 
24
- import type { FormieModuleDefinition } from '#contracts/modules';
24
+ import type { BrowserModuleDefinition } from '#contracts/modules';
25
25
  import { dispatchFieldEvent, getModuleFieldContainers } from '#modules/fields/shared';
26
26
  import { ensureModuleStyles } from '#modules/styles';
27
27
 
@@ -141,7 +141,9 @@ function initRichTextField(container: HTMLElement, input: RichTextInput, options
141
141
  actions: getActions(options.buttons),
142
142
  onChange: (html: string) => {
143
143
  const emptyParagraph = '<p><br></p>';
144
- input.value = input.placeholder && html === emptyParagraph ? '' : html;
144
+ // Treat Pell's empty document as blank so required validation matches
145
+ // a never-touched textarea (and so clearing the editor can fail required).
146
+ input.value = (!html || html === emptyParagraph) ? '' : html;
145
147
  // Bubble both generic input and a namespaced rich-text change hook.
146
148
  input.dispatchEvent(new Event('input', { bubbles: true }));
147
149
  dispatchFieldEvent(input, MODULE_ID, 'populate', {
@@ -166,6 +168,17 @@ function initRichTextField(container: HTMLElement, input: RichTextInput, options
166
168
  input.richText = editor;
167
169
  editor.content.innerHTML = input.value || '';
168
170
 
171
+ const form = input.form;
172
+ const onReset = (event: Event) => {
173
+ // Wait for the textarea to regain its default value before updating Pell.
174
+ queueMicrotask(() => {
175
+ if (!event.defaultPrevented) {
176
+ editor.content.innerHTML = input.value || '';
177
+ }
178
+ });
179
+ };
180
+ form?.addEventListener('reset', onReset);
181
+
169
182
  if (input.placeholder) {
170
183
  editor.content.setAttribute('data-placeholder', input.placeholder);
171
184
  }
@@ -175,13 +188,16 @@ function initRichTextField(container: HTMLElement, input: RichTextInput, options
175
188
  });
176
189
 
177
190
  return () => {
191
+ form?.removeEventListener('reset', onReset);
178
192
  container.innerHTML = '';
179
193
  delete input.richText;
180
194
  };
181
195
  }
182
196
 
183
- export const richTextModule: FormieModuleDefinition = {
184
- id: MODULE_ID,
197
+ export const richTextModule: BrowserModuleDefinition = {
198
+ moduleId: `formie:${MODULE_ID}`,
199
+ version: 2,
200
+ surfaces: ['server-rendered', 'client-rendered', 'cp-edit'],
185
201
  kind: 'field',
186
202
  match: (ctx) => {
187
203
  return ctx.target instanceof HTMLElement && hasRichTextField(ctx.target);
@@ -17,6 +17,19 @@ const fallbackCssEscape = (value: string): string => {
17
17
  };
18
18
  const validatorRegistrations = new WeakMap<HTMLFormElement, Map<string, number>>();
19
19
 
20
+ // Conditions clear ordinary controls directly. Enhanced controls also need to
21
+ // clear their hidden transport values before their modules are unmounted.
22
+ export function bindConditionalClear(input: HTMLElement, clear: () => void): () => void {
23
+ const root = input.getRootNode();
24
+ const handler = (event: Event) => {
25
+ if (event.target instanceof Element && event.target.contains(input)) {
26
+ clear();
27
+ }
28
+ };
29
+ root.addEventListener('formie:field:clear', handler);
30
+ return () => root.removeEventListener('formie:field:clear', handler);
31
+ }
32
+
20
33
  export function escapeSelectorValue(value: string): string {
21
34
  if (typeof window.CSS?.escape === 'function') {
22
35
  return window.CSS.escape(value);
@@ -1,8 +1,8 @@
1
1
  import SignaturePad from 'signature_pad';
2
2
  import signatureCss from '#theme-css/fields/_signature.css?inline';
3
3
 
4
- import type { FormieModuleDefinition } from '#contracts/modules';
5
- import { dispatchFieldEvent, getModuleFieldContainers } from '#modules/fields/shared';
4
+ import type { BrowserModuleDefinition } from '#contracts/modules';
5
+ import { bindConditionalClear, dispatchFieldEvent, getModuleFieldContainers } from '#modules/fields/shared';
6
6
  import { ensureModuleStyles } from '#modules/styles';
7
7
 
8
8
  const INPUT_SELECTOR = 'input[data-formie-signature-input]';
@@ -111,11 +111,45 @@ function drawValueOnCanvas(canvas: HTMLCanvasElement, value: string): void {
111
111
  };
112
112
  }
113
113
 
114
+ function getImageDimensions(dataUrl: string): Promise<{ width: number; height: number } | null> {
115
+ return new Promise((resolve) => {
116
+ const image = new Image();
117
+ image.onload = () => {
118
+ resolve({
119
+ width: image.naturalWidth,
120
+ height: image.naturalHeight,
121
+ });
122
+ };
123
+ image.onerror = () => resolve(null);
124
+ image.src = dataUrl;
125
+ });
126
+ }
127
+
128
+ async function syncCanvasHeightToSignatureValue(canvas: HTMLCanvasElement, value: string): Promise<void> {
129
+ const dimensions = await getImageDimensions(value);
130
+
131
+ if (!dimensions?.width || !dimensions?.height) {
132
+ return;
133
+ }
134
+
135
+ const { width: containerWidth } = getCanvasSize(canvas);
136
+
137
+ if (!(containerWidth > 0)) {
138
+ return;
139
+ }
140
+
141
+ // Match the stored PNG aspect ratio so restored signatures are not vertically stretched.
142
+ const aspectHeight = Math.max(1, Math.round(containerWidth * (dimensions.height / dimensions.width)));
143
+ canvas.style.height = `${aspectHeight}px`;
144
+ }
145
+
114
146
  async function restoreSignatureValue(signaturePad: SignaturePad, canvas: HTMLCanvasElement, value: string): Promise<void> {
115
147
  if (!value) {
116
148
  return;
117
149
  }
118
150
 
151
+ await syncCanvasHeightToSignatureValue(canvas, value);
152
+
119
153
  try {
120
154
  await signaturePad.fromDataURL(value);
121
155
  } catch {
@@ -131,6 +165,8 @@ function initSignatureField(
131
165
  clearButton: HTMLElement | null,
132
166
  options: SignatureOptions,
133
167
  ): () => void {
168
+ const initialValue = input.value;
169
+ const form = input.form;
134
170
  const messages = getSignatureMessages(field);
135
171
 
136
172
  if (!supportsCanvas()) {
@@ -184,6 +220,12 @@ function initSignatureField(
184
220
  };
185
221
 
186
222
  const resizeCanvas = async(): Promise<boolean> => {
223
+ const existingValue = input.value || (signaturePad.isEmpty() ? '' : signaturePad.toDataURL());
224
+
225
+ if (existingValue) {
226
+ await syncCanvasHeightToSignatureValue(canvas, existingValue);
227
+ }
228
+
187
229
  const { width, height } = getCanvasSize(canvas);
188
230
 
189
231
  if (!(width > 0) || !(height > 0)) {
@@ -196,8 +238,6 @@ function initSignatureField(
196
238
  return false;
197
239
  }
198
240
 
199
- const existingValue = input.value || (signaturePad.isEmpty() ? '' : signaturePad.toDataURL());
200
-
201
241
  canvas.width = width * ratio;
202
242
  canvas.height = height * ratio;
203
243
  context.setTransform(1, 0, 0, 1, 0, 0);
@@ -311,6 +351,20 @@ function initSignatureField(
311
351
  syncInputValue('');
312
352
  };
313
353
 
354
+ const onReset = (event: Event) => {
355
+ // Hidden inputs do not restore an earlier value through native reset.
356
+ // Reset both the submitted signature and the pad to their initial state.
357
+ queueMicrotask(() => {
358
+ if (!event.defaultPrevented) {
359
+ signaturePad.clear();
360
+ syncInputValue(initialValue);
361
+ void restoreSignatureValue(signaturePad, canvas, initialValue);
362
+ }
363
+ });
364
+ };
365
+ form?.addEventListener('reset', onReset);
366
+
367
+ const unbindConditionalClear = bindConditionalClear(input, clearSignature);
314
368
  signaturePad.addEventListener('endStroke', syncValue);
315
369
  window.addEventListener('resize', resizeHandler);
316
370
  root.addEventListener('formie:page:navigate:after', pageNavigateHandler as EventListener);
@@ -327,6 +381,8 @@ function initSignatureField(
327
381
 
328
382
  return () => {
329
383
  clearSizeRetry();
384
+ unbindConditionalClear();
385
+ form?.removeEventListener('reset', onReset);
330
386
  signaturePad.removeEventListener('endStroke', syncValue);
331
387
  window.removeEventListener('resize', resizeHandler);
332
388
  root.removeEventListener('formie:page:navigate:after', pageNavigateHandler as EventListener);
@@ -340,8 +396,10 @@ function initSignatureField(
340
396
  };
341
397
  }
342
398
 
343
- export const signatureModule: FormieModuleDefinition = {
344
- id: MODULE_ID,
399
+ export const signatureModule: BrowserModuleDefinition = {
400
+ moduleId: `formie:${MODULE_ID}`,
401
+ version: 2,
402
+ surfaces: ['server-rendered', 'client-rendered', 'cp-edit'],
345
403
  kind: 'field',
346
404
  match: (ctx) => {
347
405
  return !!ctx.target.querySelector(CANVAS_SELECTOR);
@@ -1,6 +1,6 @@
1
1
  import summaryCss from '#theme-css/fields/_summary.css?inline';
2
2
 
3
- import type { FormieModuleDefinition } from '#contracts/modules';
3
+ import type { BrowserModuleDefinition } from '#contracts/modules';
4
4
  import { dispatchFieldEvent, getModuleFieldContainers } from '#modules/fields/shared';
5
5
  import { ensureModuleStyles } from '#modules/styles';
6
6
  import { toggleThemeClasses } from '#theme/theme-classes';
@@ -11,8 +11,6 @@ import { requestText } from '#utils/http';
11
11
  const BLOCKS_SELECTOR = '[data-formie-summary-blocks]';
12
12
  const CONTAINER_SELECTOR = '[data-formie-summary-container]';
13
13
  const SUMMARY_ACTION = 'formie/fields/get-summary-html';
14
- const THEME_CONFIG_ATTR = 'data-formie-theme-config';
15
- const FRONTEND_THEME_ATTR = 'data-formie-frontend-theme';
16
14
  const MODULE_ID = 'summary';
17
15
  const debug = createDebug('fields', 'summary');
18
16
 
@@ -20,8 +18,6 @@ ensureModuleStyles(MODULE_ID, [summaryCss]);
20
18
 
21
19
  type SummaryRequestState = {
22
20
  accessToken: string | null;
23
- themeConfig: string | null;
24
- frontendTheme: string | null;
25
21
  };
26
22
 
27
23
  function getSummaryRequestUrl(): string {
@@ -31,14 +27,12 @@ function getSummaryRequestUrl(): string {
31
27
  return url.toString();
32
28
  }
33
29
 
34
- function getSummaryRequestState(field: HTMLElement, form: HTMLFormElement): SummaryRequestState {
30
+ function getSummaryRequestState(field: HTMLElement): SummaryRequestState {
35
31
  const summaryTokenInput = field.querySelector('[data-formie-summary-token]') as HTMLInputElement | null;
36
32
  const accessToken = summaryTokenInput?.value?.trim() || null;
37
33
 
38
34
  return {
39
35
  accessToken,
40
- themeConfig: form.getAttribute(THEME_CONFIG_ATTR)?.trim() || null,
41
- frontendTheme: form.getAttribute(FRONTEND_THEME_ATTR)?.trim() || null,
42
36
  };
43
37
  }
44
38
 
@@ -53,14 +47,6 @@ async function requestSummaryHtml(form: HTMLFormElement, state: SummaryRequestSt
53
47
  formData.set('action', SUMMARY_ACTION);
54
48
  formData.set('accessToken', state.accessToken);
55
49
 
56
- if (state.themeConfig) {
57
- formData.set('themeConfig', state.themeConfig);
58
- }
59
-
60
- if (state.frontendTheme) {
61
- formData.set('frontendTheme', state.frontendTheme);
62
- }
63
-
64
50
  return requestText(getSummaryRequestUrl(), {
65
51
  method: 'POST',
66
52
  body: formData,
@@ -115,7 +101,7 @@ function initSummaryField(field: HTMLElement, root: Element): () => void {
115
101
  toggleThemeClasses(blocks, form, 'loading', false);
116
102
  };
117
103
 
118
- const initialState = getSummaryRequestState(field, form);
104
+ const initialState = getSummaryRequestState(field);
119
105
  setLoadingState(!!initialState.accessToken);
120
106
 
121
107
  const queueFetch = (): void => {
@@ -128,7 +114,7 @@ function initSummaryField(field: HTMLElement, root: Element): () => void {
128
114
  };
129
115
 
130
116
  const fetchSummary = debounce(async() => {
131
- const state = getSummaryRequestState(field, form);
117
+ const state = getSummaryRequestState(field);
132
118
 
133
119
  if (!getBlocks() || !state.accessToken) {
134
120
  debug.warn('Missing state for fetch.', state);
@@ -256,8 +242,10 @@ function initSummaryField(field: HTMLElement, root: Element): () => void {
256
242
  };
257
243
  }
258
244
 
259
- export const summaryModule: FormieModuleDefinition = {
260
- id: MODULE_ID,
245
+ export const summaryModule: BrowserModuleDefinition = {
246
+ moduleId: `formie:${MODULE_ID}`,
247
+ version: 2,
248
+ surfaces: ['server-rendered', 'client-rendered', 'cp-edit'],
261
249
  kind: 'field',
262
250
  match: (ctx) => {
263
251
  return !!ctx.target.querySelector(BLOCKS_SELECTOR);
@@ -1,6 +1,6 @@
1
1
  import surveyPresentationsCss from '#theme-css/fields/_survey-presentations.css?inline';
2
2
 
3
- import type { FormieModuleDefinition } from '#contracts/modules';
3
+ import type { BrowserModuleDefinition } from '#contracts/modules';
4
4
  import { ensureModuleStyles } from '#modules/styles';
5
5
  import { createDebug } from '#utils/debug';
6
6
 
@@ -10,8 +10,10 @@ const debug = createDebug('fields', 'survey-likert');
10
10
 
11
11
  ensureModuleStyles(MODULE_ID, [surveyPresentationsCss]);
12
12
 
13
- export const surveyLikertModule: FormieModuleDefinition = {
14
- id: MODULE_ID,
13
+ export const surveyLikertModule: BrowserModuleDefinition = {
14
+ moduleId: `formie:${MODULE_ID}`,
15
+ version: 2,
16
+ surfaces: ['server-rendered', 'client-rendered', 'cp-edit'],
15
17
  kind: 'field',
16
18
  match: (ctx) => {
17
19
  return ctx.target instanceof HTMLElement && (