@verbb/formie-browser 1.0.0

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 (490) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/LICENSE.md +40 -0
  3. package/README.md +34 -0
  4. package/dist/chunks/address-finder-DfMCiW89.js +47 -0
  5. package/dist/chunks/api-CbqEMQT5.js +181 -0
  6. package/dist/chunks/api-DE7LfK-R.js +960 -0
  7. package/dist/chunks/api-DOfDzYC_.js +538 -0
  8. package/dist/chunks/async-B3DUf1GZ.js +26 -0
  9. package/dist/chunks/bpoint-Ciy3yY9Q.js +34 -0
  10. package/dist/chunks/calculations-CkYAqO_-.js +197 -0
  11. package/dist/chunks/captcha-eu-DnOWhMwr.js +43 -0
  12. package/dist/chunks/checkbox-radio-0x7Tc0br.js +197 -0
  13. package/dist/chunks/chunk-K6L4z4UQ.js +24 -0
  14. package/dist/chunks/conditions-4fXKhEJS.js +609 -0
  15. package/dist/chunks/date-picker-B6iZkjHS.js +6204 -0
  16. package/dist/chunks/debug-KnZeKYBI.js +39 -0
  17. package/dist/chunks/dist-D09GnXMW.js +2663 -0
  18. package/dist/chunks/event-names-DamGPtXR.js +51 -0
  19. package/dist/chunks/eway-DEAYcwT0.js +86 -0
  20. package/dist/chunks/field-references.keys-BpBZ_quS.js +24 -0
  21. package/dist/chunks/field-references.resolver-Ba6xhiJC.js +183 -0
  22. package/dist/chunks/file-upload-Bh63PQSE.js +430 -0
  23. package/dist/chunks/friendly-captcha-v1-CqO4WVre.js +40 -0
  24. package/dist/chunks/friendly-captcha-v2-CyykcJcM.js +47 -0
  25. package/dist/chunks/friendly-challenge-Dg8XkStd.js +1101 -0
  26. package/dist/chunks/go-cardless-CuND59rR.js +26 -0
  27. package/dist/chunks/google-address--uR8WDSm.js +208 -0
  28. package/dist/chunks/hcaptcha-CmaFUesv.js +72 -0
  29. package/dist/chunks/hidden-CYnZYple.js +36 -0
  30. package/dist/chunks/http-18nn97DZ.js +29 -0
  31. package/dist/chunks/i18n-vUh-KGiH.js +55 -0
  32. package/dist/chunks/loqate-BICNJlVK.js +97 -0
  33. package/dist/chunks/mollie-DwlsgHZ1.js +26 -0
  34. package/dist/chunks/moneris-B_IFZFTx.js +159 -0
  35. package/dist/chunks/opayo-U2x_TOII.js +192 -0
  36. package/dist/chunks/paddle-BqXFrc79.js +75 -0
  37. package/dist/chunks/paypal-Cn_DYGDb.js +121 -0
  38. package/dist/chunks/payway-Rnq796eC.js +75 -0
  39. package/dist/chunks/phone-country-B6Me4lK0.js +3317 -0
  40. package/dist/chunks/place-kit-ldUl-u9w.js +56 -0
  41. package/dist/chunks/placekit-autocomplete.esm-D-lGeaZl.js +1771 -0
  42. package/dist/chunks/recaptcha-enterprise-DPJNyv1X.js +72 -0
  43. package/dist/chunks/recaptcha-shared-DTI4qWVR.js +22 -0
  44. package/dist/chunks/recaptcha-v2-checkbox-zFjpvJ5c.js +49 -0
  45. package/dist/chunks/recaptcha-v2-invisible-CnYtkNvz.js +62 -0
  46. package/dist/chunks/recaptcha-v3-EAlWhnkX.js +33 -0
  47. package/dist/chunks/repeater-CXD1eLSn.js +151 -0
  48. package/dist/chunks/rich-text-DkmZRhGj.js +442 -0
  49. package/dist/chunks/scripts-BGD_iU_6.js +41 -0
  50. package/dist/chunks/sdk-B7u9fTlP.js +2103 -0
  51. package/dist/chunks/shared-DC6_1u8X.js +85 -0
  52. package/dist/chunks/signature-E9KyYXS1.js +765 -0
  53. package/dist/chunks/snaptcha-CCDunGeb.js +8 -0
  54. package/dist/chunks/square-BLqK51rS.js +61 -0
  55. package/dist/chunks/stripe-B8gHpZNC.js +273 -0
  56. package/dist/chunks/styles-BIh6g7V_.js +22 -0
  57. package/dist/chunks/summary-EcNE0cvg.js +191 -0
  58. package/dist/chunks/table-yxEDL6kA.js +124 -0
  59. package/dist/chunks/text-limit-D0H_Ca2c.js +179 -0
  60. package/dist/chunks/theme-classes-vSHpdCUO.js +59 -0
  61. package/dist/chunks/turnstile-DP0bdR7T.js +68 -0
  62. package/dist/chunks/utils-ByrEVYrJ.js +49584 -0
  63. package/dist/css/formie-base.css +78 -0
  64. package/dist/css/formie-theme.css +19 -0
  65. package/dist/css/formie.css +2 -0
  66. package/dist/css/theme/_buttons.css +249 -0
  67. package/dist/css/theme/_loading.css +37 -0
  68. package/dist/css/theme/_messages.css +39 -0
  69. package/dist/css/theme/_progress.css +62 -0
  70. package/dist/css/theme/_tokens.css +361 -0
  71. package/dist/css/theme/_typography.css +70 -0
  72. package/dist/css/theme/fields/_address.css +17 -0
  73. package/dist/css/theme/fields/_check-radio.css +108 -0
  74. package/dist/css/theme/fields/_file.css +58 -0
  75. package/dist/css/theme/fields/_group.css +13 -0
  76. package/dist/css/theme/fields/_input.css +48 -0
  77. package/dist/css/theme/fields/_nested.css +19 -0
  78. package/dist/css/theme/fields/_repeater.css +69 -0
  79. package/dist/css/theme/fields/_rich-text.css +201 -0
  80. package/dist/css/theme/fields/_select.css +37 -0
  81. package/dist/css/theme/fields/_signature.css +39 -0
  82. package/dist/css/theme/fields/_summary.css +53 -0
  83. package/dist/css/theme/fields/_table.css +121 -0
  84. package/dist/css/theme/fields/_text-limit.css +10 -0
  85. package/dist/css/theme/forms/_field.css +62 -0
  86. package/dist/css/theme/forms/_form.css +166 -0
  87. package/dist/css/theme/integrations/_payment-modal.css +32 -0
  88. package/dist/css/theme/integrations/_paypal.css +10 -0
  89. package/dist/css/theme/integrations/_payway.css +10 -0
  90. package/dist/css/theme/integrations/_stripe.css +24 -0
  91. package/dist/css/theme/utilities/_accessibility.css +13 -0
  92. package/dist/css/theme-base/_controls.css +41 -0
  93. package/dist/css/theme-base/_primitives.css +34 -0
  94. package/dist/index.d.ts +30 -0
  95. package/dist/index.d.ts.map +1 -0
  96. package/dist/index.js +3206 -0
  97. package/dist/js/compatibility/dom-adapter.d.ts +12 -0
  98. package/dist/js/compatibility/dom-adapter.d.ts.map +1 -0
  99. package/dist/js/compatibility/event-map.d.ts +25 -0
  100. package/dist/js/compatibility/event-map.d.ts.map +1 -0
  101. package/dist/js/compatibility/validator-adapter.d.ts +17 -0
  102. package/dist/js/compatibility/validator-adapter.d.ts.map +1 -0
  103. package/dist/js/contracts/client.d.ts +40 -0
  104. package/dist/js/contracts/client.d.ts.map +1 -0
  105. package/dist/js/contracts/common.d.ts +5 -0
  106. package/dist/js/contracts/common.d.ts.map +1 -0
  107. package/dist/js/contracts/modules.d.ts +47 -0
  108. package/dist/js/contracts/modules.d.ts.map +1 -0
  109. package/dist/js/contracts/schema.d.ts +79 -0
  110. package/dist/js/contracts/schema.d.ts.map +1 -0
  111. package/dist/js/contracts/theme.d.ts +2 -0
  112. package/dist/js/contracts/theme.d.ts.map +1 -0
  113. package/dist/js/core/create-formie-client.d.ts +3 -0
  114. package/dist/js/core/create-formie-client.d.ts.map +1 -0
  115. package/dist/js/core/dom-events.d.ts +2 -0
  116. package/dist/js/core/dom-events.d.ts.map +1 -0
  117. package/dist/js/core/formie.d.ts +27 -0
  118. package/dist/js/core/formie.d.ts.map +1 -0
  119. package/dist/js/core/hydrate-modules.d.ts +22 -0
  120. package/dist/js/core/hydrate-modules.d.ts.map +1 -0
  121. package/dist/js/core/page-client-event.d.ts +9 -0
  122. package/dist/js/core/page-client-event.d.ts.map +1 -0
  123. package/dist/js/core/page-tab-errors.d.ts +2 -0
  124. package/dist/js/core/page-tab-errors.d.ts.map +1 -0
  125. package/dist/js/core/submit-flow.d.ts +21 -0
  126. package/dist/js/core/submit-flow.d.ts.map +1 -0
  127. package/dist/js/core/submit-result-state.d.ts +8 -0
  128. package/dist/js/core/submit-result-state.d.ts.map +1 -0
  129. package/dist/js/core/submit-result-ui.d.ts +10 -0
  130. package/dist/js/core/submit-result-ui.d.ts.map +1 -0
  131. package/dist/js/events/event-bus.d.ts +21 -0
  132. package/dist/js/events/event-bus.d.ts.map +1 -0
  133. package/dist/js/modules/address/address-finder.d.ts +2 -0
  134. package/dist/js/modules/address/address-finder.d.ts.map +1 -0
  135. package/dist/js/modules/address/api.d.ts +8 -0
  136. package/dist/js/modules/address/api.d.ts.map +1 -0
  137. package/dist/js/modules/address/constants.d.ts +15 -0
  138. package/dist/js/modules/address/constants.d.ts.map +1 -0
  139. package/dist/js/modules/address/factories.d.ts +35 -0
  140. package/dist/js/modules/address/factories.d.ts.map +1 -0
  141. package/dist/js/modules/address/google-address.d.ts +2 -0
  142. package/dist/js/modules/address/google-address.d.ts.map +1 -0
  143. package/dist/js/modules/address/host.d.ts +30 -0
  144. package/dist/js/modules/address/host.d.ts.map +1 -0
  145. package/dist/js/modules/address/index.d.ts +3 -0
  146. package/dist/js/modules/address/index.d.ts.map +1 -0
  147. package/dist/js/modules/address/loqate.d.ts +2 -0
  148. package/dist/js/modules/address/loqate.d.ts.map +1 -0
  149. package/dist/js/modules/address/place-kit.d.ts +2 -0
  150. package/dist/js/modules/address/place-kit.d.ts.map +1 -0
  151. package/dist/js/modules/captchas/api.d.ts +9 -0
  152. package/dist/js/modules/captchas/api.d.ts.map +1 -0
  153. package/dist/js/modules/captchas/captcha-eu.d.ts +2 -0
  154. package/dist/js/modules/captchas/captcha-eu.d.ts.map +1 -0
  155. package/dist/js/modules/captchas/constants.d.ts +5 -0
  156. package/dist/js/modules/captchas/constants.d.ts.map +1 -0
  157. package/dist/js/modules/captchas/factories.d.ts +63 -0
  158. package/dist/js/modules/captchas/factories.d.ts.map +1 -0
  159. package/dist/js/modules/captchas/friendly-captcha-v1.d.ts +2 -0
  160. package/dist/js/modules/captchas/friendly-captcha-v1.d.ts.map +1 -0
  161. package/dist/js/modules/captchas/friendly-captcha-v2.d.ts +2 -0
  162. package/dist/js/modules/captchas/friendly-captcha-v2.d.ts.map +1 -0
  163. package/dist/js/modules/captchas/hcaptcha.d.ts +2 -0
  164. package/dist/js/modules/captchas/hcaptcha.d.ts.map +1 -0
  165. package/dist/js/modules/captchas/host.d.ts +78 -0
  166. package/dist/js/modules/captchas/host.d.ts.map +1 -0
  167. package/dist/js/modules/captchas/index.d.ts +3 -0
  168. package/dist/js/modules/captchas/index.d.ts.map +1 -0
  169. package/dist/js/modules/captchas/recaptcha-enterprise.d.ts +2 -0
  170. package/dist/js/modules/captchas/recaptcha-enterprise.d.ts.map +1 -0
  171. package/dist/js/modules/captchas/recaptcha-shared.d.ts +26 -0
  172. package/dist/js/modules/captchas/recaptcha-shared.d.ts.map +1 -0
  173. package/dist/js/modules/captchas/recaptcha-v2-checkbox.d.ts +2 -0
  174. package/dist/js/modules/captchas/recaptcha-v2-checkbox.d.ts.map +1 -0
  175. package/dist/js/modules/captchas/recaptcha-v2-invisible.d.ts +2 -0
  176. package/dist/js/modules/captchas/recaptcha-v2-invisible.d.ts.map +1 -0
  177. package/dist/js/modules/captchas/recaptcha-v3.d.ts +2 -0
  178. package/dist/js/modules/captchas/recaptcha-v3.d.ts.map +1 -0
  179. package/dist/js/modules/captchas/snaptcha.d.ts +2 -0
  180. package/dist/js/modules/captchas/snaptcha.d.ts.map +1 -0
  181. package/dist/js/modules/captchas/turnstile.d.ts +2 -0
  182. package/dist/js/modules/captchas/turnstile.d.ts.map +1 -0
  183. package/dist/js/modules/captchas/utils.d.ts +13 -0
  184. package/dist/js/modules/captchas/utils.d.ts.map +1 -0
  185. package/dist/js/modules/fields/calculations.d.ts +3 -0
  186. package/dist/js/modules/fields/calculations.d.ts.map +1 -0
  187. package/dist/js/modules/fields/checkbox-radio.d.ts +3 -0
  188. package/dist/js/modules/fields/checkbox-radio.d.ts.map +1 -0
  189. package/dist/js/modules/fields/conditions/config.d.ts +5 -0
  190. package/dist/js/modules/fields/conditions/config.d.ts.map +1 -0
  191. package/dist/js/modules/fields/conditions/effects.d.ts +2 -0
  192. package/dist/js/modules/fields/conditions/effects.d.ts.map +1 -0
  193. package/dist/js/modules/fields/conditions/evaluator.d.ts +6 -0
  194. package/dist/js/modules/fields/conditions/evaluator.d.ts.map +1 -0
  195. package/dist/js/modules/fields/conditions/references.d.ts +5 -0
  196. package/dist/js/modules/fields/conditions/references.d.ts.map +1 -0
  197. package/dist/js/modules/fields/conditions/transforms.d.ts +3 -0
  198. package/dist/js/modules/fields/conditions/transforms.d.ts.map +1 -0
  199. package/dist/js/modules/fields/conditions/types.d.ts +30 -0
  200. package/dist/js/modules/fields/conditions/types.d.ts.map +1 -0
  201. package/dist/js/modules/fields/conditions/values.d.ts +5 -0
  202. package/dist/js/modules/fields/conditions/values.d.ts.map +1 -0
  203. package/dist/js/modules/fields/conditions.d.ts +3 -0
  204. package/dist/js/modules/fields/conditions.d.ts.map +1 -0
  205. package/dist/js/modules/fields/date-picker.d.ts +3 -0
  206. package/dist/js/modules/fields/date-picker.d.ts.map +1 -0
  207. package/dist/js/modules/fields/file-upload.d.ts +3 -0
  208. package/dist/js/modules/fields/file-upload.d.ts.map +1 -0
  209. package/dist/js/modules/fields/hidden.d.ts +3 -0
  210. package/dist/js/modules/fields/hidden.d.ts.map +1 -0
  211. package/dist/js/modules/fields/index.d.ts +3 -0
  212. package/dist/js/modules/fields/index.d.ts.map +1 -0
  213. package/dist/js/modules/fields/phone-country.d.ts +3 -0
  214. package/dist/js/modules/fields/phone-country.d.ts.map +1 -0
  215. package/dist/js/modules/fields/repeater.d.ts +3 -0
  216. package/dist/js/modules/fields/repeater.d.ts.map +1 -0
  217. package/dist/js/modules/fields/rich-text.d.ts +3 -0
  218. package/dist/js/modules/fields/rich-text.d.ts.map +1 -0
  219. package/dist/js/modules/fields/shared.d.ts +20 -0
  220. package/dist/js/modules/fields/shared.d.ts.map +1 -0
  221. package/dist/js/modules/fields/signature.d.ts +3 -0
  222. package/dist/js/modules/fields/signature.d.ts.map +1 -0
  223. package/dist/js/modules/fields/summary.d.ts +3 -0
  224. package/dist/js/modules/fields/summary.d.ts.map +1 -0
  225. package/dist/js/modules/fields/table.d.ts +3 -0
  226. package/dist/js/modules/fields/table.d.ts.map +1 -0
  227. package/dist/js/modules/fields/text-limit.d.ts +3 -0
  228. package/dist/js/modules/fields/text-limit.d.ts.map +1 -0
  229. package/dist/js/modules/loader.d.ts +11 -0
  230. package/dist/js/modules/loader.d.ts.map +1 -0
  231. package/dist/js/modules/payments/api.d.ts +8 -0
  232. package/dist/js/modules/payments/api.d.ts.map +1 -0
  233. package/dist/js/modules/payments/bpoint.d.ts +2 -0
  234. package/dist/js/modules/payments/bpoint.d.ts.map +1 -0
  235. package/dist/js/modules/payments/constants.d.ts +5 -0
  236. package/dist/js/modules/payments/constants.d.ts.map +1 -0
  237. package/dist/js/modules/payments/eway.d.ts +9 -0
  238. package/dist/js/modules/payments/eway.d.ts.map +1 -0
  239. package/dist/js/modules/payments/factories.d.ts +54 -0
  240. package/dist/js/modules/payments/factories.d.ts.map +1 -0
  241. package/dist/js/modules/payments/go-cardless.d.ts +2 -0
  242. package/dist/js/modules/payments/go-cardless.d.ts.map +1 -0
  243. package/dist/js/modules/payments/host.d.ts +70 -0
  244. package/dist/js/modules/payments/host.d.ts.map +1 -0
  245. package/dist/js/modules/payments/index.d.ts +3 -0
  246. package/dist/js/modules/payments/index.d.ts.map +1 -0
  247. package/dist/js/modules/payments/mollie.d.ts +2 -0
  248. package/dist/js/modules/payments/mollie.d.ts.map +1 -0
  249. package/dist/js/modules/payments/moneris.d.ts +2 -0
  250. package/dist/js/modules/payments/moneris.d.ts.map +1 -0
  251. package/dist/js/modules/payments/opayo.d.ts +25 -0
  252. package/dist/js/modules/payments/opayo.d.ts.map +1 -0
  253. package/dist/js/modules/payments/paddle.d.ts +2 -0
  254. package/dist/js/modules/payments/paddle.d.ts.map +1 -0
  255. package/dist/js/modules/payments/paypal.d.ts +2 -0
  256. package/dist/js/modules/payments/paypal.d.ts.map +1 -0
  257. package/dist/js/modules/payments/payway.d.ts +2 -0
  258. package/dist/js/modules/payments/payway.d.ts.map +1 -0
  259. package/dist/js/modules/payments/square.d.ts +2 -0
  260. package/dist/js/modules/payments/square.d.ts.map +1 -0
  261. package/dist/js/modules/payments/stripe.d.ts +2 -0
  262. package/dist/js/modules/payments/stripe.d.ts.map +1 -0
  263. package/dist/js/modules/payments/utils.d.ts +17 -0
  264. package/dist/js/modules/payments/utils.d.ts.map +1 -0
  265. package/dist/js/modules/registry.d.ts +9 -0
  266. package/dist/js/modules/registry.d.ts.map +1 -0
  267. package/dist/js/modules/styles.d.ts +2 -0
  268. package/dist/js/modules/styles.d.ts.map +1 -0
  269. package/dist/js/submit/pipeline.d.ts +18 -0
  270. package/dist/js/submit/pipeline.d.ts.map +1 -0
  271. package/dist/js/theme/theme-classes.d.ts +10 -0
  272. package/dist/js/theme/theme-classes.d.ts.map +1 -0
  273. package/dist/js/transport/forms-api.d.ts +11 -0
  274. package/dist/js/transport/forms-api.d.ts.map +1 -0
  275. package/dist/js/utils/async.d.ts +8 -0
  276. package/dist/js/utils/async.d.ts.map +1 -0
  277. package/dist/js/utils/debug.d.ts +10 -0
  278. package/dist/js/utils/debug.d.ts.map +1 -0
  279. package/dist/js/utils/event-names.d.ts +13 -0
  280. package/dist/js/utils/event-names.d.ts.map +1 -0
  281. package/dist/js/utils/field-references.d.ts +6 -0
  282. package/dist/js/utils/field-references.d.ts.map +1 -0
  283. package/dist/js/utils/field-references.keys.d.ts +4 -0
  284. package/dist/js/utils/field-references.keys.d.ts.map +1 -0
  285. package/dist/js/utils/field-references.parser.d.ts +3 -0
  286. package/dist/js/utils/field-references.parser.d.ts.map +1 -0
  287. package/dist/js/utils/field-references.registry.d.ts +3 -0
  288. package/dist/js/utils/field-references.registry.d.ts.map +1 -0
  289. package/dist/js/utils/field-references.resolver.d.ts +4 -0
  290. package/dist/js/utils/field-references.resolver.d.ts.map +1 -0
  291. package/dist/js/utils/field-references.types.d.ts +27 -0
  292. package/dist/js/utils/field-references.types.d.ts.map +1 -0
  293. package/dist/js/utils/fields.d.ts +5 -0
  294. package/dist/js/utils/fields.d.ts.map +1 -0
  295. package/dist/js/utils/http.d.ts +9 -0
  296. package/dist/js/utils/http.d.ts.map +1 -0
  297. package/dist/js/utils/i18n.d.ts +7 -0
  298. package/dist/js/utils/i18n.d.ts.map +1 -0
  299. package/dist/js/utils/scripts.d.ts +13 -0
  300. package/dist/js/utils/scripts.d.ts.map +1 -0
  301. package/dist/js/utils/unload-warning.d.ts +10 -0
  302. package/dist/js/utils/unload-warning.d.ts.map +1 -0
  303. package/dist/js/validation/rules/email.d.ts +4 -0
  304. package/dist/js/validation/rules/email.d.ts.map +1 -0
  305. package/dist/js/validation/rules/match.d.ts +4 -0
  306. package/dist/js/validation/rules/match.d.ts.map +1 -0
  307. package/dist/js/validation/rules/number.d.ts +4 -0
  308. package/dist/js/validation/rules/number.d.ts.map +1 -0
  309. package/dist/js/validation/rules/required.d.ts +4 -0
  310. package/dist/js/validation/rules/required.d.ts.map +1 -0
  311. package/dist/js/validation/rules/shared.d.ts +7 -0
  312. package/dist/js/validation/rules/shared.d.ts.map +1 -0
  313. package/dist/js/validation/rules/url.d.ts +4 -0
  314. package/dist/js/validation/rules/url.d.ts.map +1 -0
  315. package/dist/js/validation/rules.d.ts +10 -0
  316. package/dist/js/validation/rules.d.ts.map +1 -0
  317. package/dist/js/validation/types.d.ts +44 -0
  318. package/dist/js/validation/types.d.ts.map +1 -0
  319. package/dist/js/validation/validator.d.ts +53 -0
  320. package/dist/js/validation/validator.d.ts.map +1 -0
  321. package/package.json +78 -0
  322. package/src/css/formie-base.css +78 -0
  323. package/src/css/formie-theme.css +19 -0
  324. package/src/css/formie.css +2 -0
  325. package/src/css/theme/_buttons.css +249 -0
  326. package/src/css/theme/_loading.css +37 -0
  327. package/src/css/theme/_messages.css +39 -0
  328. package/src/css/theme/_progress.css +62 -0
  329. package/src/css/theme/_tokens.css +361 -0
  330. package/src/css/theme/_typography.css +70 -0
  331. package/src/css/theme/fields/_address.css +17 -0
  332. package/src/css/theme/fields/_check-radio.css +108 -0
  333. package/src/css/theme/fields/_file.css +58 -0
  334. package/src/css/theme/fields/_group.css +13 -0
  335. package/src/css/theme/fields/_input.css +48 -0
  336. package/src/css/theme/fields/_nested.css +19 -0
  337. package/src/css/theme/fields/_repeater.css +69 -0
  338. package/src/css/theme/fields/_rich-text.css +201 -0
  339. package/src/css/theme/fields/_select.css +37 -0
  340. package/src/css/theme/fields/_signature.css +39 -0
  341. package/src/css/theme/fields/_summary.css +53 -0
  342. package/src/css/theme/fields/_table.css +121 -0
  343. package/src/css/theme/fields/_text-limit.css +10 -0
  344. package/src/css/theme/forms/_field.css +62 -0
  345. package/src/css/theme/forms/_form.css +166 -0
  346. package/src/css/theme/integrations/_payment-modal.css +32 -0
  347. package/src/css/theme/integrations/_paypal.css +10 -0
  348. package/src/css/theme/integrations/_payway.css +10 -0
  349. package/src/css/theme/integrations/_stripe.css +24 -0
  350. package/src/css/theme/utilities/_accessibility.css +13 -0
  351. package/src/css/theme-base/_controls.css +41 -0
  352. package/src/css/theme-base/_primitives.css +34 -0
  353. package/src/icons/rich-text/aligncenter.svg +6 -0
  354. package/src/icons/rich-text/alignleft.svg +6 -0
  355. package/src/icons/rich-text/alignright.svg +6 -0
  356. package/src/icons/rich-text/bold.svg +4 -0
  357. package/src/icons/rich-text/clear.svg +6 -0
  358. package/src/icons/rich-text/code.svg +4 -0
  359. package/src/icons/rich-text/heading1.svg +3 -0
  360. package/src/icons/rich-text/heading2.svg +3 -0
  361. package/src/icons/rich-text/image.svg +6 -0
  362. package/src/icons/rich-text/italic.svg +5 -0
  363. package/src/icons/rich-text/line.svg +3 -0
  364. package/src/icons/rich-text/link.svg +4 -0
  365. package/src/icons/rich-text/olist.svg +8 -0
  366. package/src/icons/rich-text/paragraph.svg +3 -0
  367. package/src/icons/rich-text/quote.svg +4 -0
  368. package/src/icons/rich-text/strikethrough.svg +4 -0
  369. package/src/icons/rich-text/ulist.svg +8 -0
  370. package/src/icons/rich-text/underline.svg +4 -0
  371. package/src/index.ts +125 -0
  372. package/src/js/compatibility/dom-adapter.ts +129 -0
  373. package/src/js/compatibility/event-map.ts +72 -0
  374. package/src/js/compatibility/validator-adapter.ts +105 -0
  375. package/src/js/contracts/client.ts +43 -0
  376. package/src/js/contracts/common.ts +14 -0
  377. package/src/js/contracts/modules.ts +53 -0
  378. package/src/js/contracts/schema.ts +83 -0
  379. package/src/js/contracts/theme.ts +1 -0
  380. package/src/js/core/create-formie-client.ts +1519 -0
  381. package/src/js/core/dom-events.ts +8 -0
  382. package/src/js/core/formie.ts +242 -0
  383. package/src/js/core/hydrate-modules.ts +102 -0
  384. package/src/js/core/page-client-event.ts +129 -0
  385. package/src/js/core/page-tab-errors.ts +37 -0
  386. package/src/js/core/submit-flow.ts +120 -0
  387. package/src/js/core/submit-result-state.ts +597 -0
  388. package/src/js/core/submit-result-ui.ts +448 -0
  389. package/src/js/events/event-bus.ts +109 -0
  390. package/src/js/modules/address/address-finder.ts +85 -0
  391. package/src/js/modules/address/api.ts +22 -0
  392. package/src/js/modules/address/constants.ts +15 -0
  393. package/src/js/modules/address/factories.ts +203 -0
  394. package/src/js/modules/address/google-address.ts +345 -0
  395. package/src/js/modules/address/host.ts +137 -0
  396. package/src/js/modules/address/index.ts +10 -0
  397. package/src/js/modules/address/loqate.ts +128 -0
  398. package/src/js/modules/address/place-kit.ts +94 -0
  399. package/src/js/modules/captchas/api.ts +25 -0
  400. package/src/js/modules/captchas/captcha-eu.ts +86 -0
  401. package/src/js/modules/captchas/constants.ts +4 -0
  402. package/src/js/modules/captchas/factories.ts +485 -0
  403. package/src/js/modules/captchas/friendly-captcha-v1.ts +65 -0
  404. package/src/js/modules/captchas/friendly-captcha-v2.ts +84 -0
  405. package/src/js/modules/captchas/hcaptcha.ts +153 -0
  406. package/src/js/modules/captchas/host.ts +448 -0
  407. package/src/js/modules/captchas/index.ts +16 -0
  408. package/src/js/modules/captchas/recaptcha-enterprise.ts +138 -0
  409. package/src/js/modules/captchas/recaptcha-shared.ts +69 -0
  410. package/src/js/modules/captchas/recaptcha-v2-checkbox.ts +72 -0
  411. package/src/js/modules/captchas/recaptcha-v2-invisible.ts +108 -0
  412. package/src/js/modules/captchas/recaptcha-v3.ts +62 -0
  413. package/src/js/modules/captchas/snaptcha.ts +10 -0
  414. package/src/js/modules/captchas/turnstile.ts +131 -0
  415. package/src/js/modules/captchas/utils.ts +85 -0
  416. package/src/js/modules/fields/calculations.ts +273 -0
  417. package/src/js/modules/fields/checkbox-radio.ts +295 -0
  418. package/src/js/modules/fields/conditions/config.ts +79 -0
  419. package/src/js/modules/fields/conditions/effects.ts +166 -0
  420. package/src/js/modules/fields/conditions/evaluator.ts +44 -0
  421. package/src/js/modules/fields/conditions/references.ts +165 -0
  422. package/src/js/modules/fields/conditions/transforms.ts +206 -0
  423. package/src/js/modules/fields/conditions/types.ts +33 -0
  424. package/src/js/modules/fields/conditions/values.ts +115 -0
  425. package/src/js/modules/fields/conditions.ts +229 -0
  426. package/src/js/modules/fields/date-picker.ts +272 -0
  427. package/src/js/modules/fields/file-upload.ts +628 -0
  428. package/src/js/modules/fields/hidden.ts +58 -0
  429. package/src/js/modules/fields/index.ts +19 -0
  430. package/src/js/modules/fields/phone-country.ts +226 -0
  431. package/src/js/modules/fields/repeater.ts +231 -0
  432. package/src/js/modules/fields/rich-text.ts +217 -0
  433. package/src/js/modules/fields/shared.ts +238 -0
  434. package/src/js/modules/fields/signature.ts +202 -0
  435. package/src/js/modules/fields/summary.ts +272 -0
  436. package/src/js/modules/fields/table.ts +197 -0
  437. package/src/js/modules/fields/text-limit.ts +280 -0
  438. package/src/js/modules/loader.ts +331 -0
  439. package/src/js/modules/payments/api.ts +20 -0
  440. package/src/js/modules/payments/bpoint.ts +48 -0
  441. package/src/js/modules/payments/constants.ts +17 -0
  442. package/src/js/modules/payments/eway.ts +132 -0
  443. package/src/js/modules/payments/factories.ts +332 -0
  444. package/src/js/modules/payments/go-cardless.ts +37 -0
  445. package/src/js/modules/payments/host.ts +459 -0
  446. package/src/js/modules/payments/index.ts +17 -0
  447. package/src/js/modules/payments/mollie.ts +38 -0
  448. package/src/js/modules/payments/moneris.ts +216 -0
  449. package/src/js/modules/payments/opayo.ts +272 -0
  450. package/src/js/modules/payments/paddle.ts +111 -0
  451. package/src/js/modules/payments/payment.ts +183 -0
  452. package/src/js/modules/payments/paypal.ts +214 -0
  453. package/src/js/modules/payments/payway.ts +114 -0
  454. package/src/js/modules/payments/square.ts +106 -0
  455. package/src/js/modules/payments/stripe.ts +426 -0
  456. package/src/js/modules/payments/stub-payment-module.ts +87 -0
  457. package/src/js/modules/payments/utils.ts +60 -0
  458. package/src/js/modules/registry.ts +38 -0
  459. package/src/js/modules/styles.ts +29 -0
  460. package/src/js/submit/pipeline.ts +514 -0
  461. package/src/js/theme/theme-classes.ts +106 -0
  462. package/src/js/transport/forms-api.ts +345 -0
  463. package/src/js/utils/async.ts +81 -0
  464. package/src/js/utils/debug.ts +59 -0
  465. package/src/js/utils/event-names.ts +60 -0
  466. package/src/js/utils/field-references.keys.ts +47 -0
  467. package/src/js/utils/field-references.parser.ts +121 -0
  468. package/src/js/utils/field-references.registry.ts +50 -0
  469. package/src/js/utils/field-references.resolver.ts +115 -0
  470. package/src/js/utils/field-references.ts +11 -0
  471. package/src/js/utils/field-references.types.ts +31 -0
  472. package/src/js/utils/fields.ts +58 -0
  473. package/src/js/utils/http.ts +51 -0
  474. package/src/js/utils/i18n.ts +98 -0
  475. package/src/js/utils/scripts.ts +84 -0
  476. package/src/js/utils/unload-warning.ts +190 -0
  477. package/src/js/validation/rules/email.ts +18 -0
  478. package/src/js/validation/rules/match.ts +26 -0
  479. package/src/js/validation/rules/minmax.ts +47 -0
  480. package/src/js/validation/rules/number.ts +55 -0
  481. package/src/js/validation/rules/pattern.ts +29 -0
  482. package/src/js/validation/rules/required.ts +30 -0
  483. package/src/js/validation/rules/shared.ts +47 -0
  484. package/src/js/validation/rules/url.ts +23 -0
  485. package/src/js/validation/rules.ts +16 -0
  486. package/src/js/validation/types.ts +50 -0
  487. package/src/js/validation/validator.ts +643 -0
  488. package/src/vendor.d.ts +100 -0
  489. package/src/vite-env.d.ts +22 -0
  490. package/vite-dev.mjs +22 -0
@@ -0,0 +1,153 @@
1
+ import {
2
+ defineCaptchaModule,
3
+ } from '#modules/captchas/api';
4
+ import {
5
+ CAPTCHA_PROVIDER_LOAD_TIMEOUT_MS,
6
+ } from '#modules/captchas/constants';
7
+ import { ensureGlobal, loadExternalScript } from '#utils/scripts';
8
+ import { getScriptAttributes } from '#modules/captchas/utils';
9
+
10
+ // Minimal subset of the hCaptcha browser API that this provider needs.
11
+ // Keeping this local makes it obvious which parts of the SDK contract this
12
+ // module relies on, without teaching shared captcha services about hCaptcha.
13
+ type HcaptchaGlobal = {
14
+ render: (container: HTMLElement, options: Record<string, unknown>) => string | number;
15
+ execute: (widgetId: string | number) => void;
16
+ reset: (widgetId: string | number) => void;
17
+ };
18
+
19
+ // These are hCaptcha-specific settings only. Anything generic such as token
20
+ // field names or error messaging now comes from shared captcha services config.
21
+ type HcaptchaProviderOptions = {
22
+ siteKey?: string | null;
23
+ theme?: string;
24
+ size?: string;
25
+ language?: string;
26
+ loadingMethod?: string;
27
+ };
28
+
29
+ async function loadHcaptchaGlobal(options: HcaptchaProviderOptions): Promise<HcaptchaGlobal> {
30
+ // hCaptcha exposes a single global (`window.hcaptcha`) after its script
31
+ // has loaded and fired the configured onload callback. This helper stays
32
+ // local to the provider because the exact script URL, callback wiring and
33
+ // readiness contract are all hCaptcha-specific.
34
+ const language = typeof options.language === 'string' && options.language.trim() !== '' ? options.language.trim() : 'en';
35
+ const { async, defer } = getScriptAttributes(options.loadingMethod);
36
+ const callbackName = 'FORMIE_HCAPTCHA_ONLOAD';
37
+ const globalWindow = window as unknown as Record<string, unknown>;
38
+ const existing = globalWindow.hcaptcha;
39
+
40
+ // Re-use the already-loaded SDK when multiple forms/providers exist on
41
+ // the page. We want one shared browser global, not duplicate script loads.
42
+ if (existing) {
43
+ return existing as HcaptchaGlobal;
44
+ }
45
+
46
+ // The script calls this named function when its internals are ready. We
47
+ // bridge that callback to a promise so the rest of the module can stay
48
+ // async/await based and deterministic.
49
+ const callbackPromise = new Promise<void>((resolve) => {
50
+ globalWindow[callbackName] = () => {
51
+ delete globalWindow[callbackName];
52
+ resolve();
53
+ };
54
+ });
55
+
56
+ await loadExternalScript({
57
+ id: 'FORMIE_HCAPTCHA_SCRIPT',
58
+ src: `https://js.hcaptcha.com/1/api.js?recaptchacompat=off&render=explicit&onload=${encodeURIComponent(callbackName)}&hl=${encodeURIComponent(language)}`,
59
+ async,
60
+ defer,
61
+ });
62
+
63
+ await callbackPromise;
64
+
65
+ return ensureGlobal<HcaptchaGlobal>('hcaptcha', CAPTCHA_PROVIDER_LOAD_TIMEOUT_MS);
66
+ }
67
+
68
+ export const hcaptchaModule = defineCaptchaModule<HcaptchaProviderOptions, HcaptchaGlobal, number | string>({
69
+ id: 'hcaptcha',
70
+ defaultPlaceholderSelector: '[data-hcaptcha-placeholder]',
71
+ defaultTokenFieldNames: ['h-captcha-response'],
72
+ load: ({ options }) => {
73
+ // `load()` is deliberately separate from `mount()`: the factory can
74
+ // cache and share this provider API promise across placeholder mounts,
75
+ // resets and page transitions without reloading the SDK each time.
76
+ return loadHcaptchaGlobal(options.provider);
77
+ },
78
+ mount: ({ api, container, provider, services }) => {
79
+ // Mount only renders/configures the widget. It does not decide whether
80
+ // a submit should be blocked; that responsibility lives in `screen()`.
81
+ return api.render(container, {
82
+ sitekey: provider.siteKey || '',
83
+ theme: provider.theme || 'light',
84
+ size: provider.size || 'normal',
85
+ callback: (token?: string) => {
86
+ // hCaptcha gives us the token in the verify callback. We push
87
+ // that into the shared transport inputs so the backend sees the
88
+ // same payload shape regardless of provider implementation.
89
+ if (typeof token === 'string' && token.trim() !== '') {
90
+ services.tokens.write(token.trim());
91
+ }
92
+
93
+ // If the user previously tried to submit without a token, the
94
+ // shared services may have rendered an inline error. Clear it as
95
+ // soon as the challenge completes successfully.
96
+ services.errors.clear();
97
+ },
98
+ 'expired-callback': () => {
99
+ // Expiry means the old token is no longer valid, so keep the
100
+ // DOM transport layer honest by clearing it immediately.
101
+ services.tokens.clear();
102
+ services.errors.clear();
103
+ },
104
+ 'chalexpired-callback': () => {
105
+ // hCaptcha has a second expiry-style callback for challenge
106
+ // expiration; treat it the same as normal token expiration.
107
+ services.tokens.clear();
108
+ services.errors.clear();
109
+ },
110
+ 'error-callback': () => {
111
+ // SDK/network errors should not leave a stale token behind.
112
+ services.tokens.clear();
113
+ },
114
+ });
115
+ },
116
+ screen: ({ api, widget, placeholder, services, stageCtx }) => {
117
+ // `screen()` runs at submit time. By the time we get here the widget is
118
+ // already mounted, so this method only answers "do we have a valid
119
+ // token yet, and if not, can we get one before the screen stage ends?"
120
+ if (services.tokens.has()) {
121
+ // Users can complete hCaptcha before clicking submit. In that case
122
+ // there is nothing to do; we already have the token the backend
123
+ // expects, so let the submit pipeline continue immediately.
124
+ return;
125
+ }
126
+
127
+ // No token yet, so tell hCaptcha to start/continue the challenge flow.
128
+ // For invisible or programmatic widget modes this is the moment the
129
+ // provider gets a chance to prompt the user.
130
+ api.execute(widget);
131
+
132
+ // After execute(), the token will arrive asynchronously via the widget
133
+ // callback configured in `mount()`. We therefore wait on the shared
134
+ // token transport layer, not on a provider-specific promise chain.
135
+ return services.tokens.wait().then((hasToken) => {
136
+ if (!hasToken) {
137
+ // If the callback never produced a token in time, surface a
138
+ // normal themed error and abort the submit pipeline's `screen`
139
+ // stage so the form is not posted without verification.
140
+ const message = services.errors.getDefaultMessage();
141
+ services.errors.show(message, placeholder);
142
+ stageCtx.abort(message);
143
+ }
144
+ });
145
+ },
146
+ unmount: ({ api, widget, services }) => {
147
+ // Reset tears down provider state and clears any token the widget had
148
+ // produced. This keeps later page visits/submits from accidentally
149
+ // reusing an old solved challenge.
150
+ api.reset(widget);
151
+ services.tokens.clear();
152
+ },
153
+ });
@@ -0,0 +1,448 @@
1
+ import type { ModuleSetupContext } from '#contracts/modules';
2
+ import type { FormRefreshTokensPayload } from '#contracts/schema';
3
+ import { addThemeClasses } from '#theme/theme-classes';
4
+ import { debounce } from '#utils/async';
5
+ import { t } from '#utils/i18n';
6
+ import { DEFAULT_WAIT_FOR_VALUE_MS } from '#modules/captchas/constants';
7
+ import {
8
+ clearCaptchaValues,
9
+ ensureCaptchaValueInput,
10
+ getInputValue,
11
+ hasCaptchaValue,
12
+ waitForCaptchaValue,
13
+ } from '#modules/captchas/utils';
14
+
15
+ type Cleanup = () => void;
16
+
17
+ type ObserveVisiblePlaceholdersResult = {
18
+ cleanup: Cleanup;
19
+ reconcile: () => void;
20
+ getVisible: () => HTMLElement[];
21
+ };
22
+
23
+ export type CaptchaRefreshEntry = {
24
+ formId?: string;
25
+ sessionKey?: string | null;
26
+ value?: string | null;
27
+ };
28
+
29
+ export type CaptchaModuleOptions<TProvider extends Record<string, unknown> = Record<string, unknown>> = {
30
+ handle?: string;
31
+ placeholderSelector?: string;
32
+ errorMessage?: string;
33
+ sessionKey?: string | null;
34
+ value?: string | null;
35
+ } & TProvider;
36
+
37
+ export type NormalizedCaptchaModuleOptions<TProvider extends Record<string, unknown>> = {
38
+ handle: string;
39
+ ui: {
40
+ placeholderSelector: string;
41
+ errorMessage: string;
42
+ };
43
+ transport: {
44
+ tokenFieldNames: string[];
45
+ waitForValueMs: number;
46
+ sessionKey: string | null;
47
+ value: string | null;
48
+ };
49
+ provider: TProvider;
50
+ };
51
+
52
+ type CaptchaModuleDefaults = {
53
+ defaultPlaceholderSelector: string;
54
+ defaultTokenFieldNames?: string[];
55
+ defaultWaitForValueMs?: number;
56
+ };
57
+
58
+ export type CaptchaHostServices = {
59
+ form: HTMLFormElement | null;
60
+ root: Element;
61
+ placeholder: {
62
+ query: () => HTMLElement[];
63
+ getPrimary: () => HTMLElement | null;
64
+ observe: (
65
+ onShow: (placeholder: HTMLElement) => void,
66
+ onHide: (placeholder: HTMLElement) => void,
67
+ ) => ObserveVisiblePlaceholdersResult;
68
+ createContainer: (placeholder: HTMLElement) => HTMLElement;
69
+ clear: (placeholder: HTMLElement | null) => void;
70
+ };
71
+ errors: {
72
+ getDefaultMessage: () => string;
73
+ show: (message?: string, placeholder?: HTMLElement | null) => void;
74
+ clear: (placeholder?: HTMLElement | null) => void;
75
+ };
76
+ tokens: {
77
+ names: string[];
78
+ has: (names?: string[], root?: ParentNode) => boolean;
79
+ read: (name?: string, root?: ParentNode) => string;
80
+ write: (
81
+ value: string,
82
+ {
83
+ names,
84
+ root,
85
+ container,
86
+ }?: {
87
+ names?: string[];
88
+ root?: ParentNode;
89
+ container?: HTMLElement | null;
90
+ },
91
+ ) => void;
92
+ clear: (names?: string[], root?: ParentNode) => void;
93
+ wait: (timeoutMs?: number, names?: string[], root?: ParentNode) => Promise<boolean>;
94
+ };
95
+ refresh: {
96
+ providerHandle: string;
97
+ onTokensRefreshed: (callback: (entry: CaptchaRefreshEntry) => void) => Cleanup;
98
+ };
99
+ events: {
100
+ onRoot: (eventName: string, callback: EventListener) => Cleanup;
101
+ onForm: (eventName: string, callback: EventListener) => Cleanup;
102
+ };
103
+ };
104
+
105
+ const CAPTCHA_OPTION_KEYS = new Set([
106
+ 'handle',
107
+ 'placeholderSelector',
108
+ 'errorMessage',
109
+ 'sessionKey',
110
+ 'value',
111
+ ]);
112
+
113
+ const CAPTCHA_ERROR_SELECTOR = '[data-formie-captcha-error-container]';
114
+ const CAPTCHA_VISIBILITY_EVENTS = [
115
+ 'formie:page:navigate',
116
+ 'formie:page:navigate:after',
117
+ 'formie:submit:result',
118
+ ];
119
+
120
+ function bindDomEvent(target: EventTarget, eventName: string, callback: EventListener): Cleanup {
121
+ target.addEventListener(eventName, callback);
122
+
123
+ return () => {
124
+ target.removeEventListener(eventName, callback);
125
+ };
126
+ }
127
+
128
+ function queryCaptchaPlaceholders(root: Element, selector: string): HTMLElement[] {
129
+ if (root instanceof HTMLElement && root.matches(selector)) {
130
+ return [root, ...Array.from(root.querySelectorAll(selector)) as HTMLElement[]];
131
+ }
132
+
133
+ return Array.from(root.querySelectorAll(selector)) as HTMLElement[];
134
+ }
135
+
136
+ function isElementVisible(target: Element): target is HTMLElement {
137
+ if (!(target instanceof HTMLElement)) {
138
+ return false;
139
+ }
140
+
141
+ if (!target.isConnected) {
142
+ return false;
143
+ }
144
+
145
+ if (target.hidden || target.closest('[hidden]')) {
146
+ return false;
147
+ }
148
+
149
+ if (target.closest('[data-formie-page-hidden]') || target.closest('[aria-hidden="true"]')) {
150
+ return false;
151
+ }
152
+
153
+ const style = window.getComputedStyle(target);
154
+
155
+ return style.display !== 'none' && style.visibility !== 'hidden';
156
+ }
157
+
158
+ function getPrimaryPlaceholder(root: Element, selector: string): HTMLElement | null {
159
+ const placeholders = queryCaptchaPlaceholders(root, selector);
160
+
161
+ return placeholders.find((placeholder) => isElementVisible(placeholder)) || placeholders[0] || null;
162
+ }
163
+
164
+ function createCaptchaContainer(placeholder: HTMLElement): HTMLElement {
165
+ placeholder.innerHTML = '';
166
+
167
+ const container = document.createElement('div');
168
+ placeholder.appendChild(container);
169
+
170
+ return container;
171
+ }
172
+
173
+ function clearCaptchaError(placeholder: HTMLElement | null): void {
174
+ placeholder?.querySelector(CAPTCHA_ERROR_SELECTOR)?.remove();
175
+ }
176
+
177
+ function showCaptchaError(placeholder: HTMLElement | null, message: string, themeSource?: Element | null): void {
178
+ if (!placeholder) {
179
+ return;
180
+ }
181
+
182
+ clearCaptchaError(placeholder);
183
+
184
+ const container = document.createElement('div');
185
+ container.setAttribute('data-formie-captcha-error-container', '');
186
+ container.setAttribute('aria-live', 'polite');
187
+ container.setAttribute('aria-atomic', 'true');
188
+ addThemeClasses(container, themeSource || placeholder, 'fieldErrors');
189
+
190
+ const error = document.createElement('div');
191
+ error.setAttribute('data-formie-captcha-error', '');
192
+ error.setAttribute('role', 'alert');
193
+ addThemeClasses(error, themeSource || placeholder, 'fieldError');
194
+ error.textContent = message;
195
+
196
+ container.appendChild(error);
197
+ placeholder.appendChild(container);
198
+ }
199
+
200
+ function parseRefreshTokensEvent(event: Event): FormRefreshTokensPayload | null {
201
+ const detail = event instanceof CustomEvent ? event.detail : null;
202
+
203
+ if (!detail || typeof detail !== 'object') {
204
+ return null;
205
+ }
206
+
207
+ return detail as FormRefreshTokensPayload;
208
+ }
209
+
210
+ function getCaptchaRefreshEntry(
211
+ payload: FormRefreshTokensPayload | null,
212
+ providerHandle: string,
213
+ ): CaptchaRefreshEntry | null {
214
+ if (!payload?.captchas || typeof payload.captchas !== 'object') {
215
+ return null;
216
+ }
217
+
218
+ const entry = payload.captchas[providerHandle];
219
+
220
+ if (!entry || typeof entry !== 'object') {
221
+ return null;
222
+ }
223
+
224
+ return entry as CaptchaRefreshEntry;
225
+ }
226
+
227
+ function observeVisiblePlaceholders(
228
+ root: Element,
229
+ selector: string,
230
+ onShow: (placeholder: HTMLElement) => void,
231
+ onHide: (placeholder: HTMLElement) => void,
232
+ ): ObserveVisiblePlaceholdersResult {
233
+ const visible = new Set<HTMLElement>();
234
+
235
+ const reconcileNow = () => {
236
+ const placeholders = queryCaptchaPlaceholders(root, selector);
237
+ const nextVisible = new Set(placeholders.filter((placeholder) => isElementVisible(placeholder)));
238
+
239
+ placeholders.forEach((placeholder) => {
240
+ if (nextVisible.has(placeholder) && !visible.has(placeholder)) {
241
+ visible.add(placeholder);
242
+ onShow(placeholder);
243
+ }
244
+ });
245
+
246
+ Array.from(visible).forEach((placeholder) => {
247
+ if (nextVisible.has(placeholder)) {
248
+ return;
249
+ }
250
+
251
+ visible.delete(placeholder);
252
+ onHide(placeholder);
253
+ });
254
+ };
255
+
256
+ const reconcile = debounce(reconcileNow, 20);
257
+ const mutationObserver = new MutationObserver(() => {
258
+ reconcile();
259
+ });
260
+
261
+ mutationObserver.observe(root, {
262
+ childList: true,
263
+ subtree: true,
264
+ attributes: true,
265
+ attributeFilter: ['class', 'style', 'hidden', 'aria-hidden', 'data-formie-page-hidden'],
266
+ });
267
+
268
+ const cleanups = [
269
+ bindDomEvent(window, 'resize', () => {
270
+ reconcile();
271
+ }),
272
+ ...CAPTCHA_VISIBILITY_EVENTS.map((eventName) => {
273
+ return bindDomEvent(root, eventName, () => {
274
+ reconcile();
275
+ });
276
+ }),
277
+ ];
278
+
279
+ reconcileNow();
280
+
281
+ return {
282
+ cleanup: () => {
283
+ mutationObserver.disconnect();
284
+ cleanups.forEach((cleanup) => {
285
+ cleanup();
286
+ });
287
+
288
+ Array.from(visible).forEach((placeholder) => {
289
+ onHide(placeholder);
290
+ });
291
+
292
+ visible.clear();
293
+ },
294
+ reconcile,
295
+ getVisible: () => {
296
+ return queryCaptchaPlaceholders(root, selector).filter((placeholder) => isElementVisible(placeholder));
297
+ },
298
+ };
299
+ }
300
+
301
+ function getCaptchaProviderHandle(id: string, options: Record<string, unknown>): string {
302
+ const handle = typeof options.handle === 'string' && options.handle.trim() !== ''
303
+ ? options.handle.trim()
304
+ : '';
305
+
306
+ return handle || id;
307
+ }
308
+
309
+ export function normalizeCaptchaModuleOptions<TProvider extends Record<string, unknown>>(
310
+ id: string,
311
+ rawOptions: Record<string, unknown> | undefined,
312
+ {
313
+ defaultPlaceholderSelector,
314
+ defaultTokenFieldNames = [],
315
+ defaultWaitForValueMs = DEFAULT_WAIT_FOR_VALUE_MS,
316
+ }: CaptchaModuleDefaults,
317
+ ): NormalizedCaptchaModuleOptions<TProvider> {
318
+ const options = rawOptions || {};
319
+ const provider = Object.entries(options).reduce((carry, [key, value]) => {
320
+ if (CAPTCHA_OPTION_KEYS.has(key)) {
321
+ return carry;
322
+ }
323
+
324
+ carry[key] = value;
325
+
326
+ return carry;
327
+ }, {} as Record<string, unknown>) as TProvider;
328
+ const tokenFieldNames = defaultTokenFieldNames.map(String).filter(Boolean);
329
+ const waitForValueMs = Number(defaultWaitForValueMs);
330
+ const placeholderSelector = typeof options.placeholderSelector === 'string' && options.placeholderSelector.trim() !== ''
331
+ ? options.placeholderSelector.trim()
332
+ : defaultPlaceholderSelector;
333
+ const errorMessage = typeof options.errorMessage === 'string' && options.errorMessage.trim() !== ''
334
+ ? options.errorMessage.trim()
335
+ : t('Captcha challenge must be completed.');
336
+ const sessionKey = typeof options.sessionKey === 'string' && options.sessionKey.trim() !== ''
337
+ ? options.sessionKey.trim()
338
+ : null;
339
+ const value = typeof options.value === 'string'
340
+ ? options.value
341
+ : null;
342
+
343
+ return {
344
+ handle: getCaptchaProviderHandle(id, options),
345
+ ui: {
346
+ placeholderSelector,
347
+ errorMessage,
348
+ },
349
+ transport: {
350
+ tokenFieldNames,
351
+ waitForValueMs: Number.isFinite(waitForValueMs) ? waitForValueMs : defaultWaitForValueMs,
352
+ sessionKey,
353
+ value,
354
+ },
355
+ provider,
356
+ };
357
+ }
358
+
359
+ export function createCaptchaHostServices<TProvider extends Record<string, unknown>>(
360
+ ctx: ModuleSetupContext,
361
+ options: NormalizedCaptchaModuleOptions<TProvider>,
362
+ ): CaptchaHostServices {
363
+ const tokenRoot = ctx.form || ctx.root;
364
+ const placeholderSelector = options.ui.placeholderSelector;
365
+ const providerHandle = options.handle;
366
+
367
+ return {
368
+ form: ctx.form,
369
+ root: ctx.root,
370
+ placeholder: {
371
+ query: () => queryCaptchaPlaceholders(ctx.root, placeholderSelector),
372
+ getPrimary: () => getPrimaryPlaceholder(ctx.root, placeholderSelector),
373
+ observe: (onShow, onHide) => observeVisiblePlaceholders(ctx.root, placeholderSelector, onShow, onHide),
374
+ createContainer: (placeholder) => createCaptchaContainer(placeholder),
375
+ clear: (placeholder) => {
376
+ if (!placeholder) {
377
+ return;
378
+ }
379
+
380
+ clearCaptchaError(placeholder);
381
+ placeholder.innerHTML = '';
382
+ },
383
+ },
384
+ errors: {
385
+ getDefaultMessage: () => options.ui.errorMessage,
386
+ show: (message, placeholder) => {
387
+ showCaptchaError(placeholder || getPrimaryPlaceholder(ctx.root, placeholderSelector), message || options.ui.errorMessage, ctx.form || ctx.root);
388
+ },
389
+ clear: (placeholder) => {
390
+ clearCaptchaError(placeholder || getPrimaryPlaceholder(ctx.root, placeholderSelector));
391
+ },
392
+ },
393
+ tokens: {
394
+ names: options.transport.tokenFieldNames,
395
+ has: (names = options.transport.tokenFieldNames, root = tokenRoot) => hasCaptchaValue(root, names),
396
+ read: (name = options.transport.tokenFieldNames[0], root = tokenRoot) => (name ? getInputValue(root, name) : ''),
397
+ write: (value, {
398
+ names = options.transport.tokenFieldNames,
399
+ root = tokenRoot,
400
+ container = ctx.form,
401
+ } = {}) => {
402
+ names.forEach((name) => {
403
+ ensureCaptchaValueInput(root, name, {
404
+ value,
405
+ container,
406
+ });
407
+ });
408
+ },
409
+ clear: (names = options.transport.tokenFieldNames, root = tokenRoot) => {
410
+ clearCaptchaValues(root, names);
411
+ },
412
+ wait: (timeoutMs = options.transport.waitForValueMs, names = options.transport.tokenFieldNames, root = tokenRoot) => {
413
+ return waitForCaptchaValue(root, names, timeoutMs);
414
+ },
415
+ },
416
+ refresh: {
417
+ providerHandle,
418
+ onTokensRefreshed: (callback) => {
419
+ const handlers = ['formie:refresh-tokens:after', 'formie:refresh-tokens:refreshed'].map((eventName) => {
420
+ return bindDomEvent(ctx.root, eventName, (event) => {
421
+ const payload = parseRefreshTokensEvent(event);
422
+ const entry = getCaptchaRefreshEntry(payload, providerHandle);
423
+
424
+ if (entry) {
425
+ callback(entry);
426
+ }
427
+ });
428
+ });
429
+
430
+ return () => {
431
+ handlers.forEach((cleanup) => {
432
+ cleanup();
433
+ });
434
+ };
435
+ },
436
+ },
437
+ events: {
438
+ onRoot: (eventName, callback) => bindDomEvent(ctx.root, eventName, callback),
439
+ onForm: (eventName, callback) => {
440
+ if (!ctx.form) {
441
+ return () => {};
442
+ }
443
+
444
+ return bindDomEvent(ctx.form, eventName, callback);
445
+ },
446
+ },
447
+ };
448
+ }
@@ -0,0 +1,16 @@
1
+ import type { FormieModuleDefinition } from '#contracts/modules';
2
+
3
+ export const builtinCaptchaModuleLoaders: Record<string, () => Promise<FormieModuleDefinition>> = {
4
+ // Module ids map directly to importer functions so the loader can fetch only
5
+ // the captcha chunks required by the current form manifest.
6
+ 'captcha-eu': () => import('#modules/captchas/captcha-eu').then((module) => module.captchaEuModule),
7
+ 'friendly-captcha-v1': () => import('#modules/captchas/friendly-captcha-v1').then((module) => module.friendlyCaptchaV1Module),
8
+ 'friendly-captcha-v2': () => import('#modules/captchas/friendly-captcha-v2').then((module) => module.friendlyCaptchaV2Module),
9
+ 'hcaptcha': () => import('#modules/captchas/hcaptcha').then((module) => module.hcaptchaModule),
10
+ 'recaptcha-enterprise': () => import('#modules/captchas/recaptcha-enterprise').then((module) => module.recaptchaEnterpriseModule),
11
+ 'recaptcha-v2-checkbox': () => import('#modules/captchas/recaptcha-v2-checkbox').then((module) => module.recaptchaV2CheckboxModule),
12
+ 'recaptcha-v2-invisible': () => import('#modules/captchas/recaptcha-v2-invisible').then((module) => module.recaptchaV2InvisibleModule),
13
+ 'recaptcha-v3': () => import('#modules/captchas/recaptcha-v3').then((module) => module.recaptchaV3Module),
14
+ 'snaptcha': () => import('#modules/captchas/snaptcha').then((module) => module.snaptchaModule),
15
+ 'turnstile': () => import('#modules/captchas/turnstile').then((module) => module.turnstileModule),
16
+ };