@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
package/dist/index.js ADDED
@@ -0,0 +1,3206 @@
1
+ import { c as getScopedModuleLifecycleEventName, d as toDomEventName, l as getValidatorEventName, o as getGlobalModuleLifecycleEventName, r as getFieldModuleEventName, t as FORMIE_HTML_EVENT_NAMES, u as normalizeFormieEventName } from "./chunks/event-names-DamGPtXR.js";
2
+ import { a as setFormieDebugEnabled, i as isFormieDebugEnabled, n as debugLog, r as debugWarn, t as createDebug } from "./chunks/debug-KnZeKYBI.js";
3
+ import { a as setFormHiddenState, c as dispatchPageClientEventForSubmit, i as clearSubmitLoading, n as applyPageState, o as setSubmitLoading, r as applySubmitResultState, s as syncPageTabErrors, t as definePaymentModule } from "./chunks/api-DE7LfK-R.js";
4
+ import { n as registerThemeClassMap, r as removeThemeClasses, t as addThemeClasses } from "./chunks/theme-classes-vSHpdCUO.js";
5
+ import { t as requestJson } from "./chunks/http-18nn97DZ.js";
6
+ import { a as translate, i as t, n as mergeFormieTranslations, r as setFormieTranslations, t as getFormieTranslations } from "./chunks/i18n-vUh-KGiH.js";
7
+ import { n as definePassiveCaptchaModule, t as defineCaptchaModule } from "./chunks/api-DOfDzYC_.js";
8
+ import { n as inputNameToFieldKey, r as normalizeFieldKey, t as fieldKeyToInputName } from "./chunks/field-references.keys-BpBZ_quS.js";
9
+ import { i as parseFieldReference, n as resolveFieldReferenceLive, r as buildFieldValueRegistry, t as resolveFieldReferenceFromFormData } from "./chunks/field-references.resolver-Ba6xhiJC.js";
10
+ import { t as defineAddressModule } from "./chunks/api-CbqEMQT5.js";
11
+ //#region src/js/compatibility/event-map.ts
12
+ var LEGACY_FORMIE_DOM_EVENT_BRIDGES = [
13
+ {
14
+ legacyEvent: "onFormieLoaded",
15
+ canonicalEvent: "formie:mount:after",
16
+ disposition: "approximate",
17
+ target: "document"
18
+ },
19
+ {
20
+ legacyEvent: "onFormieInit",
21
+ canonicalEvent: "formie:mount:after",
22
+ disposition: "approximate",
23
+ target: "document"
24
+ },
25
+ {
26
+ legacyEvent: "onFormieReady",
27
+ canonicalEvent: "formie:mount:after",
28
+ disposition: "safe"
29
+ },
30
+ {
31
+ legacyEvent: "onAfterFormieSubmit",
32
+ canonicalEvent: "formie:submit:result",
33
+ disposition: "safe"
34
+ },
35
+ {
36
+ legacyEvent: "onFormieSubmitError",
37
+ canonicalEvent: "formie:submit:result",
38
+ disposition: "safe"
39
+ },
40
+ {
41
+ legacyEvent: "onFormiePageToggle",
42
+ canonicalEvent: "formie:page:navigate:after",
43
+ disposition: "safe"
44
+ },
45
+ {
46
+ legacyEvent: "onBeforeFormieSubmit",
47
+ canonicalEvent: "formie:submit:before",
48
+ disposition: "approximate"
49
+ },
50
+ {
51
+ legacyEvent: "onFormieValidate",
52
+ canonicalEvent: "formie:stage:validate:before",
53
+ disposition: "approximate"
54
+ },
55
+ {
56
+ legacyEvent: "onAfterFormieValidate",
57
+ canonicalEvent: "formie:stage:validate:after",
58
+ disposition: "approximate"
59
+ },
60
+ {
61
+ legacyEvent: "onFormieSubmit",
62
+ canonicalEvent: "formie:submit:after",
63
+ disposition: "approximate"
64
+ }
65
+ ];
66
+ var LEGACY_FORMIE_VALIDATOR_EVENT_BRIDGES = [
67
+ {
68
+ legacyEvent: "formieValidatorInitialized",
69
+ canonicalEvent: "formie:validator:ready",
70
+ disposition: "safe"
71
+ },
72
+ {
73
+ legacyEvent: "formieValidatorDestroyed",
74
+ canonicalEvent: "formie:validator:destroy",
75
+ disposition: "safe"
76
+ },
77
+ {
78
+ legacyEvent: "formieValidatorShowError",
79
+ canonicalEvent: "formie:validator:show-error",
80
+ disposition: "safe"
81
+ },
82
+ {
83
+ legacyEvent: "formieValidatorClearError",
84
+ canonicalEvent: "formie:validator:clear-error",
85
+ disposition: "safe"
86
+ }
87
+ ];
88
+ function resolveLegacyCompatibilityOptions(options) {
89
+ if (!options) return {
90
+ enabled: false,
91
+ legacyDomEvents: false,
92
+ legacyValidatorEvents: false
93
+ };
94
+ if (options === true) return {
95
+ enabled: true,
96
+ legacyDomEvents: true,
97
+ legacyValidatorEvents: true
98
+ };
99
+ const legacyDomEvents = options.legacyDomEvents ?? true;
100
+ const legacyValidatorEvents = options.legacyValidatorEvents ?? true;
101
+ return {
102
+ enabled: legacyDomEvents || legacyValidatorEvents,
103
+ legacyDomEvents,
104
+ legacyValidatorEvents
105
+ };
106
+ }
107
+ //#endregion
108
+ //#region src/js/compatibility/dom-adapter.ts
109
+ function dispatchLegacyDomEvent(target, legacyEvent, detail) {
110
+ target.dispatchEvent(new CustomEvent(legacyEvent, {
111
+ bubbles: true,
112
+ detail
113
+ }));
114
+ }
115
+ function shouldDispatchBridge(bridge, detail) {
116
+ if (bridge.canonicalEvent !== "formie:submit:result") return true;
117
+ const result = detail;
118
+ if (bridge.legacyEvent === "onAfterFormieSubmit") return !!result?.ok;
119
+ if (bridge.legacyEvent === "onFormieSubmitError") return result?.ok === false;
120
+ return true;
121
+ }
122
+ function createLegacyPageToggleDetail(form, detail) {
123
+ const eventDetail = detail && typeof detail === "object" ? detail : {};
124
+ const nextPageId = typeof eventDetail.pageId === "string" ? eventDetail.pageId : "";
125
+ const pages = Array.from(form.querySelectorAll("[data-formie-page-id]"));
126
+ return { data: {
127
+ nextPageId,
128
+ nextPageIndex: pages.findIndex((page) => {
129
+ return page.getAttribute("data-formie-page-id") === nextPageId;
130
+ }),
131
+ totalPages: pages.length
132
+ } };
133
+ }
134
+ function createLegacyDetail(bridge, detail, target, form, instance) {
135
+ const legacyFormieApi = globalThis.Formie || instance;
136
+ if (bridge.legacyEvent === "onFormieLoaded") return { formie: legacyFormieApi };
137
+ if (bridge.legacyEvent === "onFormieInit") return {
138
+ formie: legacyFormieApi,
139
+ form: instance,
140
+ $form: form,
141
+ formId: instance.id
142
+ };
143
+ if (bridge.legacyEvent === "onFormieReady") return {
144
+ ...detail && typeof detail === "object" ? detail : {},
145
+ form,
146
+ target,
147
+ instance
148
+ };
149
+ if (bridge.legacyEvent === "onFormiePageToggle") return createLegacyPageToggleDetail(form, detail);
150
+ return detail;
151
+ }
152
+ function bindLegacyDomEventCompatibility({ target, form, instance, options, unbinds }) {
153
+ if (!options.legacyDomEvents) return;
154
+ LEGACY_FORMIE_DOM_EVENT_BRIDGES.forEach((bridge) => {
155
+ const handler = (event) => {
156
+ if (!(event instanceof CustomEvent) || !shouldDispatchBridge(bridge, event.detail)) return;
157
+ dispatchLegacyDomEvent(bridge.target === "document" ? document : form, bridge.legacyEvent, createLegacyDetail(bridge, event.detail, target, form, instance));
158
+ };
159
+ target.addEventListener(toDomEventName(bridge.canonicalEvent), handler);
160
+ unbinds.push(() => {
161
+ target.removeEventListener(toDomEventName(bridge.canonicalEvent), handler);
162
+ });
163
+ });
164
+ }
165
+ //#endregion
166
+ //#region src/js/compatibility/validator-adapter.ts
167
+ function dispatchLegacyValidatorEvent(target, legacyEvent, detail) {
168
+ target.dispatchEvent(new CustomEvent(legacyEvent, {
169
+ bubbles: true,
170
+ detail
171
+ }));
172
+ }
173
+ function matchesValidator(detail, validator) {
174
+ return !!detail && typeof detail === "object" && detail.validator === validator;
175
+ }
176
+ function bindLegacyValidatorCompatibility({ target, form, validatorDetail, options, unbinds }) {
177
+ if (!options.legacyValidatorEvents || !validatorDetail) return;
178
+ const { validator, addValidator, removeValidator } = validatorDetail;
179
+ const baseDetail = {
180
+ ...validatorDetail,
181
+ form,
182
+ target
183
+ };
184
+ dispatchLegacyValidatorEvent(document, "formieValidatorInitialized", baseDetail);
185
+ const destroyHandler = (event) => {
186
+ if (!(event instanceof CustomEvent) || !matchesValidator(event.detail, validator)) return;
187
+ dispatchLegacyValidatorEvent(document, "formieValidatorDestroyed", {
188
+ ...baseDetail,
189
+ ...event.detail
190
+ });
191
+ };
192
+ const showErrorHandler = (event) => {
193
+ if (!(event instanceof CustomEvent) || !matchesValidator(event.detail, validator) || !(event.target instanceof Element)) return;
194
+ if (!form.contains(event.target)) return;
195
+ dispatchLegacyValidatorEvent(event.target, "formieValidatorShowError", {
196
+ ...event.detail,
197
+ addValidator,
198
+ removeValidator,
199
+ form,
200
+ target
201
+ });
202
+ };
203
+ const clearErrorHandler = (event) => {
204
+ if (!(event instanceof CustomEvent) || !matchesValidator(event.detail, validator) || !(event.target instanceof Element)) return;
205
+ if (!form.contains(event.target)) return;
206
+ dispatchLegacyValidatorEvent(event.target, "formieValidatorClearError", {
207
+ ...event.detail,
208
+ addValidator,
209
+ removeValidator,
210
+ form,
211
+ target
212
+ });
213
+ };
214
+ document.addEventListener("formie:validator:destroy", destroyHandler);
215
+ document.addEventListener("formie:validator:show-error", showErrorHandler);
216
+ document.addEventListener("formie:validator:clear-error", clearErrorHandler);
217
+ unbinds.push(() => {
218
+ document.removeEventListener("formie:validator:destroy", destroyHandler);
219
+ document.removeEventListener("formie:validator:show-error", showErrorHandler);
220
+ document.removeEventListener("formie:validator:clear-error", clearErrorHandler);
221
+ });
222
+ }
223
+ //#endregion
224
+ //#region src/js/core/dom-events.ts
225
+ function dispatchFormieDomEvent(target, eventName, detail) {
226
+ target.dispatchEvent(new CustomEvent(toDomEventName(eventName), {
227
+ bubbles: true,
228
+ detail
229
+ }));
230
+ }
231
+ //#endregion
232
+ //#region src/js/events/event-bus.ts
233
+ var EventBus = class {
234
+ constructor() {
235
+ this.listeners = /* @__PURE__ */ new Map();
236
+ }
237
+ on(eventName, callback) {
238
+ if (!this.listeners.has(eventName)) this.listeners.set(eventName, /* @__PURE__ */ new Set());
239
+ this.listeners.get(eventName)?.add(callback);
240
+ return () => {
241
+ this.listeners.get(eventName)?.delete(callback);
242
+ };
243
+ }
244
+ async emit(eventName, payload) {
245
+ const callbacks = this.listeners.get(eventName);
246
+ if (!callbacks || callbacks.size === 0) return;
247
+ for (const callback of callbacks) await callback(payload);
248
+ }
249
+ async emitSafe(eventName, payload) {
250
+ const callbacks = this.listeners.get(eventName);
251
+ const report = {
252
+ eventName,
253
+ total: callbacks?.size || 0,
254
+ succeeded: 0,
255
+ failed: []
256
+ };
257
+ if (!callbacks || callbacks.size === 0) return report;
258
+ let index = 0;
259
+ for (const callback of callbacks) {
260
+ try {
261
+ await callback(payload);
262
+ report.succeeded += 1;
263
+ } catch (error) {
264
+ report.failed.push({
265
+ index,
266
+ error
267
+ });
268
+ }
269
+ index += 1;
270
+ }
271
+ return report;
272
+ }
273
+ async emitParallelSafe(eventName, payload) {
274
+ const callbacks = this.listeners.get(eventName);
275
+ const report = {
276
+ eventName,
277
+ total: callbacks?.size || 0,
278
+ succeeded: 0,
279
+ failed: []
280
+ };
281
+ if (!callbacks || callbacks.size === 0) return report;
282
+ (await Promise.allSettled(Array.from(callbacks).map(async (callback) => {
283
+ return callback(payload);
284
+ }))).forEach((result, index) => {
285
+ if (result.status === "fulfilled") {
286
+ report.succeeded += 1;
287
+ return;
288
+ }
289
+ report.failed.push({
290
+ index,
291
+ error: result.reason
292
+ });
293
+ });
294
+ return report;
295
+ }
296
+ clear() {
297
+ this.listeners.clear();
298
+ }
299
+ };
300
+ //#endregion
301
+ //#region src/js/transport/forms-api.ts
302
+ var debug$6 = createDebug("general", "transport");
303
+ function toServerRenderPayloadInput(renderOptions) {
304
+ const input = {};
305
+ [
306
+ "theme",
307
+ "themeConfig",
308
+ "locale",
309
+ "siteId"
310
+ ].forEach((key) => {
311
+ if (renderOptions[key] !== void 0) input[key] = renderOptions[key];
312
+ });
313
+ return input;
314
+ }
315
+ function flattenErrors(errors, path = "", output = {}) {
316
+ if (Array.isArray(errors)) {
317
+ const messages = errors.map((value) => {
318
+ return typeof value === "string" ? value : String(value ?? "");
319
+ }).filter((value) => {
320
+ return value.trim() !== "";
321
+ });
322
+ if (path && messages.length) output[path] = (output[path] || []).concat(messages);
323
+ return output;
324
+ }
325
+ if (errors && typeof errors === "object") Object.entries(errors).forEach(([key, value]) => {
326
+ flattenErrors(value, path ? `${path}.${key}` : key, output);
327
+ });
328
+ return output;
329
+ }
330
+ function normalizePayload(payload, fallbackFormError) {
331
+ const success = payload.success === true;
332
+ const keepSubmitLoading = payload.keepSubmitLoading === true;
333
+ const errors = payload.errors;
334
+ const fieldErrorsFlat = flattenErrors(errors || {});
335
+ const formErrors = fieldErrorsFlat.form || [];
336
+ const fieldErrors = {};
337
+ Object.entries(fieldErrorsFlat).forEach(([key, value]) => {
338
+ if (key === "form") return;
339
+ const topKey = key.split(".")[0];
340
+ fieldErrors[topKey] = (fieldErrors[topKey] || []).concat(value);
341
+ });
342
+ const resolvedFormErrors = !success && formErrors.length === 0 && Object.keys(fieldErrors).length > 0 ? [fallbackFormError || "Submission failed."] : formErrors;
343
+ const isTransientPendingResult = !success && keepSubmitLoading && resolvedFormErrors.length === 0 && Object.keys(fieldErrors).length === 0;
344
+ return {
345
+ ok: success,
346
+ action: payload.submitAction === "back" || payload.submitAction === "save" || payload.submitAction === "submit" ? payload.submitAction : void 0,
347
+ message: payload.submitActionMessage || (success ? "Submission completed." : isTransientPendingResult ? "" : resolvedFormErrors[0] || "Submission failed."),
348
+ code: success ? void 0 : String(payload.code || "SUBMIT_ERROR"),
349
+ keepSubmitLoading,
350
+ fieldErrors: Object.keys(fieldErrors).length ? fieldErrors : void 0,
351
+ formErrors: resolvedFormErrors.length ? resolvedFormErrors : void 0,
352
+ nextPage: payload.nextPageId ? { id: String(payload.nextPageId) } : null,
353
+ redirect: payload.redirectUrl ? {
354
+ url: String(payload.redirectUrl),
355
+ target: payload.submitActionTab === "new-tab" ? "new-tab" : "same-tab"
356
+ } : null,
357
+ submitData: Array.isArray(payload.submitData) ? payload.submitData : void 0,
358
+ meta: payload
359
+ };
360
+ }
361
+ async function requestRender(endpoint, handle, renderOptions = {}) {
362
+ const body = JSON.stringify({
363
+ handle,
364
+ renderOptions
365
+ });
366
+ debug$6.log("requestRender start.", {
367
+ endpoint,
368
+ handle
369
+ });
370
+ const result = await requestJson(endpoint, {
371
+ method: "POST",
372
+ body,
373
+ headers: { "Content-Type": "application/json" }
374
+ });
375
+ debug$6.log("requestRender complete.", { hasHtml: !!result.html });
376
+ return result;
377
+ }
378
+ async function requestGraphqlRender(endpoint, handle, renderOptions = {}) {
379
+ const body = JSON.stringify({
380
+ query: `
381
+ query FormieHtmlForm($handle: String!, $input: ServerRenderPayloadInput) {
382
+ formieHtmlForm(handle: $handle, input: $input) {
383
+ html
384
+ }
385
+ }`,
386
+ variables: {
387
+ handle,
388
+ input: toServerRenderPayloadInput(renderOptions)
389
+ }
390
+ });
391
+ debug$6.log("requestGraphqlRender start.", {
392
+ endpoint,
393
+ handle
394
+ });
395
+ const result = await requestJson(endpoint, {
396
+ method: "POST",
397
+ body,
398
+ headers: { "Content-Type": "application/json" }
399
+ });
400
+ if (Array.isArray(result.errors) && result.errors.length > 0) throw new Error(result.errors.map((error) => error.message || "Unknown GraphQL error").join("; "));
401
+ if (!result.data?.formieHtmlForm) throw new Error(`Form not found for handle "${handle}".`);
402
+ const payload = result.data.formieHtmlForm;
403
+ debug$6.log("requestGraphqlRender complete.", { hasHtml: !!payload.html });
404
+ return payload;
405
+ }
406
+ async function requestRefreshTokens(endpoint, handle, renderId) {
407
+ const url = new URL(endpoint, window.location.origin);
408
+ url.searchParams.set("handle", handle);
409
+ if (renderId) url.searchParams.set("renderId", renderId);
410
+ debug$6.log("requestRefreshTokens start.", {
411
+ endpoint: url.toString(),
412
+ handle,
413
+ hasRenderId: !!renderId
414
+ });
415
+ const response = await requestJson(url.toString());
416
+ debug$6.log("requestRefreshTokens complete.", { hasRefreshTokens: !!response.refreshTokens });
417
+ return response.refreshTokens || response;
418
+ }
419
+ async function requestSetPage(url, form, pageId) {
420
+ const requestUrl = new URL(url, window.location.origin);
421
+ const body = new FormData();
422
+ if (pageId) body.append("pageId", pageId);
423
+ if (form) {
424
+ [
425
+ "handle",
426
+ "renderId",
427
+ "draftContextToken",
428
+ "draftContext",
429
+ "continuationToken"
430
+ ].forEach((name) => {
431
+ const value = form.querySelector(`input[name="${name}"]`)?.value?.trim();
432
+ if (value) body.append(name, value);
433
+ });
434
+ const csrfValue = form.querySelector("input[name=\"CRAFT_CSRF_TOKEN\"]")?.value?.trim();
435
+ if (csrfValue) body.append("CRAFT_CSRF_TOKEN", csrfValue);
436
+ }
437
+ debug$6.log("requestSetPage start.", {
438
+ requestUrl: requestUrl.toString(),
439
+ pageId: pageId || null
440
+ });
441
+ const result = await requestJson(requestUrl.toString(), {
442
+ method: "POST",
443
+ body
444
+ });
445
+ debug$6.log("requestSetPage complete.", result);
446
+ return result;
447
+ }
448
+ function clearSubmissionOnUnload(endpoint, form) {
449
+ const requestUrl = new URL(endpoint, window.location.origin);
450
+ const body = new FormData();
451
+ [
452
+ "handle",
453
+ "renderId",
454
+ "draftContextToken",
455
+ "draftContext"
456
+ ].forEach((name) => {
457
+ const value = form.querySelector(`input[name="${name}"]`)?.value?.trim();
458
+ if (value) body.append(name, value);
459
+ });
460
+ const csrfValue = form.querySelector("input[name=\"CRAFT_CSRF_TOKEN\"]")?.value?.trim();
461
+ if (csrfValue) body.append("CRAFT_CSRF_TOKEN", csrfValue);
462
+ debug$6.log("clearSubmissionOnUnload start.", { requestUrl: requestUrl.toString() });
463
+ try {
464
+ if (typeof navigator.sendBeacon === "function" && navigator.sendBeacon(requestUrl.toString(), body)) return;
465
+ } catch (_error) {}
466
+ fetch(requestUrl.toString(), {
467
+ method: "POST",
468
+ body,
469
+ credentials: "include",
470
+ keepalive: true,
471
+ headers: { Accept: "application/json" }
472
+ });
473
+ }
474
+ async function submitForm(form, formData) {
475
+ const method = (form.getAttribute("method") || "POST").toUpperCase();
476
+ const action = form.getAttribute("action") || window.location.href;
477
+ const fallbackFormError = form.dataset.formieErrorMessage?.trim() || "Submission failed.";
478
+ debug$6.log("submitForm start.", {
479
+ method,
480
+ action,
481
+ submitAction: formData.get("submitAction")
482
+ });
483
+ const response = await fetch(action, {
484
+ method,
485
+ body: formData,
486
+ credentials: "include",
487
+ headers: { Accept: "application/json" }
488
+ });
489
+ const contentType = response.headers.get("content-type") || "";
490
+ if (!contentType.includes("application/json")) {
491
+ if (!response.ok) {
492
+ debug$6.warn("submitForm non-JSON HTTP error.", {
493
+ status: response.status,
494
+ contentType
495
+ });
496
+ return {
497
+ ok: false,
498
+ code: "HTTP_ERROR",
499
+ message: `Request failed (${response.status}).`,
500
+ formErrors: [`Request failed (${response.status}).`]
501
+ };
502
+ }
503
+ debug$6.log("submitForm non-JSON success response.", {
504
+ status: response.status,
505
+ contentType
506
+ });
507
+ return {
508
+ ok: true,
509
+ message: "Submission completed."
510
+ };
511
+ }
512
+ const normalized = normalizePayload(await response.json(), fallbackFormError);
513
+ debug$6.log("submitForm JSON response normalized.", {
514
+ ok: normalized.ok,
515
+ code: normalized.code,
516
+ hasRedirect: !!normalized.redirect?.url,
517
+ hasSubmitData: Array.isArray(normalized.submitData) && normalized.submitData.length > 0
518
+ });
519
+ return normalized;
520
+ }
521
+ //#endregion
522
+ //#region src/js/submit/pipeline.ts
523
+ var STAGES = [
524
+ "prepare",
525
+ "normalize",
526
+ "validate",
527
+ "screen",
528
+ "authorize",
529
+ "dispatch",
530
+ "finalize"
531
+ ];
532
+ var PREFLIGHT_STAGES = [
533
+ "prepare",
534
+ "normalize",
535
+ "validate",
536
+ "screen",
537
+ "authorize"
538
+ ];
539
+ var debug$5 = createDebug("general", "pipeline");
540
+ function getAbortedResult(stage, reason) {
541
+ return {
542
+ ok: false,
543
+ stage,
544
+ code: "ABORTED",
545
+ message: reason || "Submission aborted.",
546
+ formErrors: [reason || "Submission aborted."]
547
+ };
548
+ }
549
+ function getPages(form) {
550
+ return Array.from(form.querySelectorAll("[data-formie-page]"));
551
+ }
552
+ function getValidationScope(form) {
553
+ const pages = getPages(form);
554
+ if (!pages.length) return {
555
+ scope: form,
556
+ final: true
557
+ };
558
+ const currentPage = pages.find((page) => {
559
+ return !page.hasAttribute("data-formie-page-hidden");
560
+ }) || pages[pages.length - 1];
561
+ return {
562
+ scope: currentPage,
563
+ final: currentPage === pages[pages.length - 1]
564
+ };
565
+ }
566
+ function isSubmittableControl(element) {
567
+ return element instanceof HTMLInputElement || element instanceof HTMLSelectElement || element instanceof HTMLTextAreaElement;
568
+ }
569
+ function shouldIncludeControl(control) {
570
+ if (!control.name || control.disabled) return false;
571
+ if (control instanceof HTMLInputElement) {
572
+ if (control.type === "submit" || control.type === "button" || control.type === "reset" || control.type === "image") return false;
573
+ if ((control.type === "checkbox" || control.type === "radio") && !control.checked) return false;
574
+ if (control.type === "file" && (!control.files || control.files.length === 0)) return false;
575
+ }
576
+ return true;
577
+ }
578
+ function appendControlValue(formData, control) {
579
+ if (control instanceof HTMLInputElement) {
580
+ if (control.type === "file") {
581
+ Array.from(control.files || []).forEach((file) => {
582
+ formData.append(control.name, file);
583
+ });
584
+ return;
585
+ }
586
+ formData.append(control.name, control.value);
587
+ return;
588
+ }
589
+ if (control instanceof HTMLSelectElement && control.multiple) {
590
+ Array.from(control.selectedOptions).forEach((option) => {
591
+ formData.append(control.name, option.value);
592
+ });
593
+ return;
594
+ }
595
+ formData.append(control.name, control.value);
596
+ }
597
+ function appendControlsFromRoot(formData, form) {
598
+ form.querySelectorAll("input, select, textarea").forEach((node) => {
599
+ const control = isSubmittableControl(node) ? node : null;
600
+ if (!control || control.closest("[data-formie-page]")) return;
601
+ if (!shouldIncludeControl(control)) return;
602
+ appendControlValue(formData, control);
603
+ });
604
+ }
605
+ function appendControlsFromPage(formData, page) {
606
+ const fieldNames = /* @__PURE__ */ new Set();
607
+ page.querySelectorAll("input, select, textarea").forEach((node) => {
608
+ const control = isSubmittableControl(node) ? node : null;
609
+ if (!control || !control.name || control.disabled) return;
610
+ if (control instanceof HTMLInputElement && (control.type === "submit" || control.type === "button" || control.type === "reset" || control.type === "image")) return;
611
+ if (control.name.startsWith("fields[")) fieldNames.add(control.name);
612
+ if (!shouldIncludeControl(control)) return;
613
+ appendControlValue(formData, control);
614
+ });
615
+ return fieldNames;
616
+ }
617
+ function appendMissingFieldClears(formData, fieldNames) {
618
+ fieldNames.forEach((name) => {
619
+ if (!formData.has(name)) formData.append(name, "");
620
+ });
621
+ }
622
+ function buildSubmitFormData(form, action) {
623
+ const pages = getPages(form);
624
+ const currentPage = pages.find((page) => {
625
+ return !page.hasAttribute("data-formie-page-hidden");
626
+ }) || null;
627
+ if (!pages.length || !currentPage) {
628
+ const formData = new FormData(form);
629
+ formData.set("submitAction", action);
630
+ return formData;
631
+ }
632
+ const formData = new FormData();
633
+ appendControlsFromRoot(formData, form);
634
+ appendMissingFieldClears(formData, appendControlsFromPage(formData, currentPage));
635
+ formData.set("submitAction", action);
636
+ return formData;
637
+ }
638
+ function isFinalSubmitAttempt(form, action) {
639
+ if (action !== "submit") return false;
640
+ const pages = getPages(form);
641
+ if (!pages.length) return true;
642
+ return (pages.find((page) => {
643
+ return !page.hasAttribute("data-formie-page-hidden");
644
+ }) || pages[pages.length - 1]) === pages[pages.length - 1];
645
+ }
646
+ async function runSubmitPipeline(form, action, bus, options = {}) {
647
+ debug$5.log("Starting submit pipeline.", {
648
+ action,
649
+ preflightOnly: options.preflightOnly === true
650
+ });
651
+ let aborted = false;
652
+ let abortReason;
653
+ let dispatchResult = null;
654
+ const finalSubmitAttempt = isFinalSubmitAttempt(form, action);
655
+ const context = {
656
+ form,
657
+ action,
658
+ formData: buildSubmitFormData(form, action),
659
+ abort: (reason) => {
660
+ aborted = true;
661
+ abortReason = reason;
662
+ debug$5.warn("Pipeline aborted.", { reason });
663
+ },
664
+ isAborted: () => aborted,
665
+ abortReason: () => abortReason
666
+ };
667
+ const runners = {
668
+ prepare: async (ctx) => {
669
+ const submitAction = ctx.form.querySelector("input[name=\"submitAction\"]");
670
+ if (submitAction) submitAction.value = ctx.action;
671
+ ctx.formData.set("submitAction", ctx.action);
672
+ return null;
673
+ },
674
+ normalize: async () => {
675
+ return null;
676
+ },
677
+ validate: async (ctx) => {
678
+ if (ctx.action !== "submit") return null;
679
+ if (options.validateOnSubmit === false) return null;
680
+ if (options.validator) {
681
+ const { scope, final } = getValidationScope(ctx.form);
682
+ const errors = options.validator.submit(final ? ctx.form : scope, { final });
683
+ if (errors.length > 0) {
684
+ errors[0]?.input.focus();
685
+ return {
686
+ ok: false,
687
+ stage: "validate",
688
+ code: "VALIDATION_FAILED",
689
+ message: options.validator.config.errorMessage || "Validation failed.",
690
+ fieldErrors: options.validator.getFieldErrors(errors),
691
+ formErrors: [options.validator.config.errorMessage || "Validation failed."]
692
+ };
693
+ }
694
+ return null;
695
+ }
696
+ if (!ctx.form.checkValidity()) {
697
+ ctx.form.querySelector(":invalid")?.focus();
698
+ return {
699
+ ok: false,
700
+ stage: "validate",
701
+ code: "VALIDATION_FAILED",
702
+ message: "Validation failed.",
703
+ formErrors: ["Validation failed."]
704
+ };
705
+ }
706
+ return null;
707
+ },
708
+ screen: async () => {
709
+ return null;
710
+ },
711
+ authorize: async () => {
712
+ return null;
713
+ },
714
+ dispatch: async (ctx) => {
715
+ ctx.formData = buildSubmitFormData(ctx.form, ctx.action);
716
+ const result = await submitForm(ctx.form, ctx.formData);
717
+ dispatchResult = result;
718
+ return result;
719
+ },
720
+ finalize: async (resultCtx) => {
721
+ if (!dispatchResult) return null;
722
+ if (dispatchResult.ok && dispatchResult.redirect?.url) if (dispatchResult.redirect.target === "new-tab") window.open(dispatchResult.redirect.url, "_blank");
723
+ else window.location.href = dispatchResult.redirect.url;
724
+ return null;
725
+ }
726
+ };
727
+ {
728
+ const emitReport = await bus.emitSafe("formie:submit:before", context);
729
+ if (emitReport.failed.length > 0) debug$5.warn("Submit before listeners failed.", {
730
+ eventName: emitReport.eventName,
731
+ failed: emitReport.failed.length
732
+ });
733
+ }
734
+ if (finalSubmitAttempt) {
735
+ const emitReport = await bus.emitSafe("formie:submit:final:before", context);
736
+ if (emitReport.failed.length > 0) debug$5.warn("Final submit before listeners failed.", {
737
+ eventName: emitReport.eventName,
738
+ failed: emitReport.failed.length
739
+ });
740
+ }
741
+ const stages = options.preflightOnly ? PREFLIGHT_STAGES : STAGES;
742
+ for (const stage of stages) {
743
+ debug$5.log("Stage start.", {
744
+ stage,
745
+ action
746
+ });
747
+ if (aborted) {
748
+ debug$5.warn("Stage skipped due to abort.", {
749
+ stage,
750
+ reason: abortReason
751
+ });
752
+ return getAbortedResult(stage, abortReason);
753
+ }
754
+ {
755
+ const emitReport = await bus.emitSafe(`formie:stage:${stage}:before`, {
756
+ ...context,
757
+ stage
758
+ });
759
+ if (emitReport.failed.length > 0) debug$5.warn("Stage before listeners failed.", {
760
+ stage,
761
+ failed: emitReport.failed.length
762
+ });
763
+ }
764
+ if (aborted) {
765
+ const abortedResult = getAbortedResult(stage, abortReason);
766
+ {
767
+ const emitReport = await bus.emitSafe("formie:submit:after", abortedResult);
768
+ if (emitReport.failed.length > 0) debug$5.warn("Submit after listeners failed (abort before stage).", {
769
+ stage,
770
+ failed: emitReport.failed.length
771
+ });
772
+ }
773
+ if (finalSubmitAttempt) {
774
+ const emitReport = await bus.emitSafe("formie:submit:final:after", abortedResult);
775
+ if (emitReport.failed.length > 0) debug$5.warn("Final submit after listeners failed (abort before stage).", {
776
+ stage,
777
+ failed: emitReport.failed.length
778
+ });
779
+ }
780
+ debug$5.warn("Aborted after stage before-hooks.", {
781
+ stage,
782
+ reason: abortReason
783
+ });
784
+ return abortedResult;
785
+ }
786
+ const stageResult = await runners[stage](context);
787
+ debug$5.log("Stage runner complete.", {
788
+ stage,
789
+ hasResult: !!stageResult,
790
+ ok: stageResult ? stageResult.ok : void 0,
791
+ code: stageResult?.code
792
+ });
793
+ {
794
+ const emitReport = await bus.emitSafe(`formie:stage:${stage}:after`, {
795
+ ...context,
796
+ stage,
797
+ result: stageResult
798
+ });
799
+ if (emitReport.failed.length > 0) debug$5.warn("Stage after listeners failed.", {
800
+ stage,
801
+ failed: emitReport.failed.length
802
+ });
803
+ }
804
+ if (aborted) {
805
+ const abortedResult = getAbortedResult(stage, abortReason);
806
+ {
807
+ const emitReport = await bus.emitSafe("formie:submit:after", abortedResult);
808
+ if (emitReport.failed.length > 0) debug$5.warn("Submit after listeners failed (abort after stage).", {
809
+ stage,
810
+ failed: emitReport.failed.length
811
+ });
812
+ }
813
+ if (finalSubmitAttempt) {
814
+ const emitReport = await bus.emitSafe("formie:submit:final:after", abortedResult);
815
+ if (emitReport.failed.length > 0) debug$5.warn("Final submit after listeners failed (abort after stage).", {
816
+ stage,
817
+ failed: emitReport.failed.length
818
+ });
819
+ }
820
+ debug$5.warn("Aborted after stage after-hooks.", {
821
+ stage,
822
+ reason: abortReason
823
+ });
824
+ return abortedResult;
825
+ }
826
+ if (stageResult && !stageResult.ok) {
827
+ {
828
+ const emitReport = await bus.emitSafe("formie:submit:after", stageResult);
829
+ if (emitReport.failed.length > 0) debug$5.warn("Submit after listeners failed (failed stage).", {
830
+ stage,
831
+ failed: emitReport.failed.length
832
+ });
833
+ }
834
+ if (finalSubmitAttempt) {
835
+ const emitReport = await bus.emitSafe("formie:submit:final:after", stageResult);
836
+ if (emitReport.failed.length > 0) debug$5.warn("Final submit after listeners failed (failed stage).", {
837
+ stage,
838
+ failed: emitReport.failed.length
839
+ });
840
+ }
841
+ debug$5.warn("Pipeline short-circuited by failed stage.", {
842
+ stage,
843
+ code: stageResult.code,
844
+ message: stageResult.message
845
+ });
846
+ return stageResult;
847
+ }
848
+ }
849
+ const successResult = dispatchResult || {
850
+ ok: true,
851
+ stage: options.preflightOnly ? "authorize" : "finalize",
852
+ message: options.preflightOnly ? "Submission preflight completed." : "Submission completed."
853
+ };
854
+ {
855
+ const emitReport = await bus.emitSafe("formie:submit:after", successResult);
856
+ if (emitReport.failed.length > 0) debug$5.warn("Submit after listeners failed (success).", { failed: emitReport.failed.length });
857
+ }
858
+ if (finalSubmitAttempt) {
859
+ const emitReport = await bus.emitSafe("formie:submit:final:after", successResult);
860
+ if (emitReport.failed.length > 0) debug$5.warn("Final submit after listeners failed (success).", { failed: emitReport.failed.length });
861
+ }
862
+ debug$5.log("Pipeline completed.", {
863
+ ok: successResult.ok,
864
+ stage: successResult.stage,
865
+ code: successResult.code
866
+ });
867
+ return successResult;
868
+ }
869
+ //#endregion
870
+ //#region src/js/validation/rules/email.ts
871
+ var email = {
872
+ rule: ({ input, getRule }) => {
873
+ if (!getRule("email") || !input.value || input.value.length < 1) return true;
874
+ return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(input.value);
875
+ },
876
+ message: ({ input, label, t }) => {
877
+ return input.getAttribute("data-formie-pattern-email-message") ?? input.getAttribute("data-pattern-email-message") ?? t("{attribute} is not a valid email address.", { attribute: label });
878
+ }
879
+ };
880
+ //#endregion
881
+ //#region src/js/validation/rules/shared.ts
882
+ function getLabelText(field) {
883
+ return field?.querySelector("[data-formie-field-label]")?.childNodes[0]?.textContent?.trim() || "";
884
+ }
885
+ function getComparableInput(ctx) {
886
+ const match = ctx.getRule("match");
887
+ if (!match || match === true || typeof match !== "object" || !ctx.field) return null;
888
+ const fieldHandle = typeof match.fieldHandle === "string" ? match.fieldHandle.trim() : "";
889
+ if (!fieldHandle) return null;
890
+ const sourceField = ctx.form.querySelector(`[data-formie-field-handle="${fieldHandle}"]`);
891
+ if (!sourceField) return null;
892
+ return sourceField.querySelector(ctx.config.fieldsSelector);
893
+ }
894
+ //#endregion
895
+ //#region src/js/validation/rules.ts
896
+ var rules_default = {
897
+ required: {
898
+ rule: ({ input, getRule }) => {
899
+ if (!getRule("required") || input.type === "hidden") return true;
900
+ if (input.type === "checkbox" || input.type === "radio") {
901
+ const checkboxInputs = input.form?.querySelectorAll(`[name="${input.name}"]:not([type="hidden"]):not([disabled])`) || [];
902
+ if (checkboxInputs.length) return Array.from(checkboxInputs).some((button) => {
903
+ return button instanceof HTMLInputElement && button.checked;
904
+ });
905
+ return input instanceof HTMLInputElement ? input.checked : true;
906
+ }
907
+ return input.value.trim() !== "";
908
+ },
909
+ message: ({ input, label, t }) => {
910
+ return input.getAttribute("data-formie-required-message") ?? input.getAttribute("data-required-message") ?? t("{attribute} cannot be blank.", { attribute: label });
911
+ }
912
+ },
913
+ email,
914
+ url: {
915
+ rule: ({ input, getRule }) => {
916
+ if (!getRule("url") || !input.value || input.value.length < 1) return true;
917
+ try {
918
+ new URL(input.value);
919
+ return true;
920
+ } catch {
921
+ return false;
922
+ }
923
+ },
924
+ message: ({ input, label, t }) => {
925
+ return input.getAttribute("data-formie-pattern-url-message") ?? input.getAttribute("data-pattern-url-message") ?? t("{attribute} is not a valid URL.", { attribute: label });
926
+ }
927
+ },
928
+ number: {
929
+ rule: ({ input, getRule }) => {
930
+ const rule = getRule("number");
931
+ if (!rule || !input.value || input.value.trim() === "") return true;
932
+ const value = parseFloat(input.value);
933
+ if (Number.isNaN(value)) return false;
934
+ if (rule !== true && typeof rule === "object") {
935
+ const min = typeof rule.min === "number" ? rule.min : null;
936
+ const max = typeof rule.max === "number" ? rule.max : null;
937
+ if (min !== null && value < min) return false;
938
+ if (max !== null && value > max) return false;
939
+ }
940
+ return true;
941
+ },
942
+ message: ({ input, label, getRule, t }) => {
943
+ const rule = getRule("number");
944
+ const min = rule !== true && rule && typeof rule === "object" && typeof rule.min === "number" ? rule.min : null;
945
+ const max = rule !== true && rule && typeof rule === "object" && typeof rule.max === "number" ? rule.max : null;
946
+ if (min !== null && max !== null) return t("{attribute} must be between {min} and {max}.", {
947
+ attribute: label,
948
+ min,
949
+ max
950
+ });
951
+ if (min !== null) return t("{attribute} must be no less than {min}.", {
952
+ attribute: label,
953
+ min
954
+ });
955
+ if (max !== null) return t("{attribute} must be no greater than {max}.", {
956
+ attribute: label,
957
+ max
958
+ });
959
+ return input.getAttribute("data-formie-pattern-number-message") ?? input.getAttribute("data-pattern-number-message") ?? t("{attribute} is not a valid number.", { attribute: label });
960
+ }
961
+ },
962
+ match: {
963
+ rule: (ctx) => {
964
+ const sourceInput = getComparableInput(ctx);
965
+ if (!sourceInput) return true;
966
+ return sourceInput.value === ctx.input.value;
967
+ },
968
+ message: (ctx) => {
969
+ const sourceField = getComparableInput(ctx)?.closest("[data-formie-field-handle]");
970
+ const sourceLabel = getLabelText(sourceField);
971
+ return ctx.t("{name} must match {value}.", {
972
+ name: ctx.label,
973
+ value: sourceLabel
974
+ });
975
+ }
976
+ }
977
+ };
978
+ //#endregion
979
+ //#region src/js/validation/validator.ts
980
+ var DEFAULT_PATTERNS = {
981
+ email: /^([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x22([^\x0d\x22\x5c\x80-\xff]|\x5c[\x00-\x7f])*\x22)(\x2e([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x22([^\x0d\x22\x5c\x80-\xff]|\x5c[\x00-\x7f])*\x22))*\x40([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x5b([^\x0d\x5b-\x5d\x80-\xff]|\x5c[\x00-\x7f])*\x5d)(\x2e([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x5b([^\x0d\x5b-\x5d\x80-\xff]|\x5c[\x00-\x7f])*\x5d))*(\.\w{2,})+$/,
982
+ url: /^(?:(?:https?|HTTPS?|ftp|FTP):\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-zA-Z\u00a1-\uffff0-9]-*)*[a-zA-Z\u00a1-\uffff0-9]+)(?:\.(?:[a-zA-Z\u00a1-\uffff0-9]-*)*[a-zA-Z\u00a1-\uffff0-9]+)*(?:\.(?:[a-zA-Z\u00a1-\uffff]{2,}))\.?)(?::\d{2,5})?(?:[/?#]\S*)?$/,
983
+ number: /^(?:[-+]?[0-9]*[.,]?[0-9]+)$/,
984
+ color: /^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/,
985
+ date: /(?:19|20)[0-9]{2}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-9])|(?:(?!02)(?:0[1-9]|1[0-2])-(?:30))|(?:(?:0[13578]|1[02])-31))/,
986
+ time: /^(?:(0[0-9]|1[0-9]|2[0-3])(:[0-5][0-9]))$/,
987
+ month: /^(?:(?:19|20)[0-9]{2}-(?:(?:0[1-9]|1[0-2])))$/
988
+ };
989
+ var debug$4 = createDebug("general", "validator");
990
+ function isValidationInput(node) {
991
+ return !!node && (node instanceof HTMLInputElement || node instanceof HTMLSelectElement || node instanceof HTMLTextAreaElement);
992
+ }
993
+ function removeDescribedBy$1(input, describedById) {
994
+ const current = (input.getAttribute("aria-describedby") || "").trim();
995
+ if (!current) return;
996
+ const filtered = current.split(/\s+/).filter((item) => {
997
+ return item !== describedById;
998
+ });
999
+ if (filtered.length) {
1000
+ input.setAttribute("aria-describedby", filtered.join(" "));
1001
+ return;
1002
+ }
1003
+ input.removeAttribute("aria-describedby");
1004
+ }
1005
+ function appendDescribedBy$1(input, describedById) {
1006
+ const current = (input.getAttribute("aria-describedby") || "").trim();
1007
+ const items = current ? current.split(/\s+/) : [];
1008
+ if (!items.includes(describedById)) items.push(describedById);
1009
+ input.setAttribute("aria-describedby", items.join(" ").trim());
1010
+ }
1011
+ function setErrorMessageReference$1(input, errorMessageId) {
1012
+ input.setAttribute("aria-errormessage", errorMessageId);
1013
+ }
1014
+ function clearErrorMessageReference$1(input, errorMessageId) {
1015
+ if (input.getAttribute("aria-errormessage") === errorMessageId) input.removeAttribute("aria-errormessage");
1016
+ }
1017
+ var FormieValidator = class {
1018
+ constructor(form, config = {}) {
1019
+ this.errors = [];
1020
+ this.validators = {};
1021
+ this.boundListeners = false;
1022
+ this.activated = /* @__PURE__ */ new WeakSet();
1023
+ this.submitted = false;
1024
+ this.initialValues = /* @__PURE__ */ new WeakMap();
1025
+ this.form = form;
1026
+ this.onBlur = this.blurHandler.bind(this);
1027
+ this.onChange = this.changeHandler.bind(this);
1028
+ this.onInput = this.inputHandler.bind(this);
1029
+ this.config = {
1030
+ live: false,
1031
+ errorMessage: "",
1032
+ fieldContainerErrorClass: [],
1033
+ inputErrorClass: [],
1034
+ messagesClass: [],
1035
+ messageClass: [],
1036
+ fieldsSelector: "input:not([type=\"hidden\"]):not([type=\"submit\"]):not([type=\"button\"]):not([disabled]), select:not([disabled]), textarea:not([disabled])",
1037
+ patterns: DEFAULT_PATTERNS,
1038
+ ...config
1039
+ };
1040
+ Object.entries(rules_default).forEach(([validatorName, validator]) => {
1041
+ this.addValidator(validatorName, validator.rule, validator.message);
1042
+ });
1043
+ this.init();
1044
+ }
1045
+ init() {
1046
+ debug$4.log("Initializing validator.", {
1047
+ formId: this.form.id || null,
1048
+ live: this.config.live
1049
+ });
1050
+ this.form.setAttribute("novalidate", "true");
1051
+ this.inputs().forEach((input) => {
1052
+ this.initialValues.set(input, this.getInputValue(input));
1053
+ });
1054
+ if (this.config.live) this.addEventListeners();
1055
+ this.emitEvent(document, getValidatorEventName("ready"), { validator: this });
1056
+ }
1057
+ inputs(inputOrSelector = null) {
1058
+ if (isValidationInput(inputOrSelector)) return [inputOrSelector];
1059
+ const root = inputOrSelector || this.form;
1060
+ return Array.from(root.querySelectorAll(this.config.fieldsSelector)).filter((input) => {
1061
+ return isValidationInput(input);
1062
+ });
1063
+ }
1064
+ getInputValue(input) {
1065
+ if (input instanceof HTMLInputElement && (input.type === "checkbox" || input.type === "radio")) return input.checked;
1066
+ if (input instanceof HTMLInputElement && input.type === "file") return input.files?.length ? Array.from(input.files).map((file) => {
1067
+ return file.name;
1068
+ }).join("|") : "";
1069
+ return input.value ?? "";
1070
+ }
1071
+ isDirty(input) {
1072
+ if (!this.initialValues.has(input)) {
1073
+ this.initialValues.set(input, this.getInputValue(input));
1074
+ return false;
1075
+ }
1076
+ return this.getInputValue(input) !== this.initialValues.get(input);
1077
+ }
1078
+ shouldShowError(input) {
1079
+ return this.submitted || this.activated.has(input);
1080
+ }
1081
+ validate(inputOrSelector = null, options = {}) {
1082
+ this.errors = [];
1083
+ const seenGroups = /* @__PURE__ */ new Set();
1084
+ this.inputs(inputOrSelector).forEach((input) => {
1085
+ let errorShown = false;
1086
+ if (!this.isVisible(input, options)) return;
1087
+ const field = input.closest("[data-formie-field-handle]");
1088
+ const groupKey = input instanceof HTMLInputElement && (input.type === "checkbox" || input.type === "radio") ? `${field?.getAttribute("data-formie-field-handle") || ""}:${input.name}` : null;
1089
+ if (groupKey) {
1090
+ if (seenGroups.has(groupKey)) return;
1091
+ seenGroups.add(groupKey);
1092
+ }
1093
+ if (this.shouldShowError(input)) this.removeError(input);
1094
+ const opts = this.getValidatorCallbackOptions(input);
1095
+ Object.entries(this.validators).forEach(([validatorName, validatorConfig]) => {
1096
+ if (!validatorConfig.validate(opts)) {
1097
+ const errorMessage = this.getErrorMessage(input, validatorName, validatorConfig, opts);
1098
+ if (this.shouldShowError(input) && !errorShown) this.showError(input, validatorName, errorMessage);
1099
+ this.errors.push({
1100
+ input,
1101
+ field: opts.field,
1102
+ validator: validatorName,
1103
+ message: errorMessage,
1104
+ handle: opts.field?.getAttribute("data-formie-field-handle") || null,
1105
+ result: false
1106
+ });
1107
+ errorShown = true;
1108
+ }
1109
+ });
1110
+ if (!errorShown && this.shouldShowError(input)) this.removeError(input);
1111
+ });
1112
+ debug$4.log("Validation pass complete.", {
1113
+ errorCount: this.errors.length,
1114
+ includeHiddenPages: options.includeHiddenPages === true
1115
+ });
1116
+ return this.errors;
1117
+ }
1118
+ removeAllErrors() {
1119
+ this.inputs().forEach((input) => {
1120
+ this.removeError(input);
1121
+ });
1122
+ }
1123
+ removeError(input) {
1124
+ const fieldContainer = input.closest("[data-formie-field-handle]");
1125
+ if (!fieldContainer) {
1126
+ input.removeAttribute("aria-invalid");
1127
+ return;
1128
+ }
1129
+ const errorMessages = fieldContainer.querySelector("[data-formie-field-errors]");
1130
+ const errorContainerId = errorMessages?.id || "";
1131
+ fieldContainer.querySelectorAll("[data-formie-field-error]").forEach((node) => {
1132
+ node.remove();
1133
+ });
1134
+ if (errorMessages) errorMessages.innerHTML = "";
1135
+ fieldContainer.querySelectorAll("input, select, textarea").forEach((fieldInput) => {
1136
+ const element = fieldInput;
1137
+ element.removeAttribute("aria-invalid");
1138
+ if (this.config.inputErrorClass.length) element.classList.remove(...this.config.inputErrorClass);
1139
+ element.removeAttribute("data-formie-input-has-error");
1140
+ if (errorContainerId) removeDescribedBy$1(element, errorContainerId);
1141
+ fieldContainer.querySelectorAll("[data-formie-field-error]").forEach((errorNode) => {
1142
+ const errorMessageId = errorNode.id;
1143
+ if (errorMessageId) clearErrorMessageReference$1(element, errorMessageId);
1144
+ });
1145
+ });
1146
+ for (let element = fieldContainer; element; element = element.parentElement?.closest("[data-formie-field-handle]")) {
1147
+ if (this.config.fieldContainerErrorClass.length) element.classList.remove(...this.config.fieldContainerErrorClass);
1148
+ element.removeAttribute("data-formie-field-has-error");
1149
+ }
1150
+ this.emitEvent(input, getValidatorEventName("clear-error"), { validator: this });
1151
+ syncPageTabErrors(this.form);
1152
+ }
1153
+ showError(input, validatorName, errorMessage) {
1154
+ const fieldContainer = input.closest("[data-formie-field-handle]");
1155
+ if (!fieldContainer) return;
1156
+ let errorMessages = fieldContainer.querySelector("[data-formie-field-errors]");
1157
+ if (!errorMessages) {
1158
+ errorMessages = document.createElement("div");
1159
+ errorMessages.setAttribute("data-formie-field-errors", "true");
1160
+ if (this.config.messagesClass.length) errorMessages.classList.add(...this.config.messagesClass);
1161
+ fieldContainer.appendChild(errorMessages);
1162
+ }
1163
+ if (this.config.messagesClass.length) errorMessages.classList.add(...this.config.messagesClass);
1164
+ errorMessages.innerHTML = "";
1165
+ const handle = fieldContainer.getAttribute("data-formie-field-handle") || "field";
1166
+ const errorId = `${handle}-error`;
1167
+ errorMessages.id = errorMessages.id || `${handle}-errors`;
1168
+ errorMessages.setAttribute("aria-live", "polite");
1169
+ errorMessages.setAttribute("aria-atomic", "true");
1170
+ const errorElement = document.createElement("div");
1171
+ errorElement.setAttribute("data-formie-field-error", "true");
1172
+ errorElement.setAttribute(`data-formie-field-error-${validatorName}`, "true");
1173
+ errorElement.setAttribute("id", errorId);
1174
+ errorElement.setAttribute("role", "alert");
1175
+ if (this.config.messageClass.length) errorElement.classList.add(...this.config.messageClass);
1176
+ errorElement.textContent = errorMessage;
1177
+ errorMessages.appendChild(errorElement);
1178
+ fieldContainer.setAttribute("data-formie-field-has-error", "true");
1179
+ fieldContainer.querySelectorAll("input, select, textarea").forEach((fieldInput) => {
1180
+ const element = fieldInput;
1181
+ element.setAttribute("aria-invalid", "true");
1182
+ if (this.config.inputErrorClass.length) element.classList.add(...this.config.inputErrorClass);
1183
+ element.setAttribute("data-formie-input-has-error", "true");
1184
+ appendDescribedBy$1(element, errorMessages.id);
1185
+ setErrorMessageReference$1(element, errorId);
1186
+ });
1187
+ for (let element = fieldContainer; element; element = element.parentElement?.closest("[data-formie-field-handle]")) {
1188
+ if (this.config.fieldContainerErrorClass.length) element.classList.add(...this.config.fieldContainerErrorClass);
1189
+ element.setAttribute("data-formie-field-has-error", "true");
1190
+ }
1191
+ this.emitEvent(input, getValidatorEventName("show-error"), {
1192
+ validator: this,
1193
+ validatorName,
1194
+ errorMessage
1195
+ });
1196
+ syncPageTabErrors(this.form);
1197
+ }
1198
+ getValidatorCallbackOptions(input) {
1199
+ const fieldContainer = input.closest("[data-formie-field-handle]");
1200
+ const label = fieldContainer?.querySelector("[data-formie-field-label]")?.childNodes[0]?.textContent?.trim() ?? "";
1201
+ const rules = this.parseValidationRules(fieldContainer?.getAttribute("data-formie-validation"));
1202
+ return {
1203
+ t,
1204
+ input,
1205
+ label,
1206
+ field: fieldContainer,
1207
+ form: this.form,
1208
+ config: this.config,
1209
+ rules,
1210
+ getRule: (rule) => {
1211
+ return this.getRule(fieldContainer, rule);
1212
+ }
1213
+ };
1214
+ }
1215
+ getErrorMessage(input, validatorName, validator, opts) {
1216
+ return (typeof validator.errorMessage === "function" ? validator.errorMessage(opts) : validator.errorMessage) ?? t("{attribute} is invalid.", { attribute: opts.label });
1217
+ }
1218
+ getErrors() {
1219
+ return this.errors;
1220
+ }
1221
+ getFieldErrors(errors = this.errors) {
1222
+ const fieldErrors = {};
1223
+ errors.forEach((error) => {
1224
+ if (!error.handle || fieldErrors[error.handle]?.length) return;
1225
+ fieldErrors[error.handle] = [error.message];
1226
+ });
1227
+ return fieldErrors;
1228
+ }
1229
+ getRule(field, rule) {
1230
+ if (!field) return false;
1231
+ const rules = this.parseValidationRules(field.getAttribute("data-formie-validation"));
1232
+ if (Object.prototype.hasOwnProperty.call(rules, rule)) return rules[rule];
1233
+ return false;
1234
+ }
1235
+ parseValidationRules(ruleString) {
1236
+ const rules = {};
1237
+ if (!ruleString) return rules;
1238
+ let parsedRules = null;
1239
+ try {
1240
+ parsedRules = JSON.parse(ruleString);
1241
+ } catch {
1242
+ debug$4.warn("Invalid validation rules payload.", { formId: this.form.id || null });
1243
+ return rules;
1244
+ }
1245
+ if (!Array.isArray(parsedRules)) return rules;
1246
+ parsedRules.forEach((part) => {
1247
+ if (!part || typeof part !== "object" || Array.isArray(part)) return;
1248
+ const candidate = part;
1249
+ const type = typeof candidate.type === "string" ? candidate.type.trim() : "";
1250
+ if (!type) return;
1251
+ rules[type] = candidate;
1252
+ });
1253
+ return rules;
1254
+ }
1255
+ destroy() {
1256
+ debug$4.log("Destroying validator.", { formId: this.form.id || null });
1257
+ this.removeEventListeners();
1258
+ this.form.removeAttribute("novalidate");
1259
+ this.emitEvent(document, getValidatorEventName("destroy"), { validator: this });
1260
+ }
1261
+ isVisible(element, options = {}) {
1262
+ if (element.closest("[data-formie-conditionally-hidden]")) return false;
1263
+ if (element.closest("[data-formie-page-hidden]")) return !!options.includeHiddenPages;
1264
+ return !!(element.offsetWidth || element.offsetHeight || element.getClientRects().length);
1265
+ }
1266
+ blurHandler(event) {
1267
+ if (!(event.target instanceof HTMLElement) || !isValidationInput(event.target) || !event.target.form?.isSameNode(this.form)) return;
1268
+ if (event instanceof CustomEvent) return;
1269
+ if (event.target instanceof HTMLInputElement && event.target.type === "file") return;
1270
+ if (event.target instanceof HTMLInputElement && (event.target.type === "checkbox" || event.target.type === "radio")) return;
1271
+ if (this.isDirty(event.target)) this.activated.add(event.target);
1272
+ if (this.shouldShowError(event.target)) this.validate(event.target);
1273
+ }
1274
+ changeHandler(event) {
1275
+ if (!(event.target instanceof HTMLElement) || !isValidationInput(event.target) || !event.target.form?.isSameNode(this.form)) return;
1276
+ if (event instanceof CustomEvent) return;
1277
+ if (event.target instanceof HTMLSelectElement) {
1278
+ this.activated.add(event.target);
1279
+ this.validate(event.target);
1280
+ return;
1281
+ }
1282
+ if (!(event.target instanceof HTMLInputElement)) return;
1283
+ if (event.target.type !== "file" && event.target.type !== "checkbox" && event.target.type !== "radio") return;
1284
+ this.activated.add(event.target);
1285
+ this.validate(event.target);
1286
+ }
1287
+ inputHandler(event) {
1288
+ if (!(event.target instanceof HTMLElement) || !isValidationInput(event.target) || !event.target.form?.isSameNode(this.form)) return;
1289
+ if (event instanceof CustomEvent) return;
1290
+ if (event.target instanceof HTMLInputElement && (event.target.type === "checkbox" || event.target.type === "radio")) return;
1291
+ if (this.shouldShowError(event.target)) this.validate(event.target);
1292
+ }
1293
+ submit(inputOrSelector = null, { final = false } = {}) {
1294
+ this.submitted = true;
1295
+ debug$4.log("Submit validation requested.", { final });
1296
+ if (!this.boundListeners) this.addEventListeners();
1297
+ this.removeAllErrors();
1298
+ return this.validate(inputOrSelector, { includeHiddenPages: final });
1299
+ }
1300
+ resetLiveState() {
1301
+ this.submitted = false;
1302
+ this.activated = /* @__PURE__ */ new WeakSet();
1303
+ this.errors = [];
1304
+ this.removeAllErrors();
1305
+ }
1306
+ addEventListeners() {
1307
+ if (this.boundListeners) return;
1308
+ this.form.addEventListener("blur", this.onBlur, true);
1309
+ this.form.addEventListener("change", this.onChange, false);
1310
+ this.form.addEventListener("input", this.onInput, false);
1311
+ this.boundListeners = true;
1312
+ debug$4.log("Event listeners attached.");
1313
+ }
1314
+ removeEventListeners() {
1315
+ this.form.removeEventListener("blur", this.onBlur, true);
1316
+ this.form.removeEventListener("change", this.onChange, false);
1317
+ this.form.removeEventListener("input", this.onInput, false);
1318
+ this.boundListeners = false;
1319
+ debug$4.log("Event listeners removed.");
1320
+ }
1321
+ emitEvent(target, type, detail = {}) {
1322
+ target.dispatchEvent(new CustomEvent(type, {
1323
+ bubbles: true,
1324
+ detail
1325
+ }));
1326
+ }
1327
+ addValidator(name, validatorFunction, errorMessage) {
1328
+ this.validators[name] = {
1329
+ validate: validatorFunction,
1330
+ errorMessage
1331
+ };
1332
+ }
1333
+ removeValidator(name) {
1334
+ delete this.validators[name];
1335
+ }
1336
+ };
1337
+ //#endregion
1338
+ //#region src/js/core/submit-result-ui.ts
1339
+ var successHideTimers = /* @__PURE__ */ new WeakMap();
1340
+ function getConfiguredSubmitAction(form) {
1341
+ return (form.dataset.formieSubmitAction || "").trim();
1342
+ }
1343
+ function getErrorMessagePosition(form) {
1344
+ return (form.dataset.formieErrorMessagePosition || "top-form").trim() || "top-form";
1345
+ }
1346
+ function getSuccessMessagePosition(form) {
1347
+ return (form.dataset.formieSubmitActionMessagePosition || "").trim();
1348
+ }
1349
+ function getSuccessMessageTimeoutMs(form) {
1350
+ const rawValue = (form.dataset.formieSubmitActionMessageTimeout || "").trim();
1351
+ if (!rawValue) return null;
1352
+ const seconds = Number.parseFloat(rawValue);
1353
+ if (!Number.isFinite(seconds) || seconds < 0) return null;
1354
+ return Math.round(seconds * 1e3);
1355
+ }
1356
+ function shouldHideFormOnSuccess(form) {
1357
+ const rawValue = form.dataset.formieSubmitActionFormHide;
1358
+ if (rawValue === void 0) return false;
1359
+ const normalized = rawValue.trim().toLowerCase();
1360
+ return normalized === "true" || normalized === "1" || normalized === "";
1361
+ }
1362
+ function clearPendingSuccessHide(form) {
1363
+ const timerId = successHideTimers.get(form);
1364
+ if (typeof timerId === "number") {
1365
+ window.clearTimeout(timerId);
1366
+ successHideTimers.delete(form);
1367
+ }
1368
+ }
1369
+ function getTopMessageHost(form) {
1370
+ return form.querySelector("[data-formie-form-messages-top]") || form;
1371
+ }
1372
+ function getBottomMessageHost(form) {
1373
+ return form.querySelector("[data-formie-form-messages-bottom]") || form;
1374
+ }
1375
+ function getErrorMessageHost(form, position) {
1376
+ if (position === "bottom-form") return getBottomMessageHost(form);
1377
+ return getTopMessageHost(form);
1378
+ }
1379
+ function getSuccessMessageHost(form, position) {
1380
+ if (position === "top-form") return getTopMessageHost(form);
1381
+ if (position === "bottom-form" && !shouldHideFormOnSuccess(form)) return getBottomMessageHost(form);
1382
+ return form;
1383
+ }
1384
+ function ensureFormErrorContainer(form) {
1385
+ const position = getErrorMessagePosition(form);
1386
+ const host = getErrorMessageHost(form, position);
1387
+ let container = host.querySelector("[data-formie-error-container], [data-formie-errors]");
1388
+ if (!container) {
1389
+ container = document.createElement("div");
1390
+ container.setAttribute("data-formie-errors", "true");
1391
+ addThemeClasses(container, form, "errors");
1392
+ }
1393
+ container.setAttribute("data-formie-error-container", "true");
1394
+ if (position === "bottom-form") host.append(container);
1395
+ else host.prepend(container);
1396
+ return container;
1397
+ }
1398
+ function ensureFormErrorMessageContainer(form, container) {
1399
+ let messageContainer = container.querySelector("[data-formie-error-message-container], [data-formie-message][data-formie-message-error]");
1400
+ if (!messageContainer) {
1401
+ messageContainer = document.createElement("div");
1402
+ messageContainer.setAttribute("data-formie-error-message-container", "true");
1403
+ container.appendChild(messageContainer);
1404
+ }
1405
+ messageContainer.setAttribute("data-formie-message", "true");
1406
+ messageContainer.setAttribute("data-formie-message-error", "true");
1407
+ addThemeClasses(messageContainer, form, "message", "messageError");
1408
+ messageContainer.setAttribute("role", "alert");
1409
+ messageContainer.setAttribute("aria-live", "polite");
1410
+ messageContainer.setAttribute("aria-atomic", "true");
1411
+ return messageContainer;
1412
+ }
1413
+ function ensureFormSuccessContainer(form, position) {
1414
+ let container = form.querySelector("[data-formie-success-container]");
1415
+ const host = getSuccessMessageHost(form, position);
1416
+ if (!container) {
1417
+ container = document.createElement("div");
1418
+ container.setAttribute("data-formie-success-container", "true");
1419
+ addThemeClasses(container, form, "successes");
1420
+ }
1421
+ if (position === "bottom-form") host.append(container);
1422
+ else if (host === form) host.prepend(container);
1423
+ else host.prepend(container);
1424
+ return container;
1425
+ }
1426
+ function ensureFieldErrorContainer(fieldNode) {
1427
+ let container = fieldNode.querySelector("[data-formie-field-errors]");
1428
+ if (!container) {
1429
+ container = document.createElement("div");
1430
+ container.setAttribute("data-formie-field-errors", "true");
1431
+ addThemeClasses(container, fieldNode, "fieldErrors");
1432
+ fieldNode.appendChild(container);
1433
+ }
1434
+ return container;
1435
+ }
1436
+ function removeDescribedBy(input, describedById) {
1437
+ const current = (input.getAttribute("aria-describedby") || "").trim();
1438
+ if (!current) return;
1439
+ const nextValue = current.split(/\s+/).filter((item) => {
1440
+ return item !== describedById;
1441
+ }).join(" ").trim();
1442
+ if (nextValue) {
1443
+ input.setAttribute("aria-describedby", nextValue);
1444
+ return;
1445
+ }
1446
+ input.removeAttribute("aria-describedby");
1447
+ }
1448
+ function setErrorMessageReference(input, errorMessageId) {
1449
+ input.setAttribute("aria-errormessage", errorMessageId);
1450
+ }
1451
+ function clearErrorMessageReference(input, errorMessageId) {
1452
+ if (input.getAttribute("aria-errormessage") === errorMessageId) input.removeAttribute("aria-errormessage");
1453
+ }
1454
+ function clearFieldErrors(form) {
1455
+ form.querySelectorAll("[data-formie-field-handle]").forEach((fieldNode) => {
1456
+ const fieldElement = fieldNode;
1457
+ const container = fieldElement.querySelector("[data-formie-field-errors]");
1458
+ const containerId = container?.id || "";
1459
+ const errorMessageIds = Array.from(fieldElement.querySelectorAll("[data-formie-field-error]")).map((node) => {
1460
+ return node.id;
1461
+ }).filter(Boolean);
1462
+ removeThemeClasses(fieldElement, form, "fieldLayoutError");
1463
+ fieldElement.removeAttribute("data-formie-field-has-error");
1464
+ fieldElement.querySelectorAll("[data-formie-field-error]").forEach((node) => {
1465
+ node.remove();
1466
+ });
1467
+ if (container && !container.querySelector("[data-formie-field-error]")) container.innerHTML = "";
1468
+ fieldElement.querySelectorAll("input, select, textarea").forEach((input) => {
1469
+ const element = input;
1470
+ element.removeAttribute("aria-invalid");
1471
+ removeThemeClasses(element, form, "fieldControlError");
1472
+ element.removeAttribute("data-formie-input-has-error");
1473
+ if (containerId) removeDescribedBy(element, containerId);
1474
+ errorMessageIds.forEach((errorMessageId) => {
1475
+ clearErrorMessageReference(element, errorMessageId);
1476
+ });
1477
+ });
1478
+ });
1479
+ syncPageTabErrors(form);
1480
+ }
1481
+ function clearFormErrors(form) {
1482
+ form.querySelectorAll("[data-formie-error-container], [data-formie-errors]").forEach((node) => {
1483
+ const container = node;
1484
+ container.querySelectorAll("[data-formie-error]").forEach((errorNode) => {
1485
+ errorNode.remove();
1486
+ });
1487
+ removeThemeClasses(container, form, "message", "messageError");
1488
+ container.removeAttribute("data-formie-message");
1489
+ container.removeAttribute("data-formie-message-error");
1490
+ container.removeAttribute("role");
1491
+ container.removeAttribute("aria-live");
1492
+ container.removeAttribute("aria-atomic");
1493
+ if (!container.querySelector("[data-formie-error]")) container.innerHTML = "";
1494
+ });
1495
+ }
1496
+ function clearFormSuccess(form) {
1497
+ clearPendingSuccessHide(form);
1498
+ form.querySelectorAll("[data-formie-message-success]:not([data-formie-success-container])").forEach((node) => {
1499
+ node.remove();
1500
+ });
1501
+ form.querySelectorAll("[data-formie-success-container]").forEach((node) => {
1502
+ const container = node;
1503
+ container.querySelectorAll("[data-formie-success]").forEach((successNode) => {
1504
+ successNode.remove();
1505
+ });
1506
+ removeThemeClasses(container, form, "message", "messageSuccess");
1507
+ container.removeAttribute("data-formie-message");
1508
+ container.removeAttribute("data-formie-message-success");
1509
+ container.removeAttribute("role");
1510
+ container.removeAttribute("aria-live");
1511
+ container.removeAttribute("aria-atomic");
1512
+ if (!container.querySelector("[data-formie-success]")) container.innerHTML = "";
1513
+ });
1514
+ if (!(getConfiguredSubmitAction(form) === "message" && shouldHideFormOnSuccess(form))) setFormHiddenState(form, false);
1515
+ }
1516
+ function clearAriaInvalid(form) {
1517
+ form.querySelectorAll("[aria-invalid=\"true\"]").forEach((node) => {
1518
+ node.removeAttribute("aria-invalid");
1519
+ });
1520
+ }
1521
+ function appendDescribedBy(input, describedById) {
1522
+ const current = (input.getAttribute("aria-describedby") || "").trim();
1523
+ const items = current ? current.split(/\s+/) : [];
1524
+ if (!items.includes(describedById)) items.push(describedById);
1525
+ input.setAttribute("aria-describedby", items.join(" ").trim());
1526
+ }
1527
+ function renderFieldErrors(form, fieldErrors) {
1528
+ Object.entries(fieldErrors).forEach(([handle, messages]) => {
1529
+ const fieldNode = form.querySelector(`[data-formie-field-handle="${handle}"]`);
1530
+ if (!fieldNode) return;
1531
+ const container = ensureFieldErrorContainer(fieldNode);
1532
+ const containerId = container.id && container.id.trim() ? container.id : `${handle}-errors`;
1533
+ container.id = containerId;
1534
+ container.setAttribute("aria-live", "polite");
1535
+ container.setAttribute("aria-atomic", "true");
1536
+ addThemeClasses(fieldNode, form, "fieldLayoutError");
1537
+ fieldNode.setAttribute("data-formie-field-has-error", "true");
1538
+ messages.forEach((message, index) => {
1539
+ const errorNode = document.createElement("div");
1540
+ errorNode.setAttribute("data-formie-field-error", "true");
1541
+ errorNode.setAttribute("role", "alert");
1542
+ errorNode.id = `${containerId}-${index + 1}`;
1543
+ addThemeClasses(errorNode, form, "fieldError");
1544
+ errorNode.textContent = message;
1545
+ container.appendChild(errorNode);
1546
+ });
1547
+ const primaryErrorId = container.querySelector("[data-formie-field-error]")?.id;
1548
+ fieldNode.querySelectorAll("input, select, textarea").forEach((input) => {
1549
+ const element = input;
1550
+ element.setAttribute("aria-invalid", "true");
1551
+ addThemeClasses(element, form, "fieldControlError");
1552
+ element.setAttribute("data-formie-input-has-error", "true");
1553
+ appendDescribedBy(element, containerId);
1554
+ if (primaryErrorId) setErrorMessageReference(element, primaryErrorId);
1555
+ const instructions = fieldNode.querySelector("[data-formie-instructions]");
1556
+ if (instructions?.id) appendDescribedBy(element, instructions.id);
1557
+ });
1558
+ });
1559
+ syncPageTabErrors(form);
1560
+ }
1561
+ function renderFormErrors(form, formErrors) {
1562
+ const container = ensureFormErrorContainer(form);
1563
+ const messageContainer = ensureFormErrorMessageContainer(form, container);
1564
+ addThemeClasses(container, form, "errors");
1565
+ formErrors.forEach((error) => {
1566
+ const errorNode = document.createElement("div");
1567
+ errorNode.setAttribute("data-formie-error", "true");
1568
+ errorNode.setAttribute("role", "alert");
1569
+ addThemeClasses(errorNode, form, "error");
1570
+ errorNode.innerHTML = error;
1571
+ messageContainer.appendChild(errorNode);
1572
+ });
1573
+ }
1574
+ function shouldRenderSuccessMessage(form, result) {
1575
+ if (!result.message || result.nextPage || result.redirect) return false;
1576
+ if (result.action === "save") return true;
1577
+ return getConfiguredSubmitAction(form) === "message" && getSuccessMessagePosition(form) !== "";
1578
+ }
1579
+ function renderFormSuccess(form, message) {
1580
+ const position = getSuccessMessagePosition(form);
1581
+ if (!position) return;
1582
+ const container = ensureFormSuccessContainer(form, position);
1583
+ addThemeClasses(container, form, "message", "messageSuccess");
1584
+ container.setAttribute("data-formie-message", "true");
1585
+ container.setAttribute("data-formie-message-success", "true");
1586
+ container.setAttribute("role", "status");
1587
+ container.setAttribute("aria-live", "polite");
1588
+ container.setAttribute("aria-atomic", "true");
1589
+ const successNode = document.createElement("div");
1590
+ successNode.setAttribute("data-formie-success", "true");
1591
+ addThemeClasses(successNode, form, "success");
1592
+ successNode.innerHTML = message;
1593
+ container.appendChild(successNode);
1594
+ if (shouldHideFormOnSuccess(form)) setFormHiddenState(form, true);
1595
+ const timeoutMs = getSuccessMessageTimeoutMs(form);
1596
+ if (timeoutMs !== null) {
1597
+ const timerId = window.setTimeout(() => {
1598
+ successHideTimers.delete(form);
1599
+ clearFormSuccess(form);
1600
+ }, timeoutMs);
1601
+ successHideTimers.set(form, timerId);
1602
+ }
1603
+ }
1604
+ function applySubmitResultUi(form, result) {
1605
+ clearFieldErrors(form);
1606
+ clearFormErrors(form);
1607
+ clearFormSuccess(form);
1608
+ clearAriaInvalid(form);
1609
+ if (result.ok) {
1610
+ if (shouldRenderSuccessMessage(form, result)) renderFormSuccess(form, result.message || "");
1611
+ return;
1612
+ }
1613
+ if (result.fieldErrors) renderFieldErrors(form, result.fieldErrors);
1614
+ if (result.formErrors?.length) {
1615
+ renderFormErrors(form, result.formErrors);
1616
+ return;
1617
+ }
1618
+ if (!result.fieldErrors && result.message) renderFormErrors(form, [result.message]);
1619
+ }
1620
+ //#endregion
1621
+ //#region src/js/core/submit-flow.ts
1622
+ var debug$3 = createDebug("general", "submit-flow");
1623
+ function shouldRefreshTokensAfterSubmit(result) {
1624
+ if (!result.ok && result.stage === "validate") return false;
1625
+ return true;
1626
+ }
1627
+ function shouldKeepSubmitLoading(result) {
1628
+ if (!result) return false;
1629
+ if (result.keepSubmitLoading === true) return true;
1630
+ if (result.ok && result.redirect?.url && result.redirect.target !== "new-tab") return true;
1631
+ return false;
1632
+ }
1633
+ function clearSubmitFeedback(form) {
1634
+ clearFieldErrors(form);
1635
+ clearFormErrors(form);
1636
+ clearFormSuccess(form);
1637
+ clearAriaInvalid(form);
1638
+ }
1639
+ async function executeAjaxSubmitFlow(params) {
1640
+ const { id, target, form, bus, validator, validateOnSubmit, action, submitter, waitForSubmitDelay, onRefreshTokensAfterSubmit, dispatchSubmitResult } = params;
1641
+ clearSubmitFeedback(form);
1642
+ setSubmitLoading(form, submitter || null);
1643
+ let result = {
1644
+ ok: false,
1645
+ code: "SUBMIT_ERROR",
1646
+ message: "Submission failed.",
1647
+ formErrors: ["Submission failed."]
1648
+ };
1649
+ try {
1650
+ await waitForSubmitDelay(form);
1651
+ result = await runSubmitPipeline(form, action, bus, {
1652
+ validator,
1653
+ validateOnSubmit
1654
+ });
1655
+ applySubmitResultUi(form, result);
1656
+ applySubmitResultState(form, result, action);
1657
+ if (shouldRefreshTokensAfterSubmit(result)) await onRefreshTokensAfterSubmit(result);
1658
+ dispatchSubmitResult(result);
1659
+ } catch (error) {
1660
+ result = {
1661
+ ok: false,
1662
+ code: "SUBMIT_ERROR",
1663
+ message: error instanceof Error ? error.message : "Submission failed.",
1664
+ formErrors: [error instanceof Error ? error.message : "Submission failed."]
1665
+ };
1666
+ applySubmitResultUi(form, result);
1667
+ dispatchSubmitResult(result);
1668
+ debug$3.warn("Submit failed with exception.", {
1669
+ id,
1670
+ action,
1671
+ target,
1672
+ error: error instanceof Error ? error.message : error
1673
+ });
1674
+ } finally {
1675
+ if (!shouldKeepSubmitLoading(result)) clearSubmitLoading(form);
1676
+ }
1677
+ return result;
1678
+ }
1679
+ //#endregion
1680
+ //#region src/js/modules/registry.ts
1681
+ var ModuleRegistry = class {
1682
+ constructor() {
1683
+ this.modules = /* @__PURE__ */ new Map();
1684
+ }
1685
+ register(moduleDefinition, options = {}) {
1686
+ const existing = this.modules.get(moduleDefinition.id);
1687
+ if (existing === moduleDefinition) return true;
1688
+ if (existing && !options.replace) {
1689
+ console.warn(`[formie] Module "${moduleDefinition.id}" is already registered. Pass { replace: true } to override the existing definition.`);
1690
+ return false;
1691
+ }
1692
+ this.modules.set(moduleDefinition.id, moduleDefinition);
1693
+ return true;
1694
+ }
1695
+ unregister(moduleId) {
1696
+ this.modules.delete(moduleId);
1697
+ }
1698
+ get(moduleId) {
1699
+ return this.modules.get(moduleId) || null;
1700
+ }
1701
+ getAll() {
1702
+ return Array.from(this.modules.values());
1703
+ }
1704
+ };
1705
+ //#endregion
1706
+ //#region src/js/modules/address/index.ts
1707
+ var builtinAddressModuleLoaders = {
1708
+ "address-finder": () => import("./chunks/address-finder-DfMCiW89.js").then((m) => m.addressFinderModule),
1709
+ "google-address": () => import("./chunks/google-address--uR8WDSm.js").then((m) => m.googleAddressModule),
1710
+ "loqate": () => import("./chunks/loqate-BICNJlVK.js").then((m) => m.loqateModule),
1711
+ "place-kit": () => import("./chunks/place-kit-ldUl-u9w.js").then((m) => m.placeKitModule)
1712
+ };
1713
+ //#endregion
1714
+ //#region src/js/modules/captchas/index.ts
1715
+ var builtinCaptchaModuleLoaders = {
1716
+ "captcha-eu": () => import("./chunks/captcha-eu-DnOWhMwr.js").then((module) => module.captchaEuModule),
1717
+ "friendly-captcha-v1": () => import("./chunks/friendly-captcha-v1-CqO4WVre.js").then((module) => module.friendlyCaptchaV1Module),
1718
+ "friendly-captcha-v2": () => import("./chunks/friendly-captcha-v2-CyykcJcM.js").then((module) => module.friendlyCaptchaV2Module),
1719
+ "hcaptcha": () => import("./chunks/hcaptcha-CmaFUesv.js").then((module) => module.hcaptchaModule),
1720
+ "recaptcha-enterprise": () => import("./chunks/recaptcha-enterprise-DPJNyv1X.js").then((module) => module.recaptchaEnterpriseModule),
1721
+ "recaptcha-v2-checkbox": () => import("./chunks/recaptcha-v2-checkbox-zFjpvJ5c.js").then((module) => module.recaptchaV2CheckboxModule),
1722
+ "recaptcha-v2-invisible": () => import("./chunks/recaptcha-v2-invisible-CnYtkNvz.js").then((module) => module.recaptchaV2InvisibleModule),
1723
+ "recaptcha-v3": () => import("./chunks/recaptcha-v3-EAlWhnkX.js").then((module) => module.recaptchaV3Module),
1724
+ "snaptcha": () => import("./chunks/snaptcha-CCDunGeb.js").then((module) => module.snaptchaModule),
1725
+ "turnstile": () => import("./chunks/turnstile-DP0bdR7T.js").then((module) => module.turnstileModule)
1726
+ };
1727
+ //#endregion
1728
+ //#region src/js/modules/fields/index.ts
1729
+ var builtinFieldModuleLoaders = {
1730
+ "calculations": () => import("./chunks/calculations-CkYAqO_-.js").then((module) => module.calculationsModule),
1731
+ "checkbox-radio": () => import("./chunks/checkbox-radio-0x7Tc0br.js").then((module) => module.checkboxRadioModule),
1732
+ "conditions": () => import("./chunks/conditions-4fXKhEJS.js").then((module) => module.conditionsModule),
1733
+ "date-picker": () => import("./chunks/date-picker-B6iZkjHS.js").then((module) => module.datePickerModule),
1734
+ "file-upload": () => import("./chunks/file-upload-Bh63PQSE.js").then((module) => module.fileUploadModule),
1735
+ "hidden": () => import("./chunks/hidden-CYnZYple.js").then((module) => module.hiddenModule),
1736
+ "phone-country": () => import("./chunks/phone-country-B6Me4lK0.js").then((module) => module.phoneCountryModule),
1737
+ "repeater": () => import("./chunks/repeater-CXD1eLSn.js").then((module) => module.repeaterModule),
1738
+ "rich-text": () => import("./chunks/rich-text-DkmZRhGj.js").then((module) => module.richTextModule),
1739
+ "signature": () => import("./chunks/signature-E9KyYXS1.js").then((module) => module.signatureModule),
1740
+ "summary": () => import("./chunks/summary-EcNE0cvg.js").then((module) => module.summaryModule),
1741
+ "table": () => import("./chunks/table-yxEDL6kA.js").then((module) => module.tableModule),
1742
+ "text-limit": () => import("./chunks/text-limit-D0H_Ca2c.js").then((module) => module.textLimitModule)
1743
+ };
1744
+ //#endregion
1745
+ //#region src/js/modules/payments/index.ts
1746
+ var builtinPaymentModuleLoaders = {
1747
+ "bpoint": () => import("./chunks/bpoint-Ciy3yY9Q.js").then((module) => module.bpointModule),
1748
+ "eway": () => import("./chunks/eway-DEAYcwT0.js").then((module) => module.ewayModule),
1749
+ "go-cardless": () => import("./chunks/go-cardless-CuND59rR.js").then((module) => module.goCardlessModule),
1750
+ "mollie": () => import("./chunks/mollie-DwlsgHZ1.js").then((module) => module.mollieModule),
1751
+ "moneris": () => import("./chunks/moneris-B_IFZFTx.js").then((module) => module.monerisModule),
1752
+ "opayo": () => import("./chunks/opayo-U2x_TOII.js").then((module) => module.opayoModule),
1753
+ "paddle": () => import("./chunks/paddle-BqXFrc79.js").then((module) => module.paddleModule),
1754
+ "paypal": () => import("./chunks/paypal-Cn_DYGDb.js").then((module) => module.paypalModule),
1755
+ "payway": () => import("./chunks/payway-Rnq796eC.js").then((module) => module.paywayModule),
1756
+ "square": () => import("./chunks/square-BLqK51rS.js").then((module) => module.squareModule),
1757
+ "stripe": () => import("./chunks/stripe-B8gHpZNC.js").then((module) => module.stripeModule)
1758
+ };
1759
+ //#endregion
1760
+ //#region src/js/modules/loader.ts
1761
+ var builtinModuleLoaders = {
1762
+ ...builtinFieldModuleLoaders,
1763
+ ...builtinAddressModuleLoaders,
1764
+ ...builtinCaptchaModuleLoaders,
1765
+ ...builtinPaymentModuleLoaders
1766
+ };
1767
+ var builtinModuleLoadCache = /* @__PURE__ */ new Map();
1768
+ var debug$2 = createDebug("general", "loader");
1769
+ var importModuleFromSrc = new Function("src", "return import(src);");
1770
+ async function emitModuleLifecycleEvent(emit, moduleId, phase, detail) {
1771
+ await emit(getGlobalModuleLifecycleEventName(phase), detail);
1772
+ await emit(getScopedModuleLifecycleEventName(moduleId, phase), detail);
1773
+ }
1774
+ function isModuleDefinition(definition) {
1775
+ return !!definition && typeof definition === "object" && typeof definition.id === "string" && typeof definition.setup === "function" && typeof definition.match === "function";
1776
+ }
1777
+ async function resolveBuiltinDefinition(moduleId, ctx) {
1778
+ const loader = builtinModuleLoaders[moduleId];
1779
+ if (!loader) return null;
1780
+ if (!builtinModuleLoadCache.has(moduleId)) builtinModuleLoadCache.set(moduleId, (async () => {
1781
+ try {
1782
+ const definition = await loader();
1783
+ if (!isModuleDefinition(definition)) return null;
1784
+ ctx.registry.register(definition);
1785
+ return definition;
1786
+ } catch (error) {
1787
+ console.error("[formie] Failed to load builtin module:", moduleId, error);
1788
+ debug$2.warn("Failed loading builtin module.", {
1789
+ moduleId,
1790
+ error
1791
+ });
1792
+ return null;
1793
+ }
1794
+ })());
1795
+ return builtinModuleLoadCache.get(moduleId) || null;
1796
+ }
1797
+ async function resolveDefinitionFromSrc(src) {
1798
+ try {
1799
+ const imported = await importModuleFromSrc(src);
1800
+ const definition = imported?.default || imported?.formieModule || null;
1801
+ if (!isModuleDefinition(definition)) return null;
1802
+ return definition;
1803
+ } catch (error) {
1804
+ console.error("[formie] Failed to load module from src:", src, error);
1805
+ debug$2.warn("Failed loading module from src.", {
1806
+ src,
1807
+ error
1808
+ });
1809
+ return null;
1810
+ }
1811
+ }
1812
+ async function resolveDefinition(manifestItem, ctx) {
1813
+ const registered = ctx.registry.get(manifestItem.id);
1814
+ if (registered) return registered;
1815
+ const builtin = await resolveBuiltinDefinition(manifestItem.id, ctx);
1816
+ if (builtin) return builtin;
1817
+ if (manifestItem.src) {
1818
+ const fromSrc = await resolveDefinitionFromSrc(manifestItem.src);
1819
+ if (fromSrc) {
1820
+ ctx.registry.register(fromSrc);
1821
+ return fromSrc;
1822
+ }
1823
+ }
1824
+ return null;
1825
+ }
1826
+ function escapeSelectorValue(value) {
1827
+ if (typeof window.CSS?.escape === "function") return window.CSS.escape(value);
1828
+ return value.replace(/["\\]/g, "\\$&");
1829
+ }
1830
+ function queryTargets(root, selector) {
1831
+ if (root.matches(selector)) return [root, ...Array.from(root.querySelectorAll(selector))];
1832
+ return Array.from(root.querySelectorAll(selector));
1833
+ }
1834
+ function resolveTarget(target, ctx) {
1835
+ const root = ctx.setupContext.root;
1836
+ const form = ctx.setupContext.form;
1837
+ const scope = target.targetType;
1838
+ const targetId = target.targetId;
1839
+ if (scope === "selector") return queryTargets(root, targetId).map((element) => {
1840
+ return {
1841
+ scope,
1842
+ element
1843
+ };
1844
+ });
1845
+ if (scope === "field") return queryTargets(root, `[data-formie-field-handle="${escapeSelectorValue(targetId)}"]`).map((element) => {
1846
+ return {
1847
+ scope,
1848
+ element
1849
+ };
1850
+ });
1851
+ if (scope === "page") return queryTargets(root, `[data-formie-page-id="${escapeSelectorValue(targetId)}"]`).map((element) => {
1852
+ return {
1853
+ scope,
1854
+ element
1855
+ };
1856
+ });
1857
+ if (scope === "button") return queryTargets(root, `[data-formie-action="${escapeSelectorValue(targetId)}"]`).map((element) => {
1858
+ return {
1859
+ scope,
1860
+ element
1861
+ };
1862
+ });
1863
+ return [{
1864
+ scope: "form",
1865
+ element: form || root
1866
+ }];
1867
+ }
1868
+ function resolveTargets(item, ctx) {
1869
+ return (item.targets && item.targets.length > 0 ? item.targets : [{
1870
+ targetType: "form",
1871
+ targetId: "form"
1872
+ }]).flatMap((target) => {
1873
+ return resolveTarget(target, ctx);
1874
+ });
1875
+ }
1876
+ async function loadModulesFromManifest(manifest, ctx) {
1877
+ const instances = [];
1878
+ debug$2.log("Loading module manifest.", { manifestCount: manifest.length });
1879
+ for (const item of manifest) {
1880
+ const definition = await resolveDefinition(item, ctx);
1881
+ if (!definition) {
1882
+ debug$2.warn("Skipping manifest item (definition not resolved).", {
1883
+ moduleId: item.id,
1884
+ src: item.src
1885
+ });
1886
+ continue;
1887
+ }
1888
+ const targets = resolveTargets(item, ctx);
1889
+ debug$2.log("Resolved module targets.", {
1890
+ moduleId: definition.id,
1891
+ targets: item.targets || [],
1892
+ targetCount: targets.length
1893
+ });
1894
+ if (targets.length === 0 && definition.kind === "address") console.warn(`[formie] Address module "${item.id}" skipped: no target element found for fieldHandle="${item.targets?.find((target) => target.targetType === "field")?.targetId ?? "?"}". Check that the Address field exists in the rendered form.`);
1895
+ for (const target of targets) {
1896
+ const matchContext = {
1897
+ ...ctx.matchContext,
1898
+ target: target.element,
1899
+ scope: target.scope,
1900
+ manifestItem: item
1901
+ };
1902
+ if (!definition.match(matchContext)) {
1903
+ if (definition.kind === "address") console.warn(`[formie] Address module "${definition.id}" skipped: target element does not contain [data-formie-address-autocomplete-input]. Enable the Auto-Complete subfield.`);
1904
+ debug$2.log("Module target did not match predicate.", {
1905
+ moduleId: definition.id,
1906
+ scope: target.scope
1907
+ });
1908
+ continue;
1909
+ }
1910
+ const options = item.config || ctx.setupContext.options;
1911
+ const moduleEventName = definition.id;
1912
+ const lifecycleDetail = {
1913
+ moduleId: definition.id,
1914
+ moduleKind: definition.kind,
1915
+ target: target.element,
1916
+ scope: target.scope,
1917
+ options,
1918
+ manifestItem: item
1919
+ };
1920
+ await emitModuleLifecycleEvent(ctx.setupContext.emit, moduleEventName, "before-setup", lifecycleDetail);
1921
+ let instance = null;
1922
+ try {
1923
+ const setupResult = await definition.setup({
1924
+ ...ctx.setupContext,
1925
+ target: target.element,
1926
+ scope: target.scope,
1927
+ options
1928
+ });
1929
+ if (setupResult) instance = setupResult;
1930
+ } catch (err) {
1931
+ console.error(`[formie] Module "${definition.id}" setup failed:`, err);
1932
+ debug$2.warn("Module setup failed.", {
1933
+ moduleId: definition.id,
1934
+ scope: target.scope,
1935
+ error: err
1936
+ });
1937
+ }
1938
+ await emitModuleLifecycleEvent(ctx.setupContext.emit, moduleEventName, "after-setup", {
1939
+ ...lifecycleDetail,
1940
+ instanceCreated: !!instance
1941
+ });
1942
+ if (instance) {
1943
+ debug$2.log("Module instance created.", {
1944
+ moduleId: definition.id,
1945
+ scope: target.scope
1946
+ });
1947
+ instances.push({
1948
+ ...instance,
1949
+ destroy: async () => {
1950
+ debug$2.log("Destroying module instance.", {
1951
+ moduleId: definition.id,
1952
+ scope: target.scope
1953
+ });
1954
+ await emitModuleLifecycleEvent(ctx.setupContext.emit, moduleEventName, "before-destroy", lifecycleDetail);
1955
+ await instance.destroy();
1956
+ await emitModuleLifecycleEvent(ctx.setupContext.emit, moduleEventName, "after-destroy", lifecycleDetail);
1957
+ debug$2.log("Module instance destroyed.", {
1958
+ moduleId: definition.id,
1959
+ scope: target.scope
1960
+ });
1961
+ }
1962
+ });
1963
+ }
1964
+ }
1965
+ }
1966
+ debug$2.log("Module manifest processing complete.", { instanceCount: instances.length });
1967
+ return instances;
1968
+ }
1969
+ //#endregion
1970
+ //#region src/js/utils/unload-warning.ts
1971
+ var DIRTY_TRACKING_IGNORED_FIELD_NAMES = new Set([
1972
+ "CRAFT_CSRF_TOKEN",
1973
+ "action",
1974
+ "redirect",
1975
+ "requestToken",
1976
+ "renderId",
1977
+ "submitAction",
1978
+ "pageId",
1979
+ "draftContextToken",
1980
+ "draftContext",
1981
+ "continuationToken"
1982
+ ]);
1983
+ function serializeStableValue(value, seen) {
1984
+ if (value == null) return String(value);
1985
+ if (typeof value === "string") return JSON.stringify(value);
1986
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
1987
+ if (typeof value === "function") return "[function]";
1988
+ if (typeof File !== "undefined" && value instanceof File) return `[file:${value.name}:${value.size}:${value.type}]`;
1989
+ if (typeof Blob !== "undefined" && value instanceof Blob) return `[blob:${value.size}:${value.type}]`;
1990
+ if (Array.isArray(value)) return `[${value.map((item) => serializeStableValue(item, seen)).join(",")}]`;
1991
+ if (typeof value === "object") {
1992
+ if (seen.has(value)) return "[circular]";
1993
+ seen.add(value);
1994
+ const entries = Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, item]) => {
1995
+ return `${JSON.stringify(key)}:${serializeStableValue(item, seen)}`;
1996
+ });
1997
+ seen.delete(value);
1998
+ return `{${entries.join(",")}}`;
1999
+ }
2000
+ return JSON.stringify(String(value));
2001
+ }
2002
+ function stableSerialize(value) {
2003
+ return serializeStableValue(value, /* @__PURE__ */ new WeakSet());
2004
+ }
2005
+ function shouldTrackFieldName(name) {
2006
+ if (!name) return false;
2007
+ const normalizedName = name.endsWith("[]") ? name.slice(0, -2) : name;
2008
+ return !DIRTY_TRACKING_IGNORED_FIELD_NAMES.has(normalizedName);
2009
+ }
2010
+ function buildTrackedSnapshot(form) {
2011
+ return stableSerialize(Array.from(new FormData(form).entries()).filter(([name]) => {
2012
+ return shouldTrackFieldName(String(name || ""));
2013
+ }));
2014
+ }
2015
+ function createFormUnloadWarningGuard(form, options = {}) {
2016
+ let baselineSnapshot = null;
2017
+ let isReady = false;
2018
+ let isDirty = false;
2019
+ let animationFrameId = null;
2020
+ let dirtyTimerId = null;
2021
+ let baselineTimerId = null;
2022
+ const clearScheduledWork = () => {
2023
+ if (animationFrameId !== null) {
2024
+ window.cancelAnimationFrame(animationFrameId);
2025
+ animationFrameId = null;
2026
+ }
2027
+ if (dirtyTimerId !== null) {
2028
+ window.clearTimeout(dirtyTimerId);
2029
+ dirtyTimerId = null;
2030
+ }
2031
+ if (baselineTimerId !== null) {
2032
+ window.clearTimeout(baselineTimerId);
2033
+ baselineTimerId = null;
2034
+ }
2035
+ };
2036
+ const refreshDirtyState = () => {
2037
+ if (!isReady) return false;
2038
+ isDirty = buildTrackedSnapshot(form) !== baselineSnapshot;
2039
+ return isDirty;
2040
+ };
2041
+ const captureBaseline = () => {
2042
+ baselineSnapshot = buildTrackedSnapshot(form);
2043
+ isReady = true;
2044
+ isDirty = false;
2045
+ };
2046
+ const scheduleBaselineCapture = () => {
2047
+ clearScheduledWork();
2048
+ isReady = false;
2049
+ animationFrameId = window.requestAnimationFrame(() => {
2050
+ animationFrameId = null;
2051
+ baselineTimerId = window.setTimeout(() => {
2052
+ baselineTimerId = null;
2053
+ captureBaseline();
2054
+ }, 0);
2055
+ });
2056
+ };
2057
+ const scheduleDirtyRefresh = () => {
2058
+ if (dirtyTimerId !== null) window.clearTimeout(dirtyTimerId);
2059
+ dirtyTimerId = window.setTimeout(() => {
2060
+ dirtyTimerId = null;
2061
+ refreshDirtyState();
2062
+ }, 120);
2063
+ };
2064
+ const handleBeforeUnload = (event) => {
2065
+ if (options.shouldWarn && !options.shouldWarn()) return;
2066
+ if (!refreshDirtyState()) return;
2067
+ event.preventDefault();
2068
+ event.returnValue = "";
2069
+ };
2070
+ form.addEventListener("input", scheduleDirtyRefresh);
2071
+ form.addEventListener("change", scheduleDirtyRefresh);
2072
+ window.addEventListener("beforeunload", handleBeforeUnload);
2073
+ scheduleBaselineCapture();
2074
+ return {
2075
+ captureBaseline,
2076
+ scheduleBaselineCapture,
2077
+ refreshDirtyState,
2078
+ destroy: () => {
2079
+ clearScheduledWork();
2080
+ form.removeEventListener("input", scheduleDirtyRefresh);
2081
+ form.removeEventListener("change", scheduleDirtyRefresh);
2082
+ window.removeEventListener("beforeunload", handleBeforeUnload);
2083
+ }
2084
+ };
2085
+ }
2086
+ //#endregion
2087
+ //#region src/js/core/create-formie-client.ts
2088
+ var ROOT_SELECTORS = "[data-formie]:not([data-formie-init=\"false\"]), [data-formie-form]:not([data-formie-init=\"false\"])";
2089
+ var DEFAULT_SUBMIT_DELAY_MS = 300;
2090
+ var DEFAULT_HEADLESS_RENDER_ACTION = "/actions/formie/server/forms/render";
2091
+ var DEFAULT_HEADLESS_GRAPHQL_ENDPOINT = "/api";
2092
+ var DEFAULT_HEADLESS_REFRESH_TOKENS_ACTION = "/actions/formie/server/forms/refresh-tokens";
2093
+ var DEFAULT_HEADLESS_SUBMIT_ACTION = "/actions/formie/server/submissions/submit";
2094
+ var DEFAULT_HEADLESS_SET_PAGE_ACTION = "/actions/formie/server/submissions/set-page";
2095
+ var DEFAULT_HEADLESS_CLEAR_SUBMISSION_ACTION = "/actions/formie/server/submissions/clear-submission";
2096
+ var DEFAULT_FILE_UPLOAD_HYDRATE_ACTION = "/actions/formie/file-upload/hydrate";
2097
+ var debug$1 = createDebug("general", "client");
2098
+ var compatibilityWarnings = /* @__PURE__ */ new Set();
2099
+ function parseBooleanOption(value, defaultValue) {
2100
+ if (value == null || value === "") return defaultValue;
2101
+ const normalized = value.toLowerCase();
2102
+ return !(normalized === "false" || normalized === "0" || normalized === "off");
2103
+ }
2104
+ function inferStaticCacheOnLoadFromDataset(dataset) {
2105
+ if (dataset.formieRefreshTokens != null && dataset.formieRefreshTokens !== "") return parseBooleanOption(dataset.formieRefreshTokens, false);
2106
+ if (dataset.formieStaticCache != null && dataset.formieStaticCache !== "") return parseBooleanOption(dataset.formieStaticCache, false);
2107
+ return false;
2108
+ }
2109
+ function inferOptionsFromElement(target) {
2110
+ const dataset = target instanceof HTMLElement ? target.dataset : {};
2111
+ return {
2112
+ mode: "server-rendered",
2113
+ transport: dataset.formieTransport || "rest",
2114
+ formHandle: dataset.formieHandle,
2115
+ endpoint: dataset.formieEndpoint,
2116
+ staticCache: inferStaticCacheOnLoadFromDataset(dataset),
2117
+ autoVisible: parseBooleanOption(dataset.formieAutoVisible, true),
2118
+ compatibility: parseBooleanOption(dataset.formieCompatibility, false)
2119
+ };
2120
+ }
2121
+ function normalizeMode(mode) {
2122
+ return mode || "server-rendered";
2123
+ }
2124
+ function normalizeTransport(transport) {
2125
+ return transport || "rest";
2126
+ }
2127
+ function getFormFromTarget(target) {
2128
+ if (target instanceof HTMLFormElement) return target;
2129
+ return target.querySelector("form");
2130
+ }
2131
+ function warnCompatibilityOnce(key, message) {
2132
+ if (compatibilityWarnings.has(key)) return;
2133
+ compatibilityWarnings.add(key);
2134
+ debug$1.warn(message);
2135
+ }
2136
+ function resolveEndpointAgainstBase(endpoint, baseEndpoint) {
2137
+ if (!endpoint) return endpoint;
2138
+ try {
2139
+ return new URL(endpoint).toString();
2140
+ } catch (_error) {}
2141
+ if (!baseEndpoint) return endpoint;
2142
+ try {
2143
+ return new URL(endpoint, baseEndpoint).toString();
2144
+ } catch (_error) {
2145
+ return endpoint;
2146
+ }
2147
+ }
2148
+ function resolveHeadlessEndpoint(baseOrEndpoint, actionPath) {
2149
+ const candidate = (baseOrEndpoint || "").trim();
2150
+ if (!candidate) return actionPath;
2151
+ if (candidate.includes("/actions/")) return candidate;
2152
+ return resolveEndpointAgainstBase(actionPath, candidate);
2153
+ }
2154
+ function resolveHtmlRenderEndpoint(options, target) {
2155
+ return resolveHeadlessEndpoint(options.endpoint || target.dataset.formieEndpoint, DEFAULT_HEADLESS_RENDER_ACTION);
2156
+ }
2157
+ function resolveGraphqlEndpoint(options, target) {
2158
+ const candidate = (options.endpoint || target.dataset.formieEndpoint || "").trim();
2159
+ if (!candidate) return DEFAULT_HEADLESS_GRAPHQL_ENDPOINT;
2160
+ if (candidate.includes("/graphql") || candidate.endsWith("/api") || candidate.includes("/actions/graphql/")) return candidate;
2161
+ return resolveEndpointAgainstBase(DEFAULT_HEADLESS_GRAPHQL_ENDPOINT, candidate);
2162
+ }
2163
+ function resolveRefreshTokensEndpoint(options, target) {
2164
+ return resolveHeadlessEndpoint(target.dataset.formieRefreshTokensEndpoint || options.endpoint || target.dataset.formieEndpoint, DEFAULT_HEADLESS_REFRESH_TOKENS_ACTION);
2165
+ }
2166
+ function mergeSearchParams(sourceUrl, destinationUrl) {
2167
+ if (!sourceUrl) return destinationUrl;
2168
+ try {
2169
+ const source = new URL(sourceUrl, window.location.origin);
2170
+ const destination = new URL(destinationUrl, window.location.origin);
2171
+ source.searchParams.forEach((value, key) => {
2172
+ if (!destination.searchParams.has(key)) destination.searchParams.set(key, value);
2173
+ });
2174
+ return destination.toString();
2175
+ } catch (_error) {
2176
+ return destinationUrl;
2177
+ }
2178
+ }
2179
+ function normalizeHeadlessManagedUrls(target, form, options) {
2180
+ const baseEndpoint = options.endpoint || target.dataset.formieEndpoint;
2181
+ const submitAction = resolveHeadlessEndpoint(baseEndpoint, DEFAULT_HEADLESS_SUBMIT_ACTION);
2182
+ const existingAction = form.getAttribute("action");
2183
+ form.setAttribute("action", mergeSearchParams(existingAction, submitAction));
2184
+ form.querySelectorAll("[data-formie-tab-link]").forEach((link) => {
2185
+ const existingHref = link.getAttribute("href");
2186
+ const setPageEndpoint = resolveHeadlessEndpoint(baseEndpoint, DEFAULT_HEADLESS_SET_PAGE_ACTION);
2187
+ link.setAttribute("href", mergeSearchParams(existingHref, setPageEndpoint));
2188
+ });
2189
+ form.querySelectorAll("[data-formie-file-upload-hydrate-endpoint]").forEach((input) => {
2190
+ input.setAttribute("data-formie-file-upload-hydrate-endpoint", resolveHeadlessEndpoint(baseEndpoint, DEFAULT_FILE_UPLOAD_HYDRATE_ACTION));
2191
+ });
2192
+ }
2193
+ function ensureSupportedHeadlessTransport(transport, mode) {
2194
+ if (transport === "graphql" && mode !== "server-rendered") throw new Error(`Formie ${mode} mode does not support GraphQL transport yet.`);
2195
+ }
2196
+ function parseBooleanDatasetValue(value) {
2197
+ if (value == null) return false;
2198
+ const normalized = value.trim().toLowerCase();
2199
+ return normalized === "true" || normalized === "1" || normalized === "";
2200
+ }
2201
+ function hasAutomaticSubmissionState(form) {
2202
+ return parseBooleanOption(form.dataset.formieAutomaticSubmissionState, true);
2203
+ }
2204
+ function resolveClearSubmissionEndpoint(options, target, form) {
2205
+ return resolveHeadlessEndpoint(form.dataset.formieClearSubmissionEndpoint || options.endpoint || target.dataset.formieEndpoint, DEFAULT_HEADLESS_CLEAR_SUBMISSION_ACTION);
2206
+ }
2207
+ function shouldEnableUnloadWarning(form) {
2208
+ return parseBooleanDatasetValue(form.dataset.formieUnloadWarning);
2209
+ }
2210
+ function markInternalNavigation(form, reason) {
2211
+ form.setAttribute("data-formie-internal-navigation", reason);
2212
+ }
2213
+ function clearInternalNavigation(form) {
2214
+ form.removeAttribute("data-formie-internal-navigation");
2215
+ }
2216
+ function hasInternalNavigation(form) {
2217
+ return form.getAttribute("data-formie-internal-navigation") !== null;
2218
+ }
2219
+ function urlHasSearchParam(sourceUrl, param) {
2220
+ if (!sourceUrl) return false;
2221
+ try {
2222
+ return new URL(sourceUrl, window.location.origin).searchParams.has(param);
2223
+ } catch (_error) {
2224
+ return false;
2225
+ }
2226
+ }
2227
+ function formHasResumeTokenState(form) {
2228
+ return urlHasSearchParam(window.location.href, "resumeToken") || urlHasSearchParam(form.getAttribute("action"), "resumeToken");
2229
+ }
2230
+ function isSameTabClickEvent(event) {
2231
+ if (!(event instanceof MouseEvent)) return true;
2232
+ return event.button === 0 && !event.metaKey && !event.ctrlKey && !event.shiftKey && !event.altKey;
2233
+ }
2234
+ function parseIntegerDatasetValue(value, fallback = 0) {
2235
+ if (!value) return fallback;
2236
+ const parsed = Number.parseInt(value, 10);
2237
+ if (!Number.isFinite(parsed)) return fallback;
2238
+ return parsed;
2239
+ }
2240
+ function getSubmitDelayMs(form) {
2241
+ return Math.max(0, parseIntegerDatasetValue(form.dataset.formieSubmitDelay, DEFAULT_SUBMIT_DELAY_MS));
2242
+ }
2243
+ function shouldValidateOnSubmit(form) {
2244
+ return parseBooleanDatasetValue(form.dataset.formieValidationOnSubmit);
2245
+ }
2246
+ async function waitForSubmitDelay(form) {
2247
+ const delay = getSubmitDelayMs(form);
2248
+ if (delay < 1) return;
2249
+ await new Promise((resolve) => {
2250
+ window.setTimeout(resolve, delay);
2251
+ });
2252
+ }
2253
+ function parseJsonAttribute(element, attributeName) {
2254
+ const rawValue = element?.getAttribute(attributeName)?.trim();
2255
+ if (!rawValue) return null;
2256
+ try {
2257
+ return JSON.parse(rawValue);
2258
+ } catch (error) {
2259
+ console.error(`[formie] Failed to parse ${attributeName}.`, error);
2260
+ return null;
2261
+ }
2262
+ }
2263
+ function getEmbeddedPayload(target, form) {
2264
+ const payloadRoot = form || (target instanceof HTMLFormElement ? target : null);
2265
+ if (!payloadRoot) return null;
2266
+ const modules = parseJsonAttribute(payloadRoot, "data-formie-modules");
2267
+ const theme = parseJsonAttribute(payloadRoot, "data-formie-theme");
2268
+ if (!modules && !theme) return null;
2269
+ return {
2270
+ modules: modules || void 0,
2271
+ theme: theme || void 0
2272
+ };
2273
+ }
2274
+ function isElementVisible(target) {
2275
+ if (!(target instanceof HTMLElement)) return true;
2276
+ if (!target.isConnected) return false;
2277
+ if (target.hidden || target.closest("[hidden]")) return false;
2278
+ const style = window.getComputedStyle(target);
2279
+ if (style.display === "none" || style.visibility === "hidden") return false;
2280
+ return target.getClientRects().length > 0;
2281
+ }
2282
+ function isWithinScope(target, scope) {
2283
+ if (scope === document) return true;
2284
+ if (scope instanceof Element) return scope === target || scope.contains(target);
2285
+ return true;
2286
+ }
2287
+ function getTargetDebugLabel(target) {
2288
+ const element = target;
2289
+ const id = element.id ? `#${element.id}` : "";
2290
+ const handle = element.dataset?.formieHandle ? `[handle="${element.dataset.formieHandle}"]` : "";
2291
+ return `${element.tagName ? element.tagName.toLowerCase() : "element"}${id}${handle}`;
2292
+ }
2293
+ function applyRefreshTokensToForm(form, refreshTokens) {
2294
+ if (!refreshTokens) return;
2295
+ if (refreshTokens.csrf?.param && refreshTokens.csrf?.token) {
2296
+ const csrfInput = form.querySelector(`input[name="${refreshTokens.csrf.param}"]`);
2297
+ if (csrfInput) csrfInput.value = refreshTokens.csrf.token;
2298
+ }
2299
+ if (refreshTokens.requestToken) {
2300
+ const requestTokenInput = form.querySelector("input[name=\"requestToken\"]");
2301
+ if (requestTokenInput) requestTokenInput.value = refreshTokens.requestToken;
2302
+ }
2303
+ if (refreshTokens.renderId) {
2304
+ const renderIdInput = form.querySelector("input[name=\"renderId\"]");
2305
+ if (renderIdInput) renderIdInput.value = refreshTokens.renderId;
2306
+ }
2307
+ if (refreshTokens.captchas && typeof refreshTokens.captchas === "object") Object.values(refreshTokens.captchas).forEach((captchaEntry) => {
2308
+ if (!captchaEntry || typeof captchaEntry !== "object") return;
2309
+ const entry = captchaEntry;
2310
+ if (!entry.sessionKey) return;
2311
+ const captchaInput = form.querySelector(`input[name="${entry.sessionKey}"]`);
2312
+ if (captchaInput && typeof entry.value === "string") captchaInput.value = entry.value;
2313
+ });
2314
+ }
2315
+ async function ensureHtmlRender(target, options) {
2316
+ const mode = normalizeMode(options.mode);
2317
+ const transport = normalizeTransport(options.transport);
2318
+ if (mode !== "server-rendered") return null;
2319
+ if (options.payload) {
2320
+ if (options.payload.html) target.innerHTML = options.payload.html;
2321
+ return options.payload;
2322
+ }
2323
+ ensureSupportedHeadlessTransport(transport, mode);
2324
+ const hasForm = !!getFormFromTarget(target);
2325
+ const formHandle = options.formHandle || target.dataset.formieHandle;
2326
+ if (hasForm || !formHandle) return null;
2327
+ const renderOptions = {
2328
+ mode,
2329
+ endpoint: options.endpoint,
2330
+ locale: options.locale,
2331
+ siteId: options.siteId,
2332
+ theme: options.theme,
2333
+ themeConfig: options.themeConfig
2334
+ };
2335
+ const endpoint = transport === "graphql" ? resolveGraphqlEndpoint(options, target) : resolveHtmlRenderEndpoint(options, target);
2336
+ const payload = transport === "graphql" ? await requestGraphqlRender(endpoint, formHandle, renderOptions) : await requestRender(endpoint, formHandle, {
2337
+ ...renderOptions,
2338
+ endpoint
2339
+ });
2340
+ if (payload?.html) target.innerHTML = payload.html;
2341
+ return payload;
2342
+ }
2343
+ async function refreshTokensAfterSubmitIfNeeded(target, options, form) {
2344
+ if (options.refreshTokens === false) return;
2345
+ ensureSupportedHeadlessTransport(normalizeTransport(options.transport), normalizeMode(options.mode));
2346
+ const formHandle = options.formHandle || target.dataset.formieHandle;
2347
+ if (!formHandle) return;
2348
+ const refreshTokens = await requestRefreshTokens(resolveRefreshTokensEndpoint(options, target), formHandle, form.querySelector("input[name=\"renderId\"]")?.value || void 0);
2349
+ applyRefreshTokensToForm(form, refreshTokens);
2350
+ dispatchFormieDomEvent(target, "formie:refresh-tokens:refreshed", refreshTokens);
2351
+ }
2352
+ function bindFormEvents(target, form, options, bus, validator, unbinds) {
2353
+ const submitMethod = String(form.dataset.formieSubmitMethod || "").trim().toLowerCase();
2354
+ const clearSubmissionEndpoint = resolveClearSubmissionEndpoint(options, target, form);
2355
+ let allowNativeSubmit = false;
2356
+ const submitButtons = form.querySelectorAll("[data-formie-action]");
2357
+ const setPendingAction = (action) => {
2358
+ if (action) {
2359
+ form.setAttribute("data-formie-pending-action", action);
2360
+ return;
2361
+ }
2362
+ form.removeAttribute("data-formie-pending-action");
2363
+ };
2364
+ if (shouldEnableUnloadWarning(form)) {
2365
+ const unloadWarning = createFormUnloadWarningGuard(form, { shouldWarn: () => {
2366
+ return !hasInternalNavigation(form);
2367
+ } });
2368
+ const handleSubmitResult = (event) => {
2369
+ if (!(event instanceof CustomEvent)) return;
2370
+ const result = event.detail;
2371
+ if (!result?.ok) return;
2372
+ if (result.action === "save") unloadWarning.scheduleBaselineCapture();
2373
+ };
2374
+ const handleStateReset = () => {
2375
+ unloadWarning.scheduleBaselineCapture();
2376
+ };
2377
+ target.addEventListener("formie:submit:result", handleSubmitResult);
2378
+ form.addEventListener("formie:state:reset", handleStateReset);
2379
+ unbinds.push(() => {
2380
+ target.removeEventListener("formie:submit:result", handleSubmitResult);
2381
+ form.removeEventListener("formie:state:reset", handleStateReset);
2382
+ unloadWarning.destroy();
2383
+ });
2384
+ }
2385
+ submitButtons.forEach((button) => {
2386
+ const handler = (event) => {
2387
+ const action = event.currentTarget.getAttribute("data-formie-action");
2388
+ const submitAction = form.querySelector("input[name=\"submitAction\"]");
2389
+ setPendingAction(action);
2390
+ if (action && submitAction) submitAction.value = action;
2391
+ };
2392
+ button.addEventListener("click", handler);
2393
+ unbinds.push(() => {
2394
+ button.removeEventListener("click", handler);
2395
+ });
2396
+ });
2397
+ form.querySelectorAll("[data-formie-tab-link]").forEach((link) => {
2398
+ const handler = async (event) => {
2399
+ if (submitMethod !== "ajax") {
2400
+ if (isSameTabClickEvent(event)) markInternalNavigation(form, "set-page");
2401
+ return;
2402
+ }
2403
+ event.preventDefault();
2404
+ const currentTarget = event.currentTarget;
2405
+ const nextPageId = currentTarget?.getAttribute("data-formie-page-id");
2406
+ const href = currentTarget?.getAttribute("href");
2407
+ if (!nextPageId || !href) return;
2408
+ applyPageState(form, nextPageId);
2409
+ dispatchFormieDomEvent(target, "formie:page:navigate", {
2410
+ pageId: nextPageId,
2411
+ href
2412
+ });
2413
+ try {
2414
+ dispatchFormieDomEvent(target, "formie:page:navigate:after", {
2415
+ pageId: nextPageId,
2416
+ href,
2417
+ response: await requestSetPage(href, form, nextPageId)
2418
+ });
2419
+ } catch (error) {
2420
+ console.error("[formie] Failed to persist page navigation state.", error);
2421
+ dispatchFormieDomEvent(target, "formie:page:navigate:error", {
2422
+ pageId: nextPageId,
2423
+ href,
2424
+ error
2425
+ });
2426
+ }
2427
+ };
2428
+ link.addEventListener("click", handler);
2429
+ unbinds.push(() => {
2430
+ link.removeEventListener("click", handler);
2431
+ });
2432
+ });
2433
+ if (!hasAutomaticSubmissionState(form)) {
2434
+ let requestedClearOnLeave = false;
2435
+ const leaveHandler = () => {
2436
+ if (requestedClearOnLeave || hasInternalNavigation(form) || formHasResumeTokenState(form)) return;
2437
+ requestedClearOnLeave = true;
2438
+ clearSubmissionOnUnload(clearSubmissionEndpoint, form);
2439
+ };
2440
+ window.addEventListener("pagehide", leaveHandler);
2441
+ window.addEventListener("beforeunload", leaveHandler);
2442
+ unbinds.push(() => {
2443
+ window.removeEventListener("pagehide", leaveHandler);
2444
+ window.removeEventListener("beforeunload", leaveHandler);
2445
+ });
2446
+ }
2447
+ const submitHandler = async (event) => {
2448
+ if (allowNativeSubmit) return;
2449
+ const isAjaxSubmit = submitMethod === "ajax";
2450
+ if (!isAjaxSubmit) event.preventDefault();
2451
+ else event.preventDefault();
2452
+ if (form.getAttribute("data-formie-loading") === "true") {
2453
+ if (!(form.getAttribute("data-formie-internal-resubmit") === "true")) return;
2454
+ form.removeAttribute("data-formie-internal-resubmit");
2455
+ } else form.removeAttribute("data-formie-internal-resubmit");
2456
+ const submitter = event.submitter;
2457
+ const actionFromSubmitter = submitter?.getAttribute("data-formie-action");
2458
+ const pendingAction = form.getAttribute("data-formie-pending-action");
2459
+ const submitAction = form.querySelector("input[name=\"submitAction\"]");
2460
+ const action = actionFromSubmitter || pendingAction || submitAction?.value || "submit";
2461
+ let result = null;
2462
+ let nativeSubmitStarted = false;
2463
+ try {
2464
+ if (isAjaxSubmit) result = await executeAjaxSubmitFlow({
2465
+ target,
2466
+ form,
2467
+ bus,
2468
+ validator,
2469
+ validateOnSubmit: shouldValidateOnSubmit(form),
2470
+ action,
2471
+ submitter,
2472
+ waitForSubmitDelay,
2473
+ onRefreshTokensAfterSubmit: async () => {
2474
+ await refreshTokensAfterSubmitIfNeeded(target, options, form);
2475
+ },
2476
+ dispatchSubmitResult: (submitResult) => {
2477
+ dispatchFormieDomEvent(target, "formie:submit:result", submitResult);
2478
+ }
2479
+ });
2480
+ else {
2481
+ clearSubmitFeedback(form);
2482
+ setSubmitLoading(form, submitter);
2483
+ await waitForSubmitDelay(form);
2484
+ result = await runSubmitPipeline(form, action, bus, {
2485
+ validator,
2486
+ validateOnSubmit: shouldValidateOnSubmit(form),
2487
+ preflightOnly: true
2488
+ });
2489
+ if (result.ok) {
2490
+ dispatchPageClientEventForSubmit(form, action);
2491
+ allowNativeSubmit = true;
2492
+ markInternalNavigation(form, "submit");
2493
+ setPendingAction(null);
2494
+ let nativeValidationFailed = false;
2495
+ const nativeInvalidHandler = () => {
2496
+ nativeValidationFailed = true;
2497
+ allowNativeSubmit = false;
2498
+ clearInternalNavigation(form);
2499
+ clearSubmitLoading(form);
2500
+ };
2501
+ if (typeof form.requestSubmit === "function") {
2502
+ form.addEventListener("invalid", nativeInvalidHandler, true);
2503
+ try {
2504
+ form.requestSubmit();
2505
+ } finally {
2506
+ form.removeEventListener("invalid", nativeInvalidHandler, true);
2507
+ }
2508
+ } else form.submit();
2509
+ if (nativeValidationFailed) return;
2510
+ nativeSubmitStarted = true;
2511
+ return;
2512
+ }
2513
+ applySubmitResultUi(form, result);
2514
+ dispatchFormieDomEvent(target, "formie:submit:result", result);
2515
+ clearInternalNavigation(form);
2516
+ }
2517
+ } catch (error) {
2518
+ allowNativeSubmit = false;
2519
+ result = {
2520
+ ok: false,
2521
+ code: "SUBMIT_ERROR",
2522
+ message: error instanceof Error ? error.message : "Submission failed.",
2523
+ formErrors: [error instanceof Error ? error.message : "Submission failed."]
2524
+ };
2525
+ applySubmitResultUi(form, result);
2526
+ dispatchFormieDomEvent(target, "formie:submit:result", result);
2527
+ clearInternalNavigation(form);
2528
+ } finally {
2529
+ setPendingAction(null);
2530
+ if (!isAjaxSubmit && !nativeSubmitStarted && !shouldKeepSubmitLoading(result)) clearSubmitLoading(form);
2531
+ }
2532
+ };
2533
+ form.addEventListener("submit", submitHandler);
2534
+ unbinds.push(() => {
2535
+ form.removeEventListener("submit", submitHandler);
2536
+ });
2537
+ }
2538
+ async function refreshTokensIfNeeded(target, options, form) {
2539
+ if (options.refreshTokens === false) return;
2540
+ if (!options.staticCache) return;
2541
+ ensureSupportedHeadlessTransport(normalizeTransport(options.transport), normalizeMode(options.mode));
2542
+ const formHandle = options.formHandle || target.dataset.formieHandle;
2543
+ const endpoint = resolveRefreshTokensEndpoint(options, target);
2544
+ const renderId = (form?.querySelector("input[name=\"renderId\"]"))?.value || void 0;
2545
+ if (!formHandle) return;
2546
+ const refreshTokens = await requestRefreshTokens(endpoint, formHandle, renderId);
2547
+ if (!refreshTokens || !form) return;
2548
+ applyRefreshTokensToForm(form, refreshTokens);
2549
+ dispatchFormieDomEvent(target, "formie:refresh-tokens:after", refreshTokens);
2550
+ }
2551
+ function createFormieClient() {
2552
+ const instances = /* @__PURE__ */ new Map();
2553
+ const moduleRegistry = new ModuleRegistry();
2554
+ const pendingVisibilityMounts = /* @__PURE__ */ new Map();
2555
+ const pendingUnmounts = /* @__PURE__ */ new Map();
2556
+ const stageNames = [
2557
+ "prepare",
2558
+ "normalize",
2559
+ "validate",
2560
+ "screen",
2561
+ "authorize",
2562
+ "dispatch",
2563
+ "finalize"
2564
+ ];
2565
+ const unmount = async (target) => {
2566
+ const inFlightUnmount = pendingUnmounts.get(target);
2567
+ if (inFlightUnmount) {
2568
+ await inFlightUnmount;
2569
+ return;
2570
+ }
2571
+ const unmountPromise = (async () => {
2572
+ debug$1.log("Unmount requested.", { target: getTargetDebugLabel(target) });
2573
+ const pendingUnmount = pendingVisibilityMounts.get(target);
2574
+ if (pendingUnmount) {
2575
+ pendingUnmount();
2576
+ pendingVisibilityMounts.delete(target);
2577
+ }
2578
+ const state = instances.get(target);
2579
+ if (!state) {
2580
+ debug$1.log("Unmount skipped (no mounted state).", { target: getTargetDebugLabel(target) });
2581
+ return;
2582
+ }
2583
+ dispatchFormieDomEvent(target, "formie:unmount:before", { id: state.instance.id });
2584
+ state.unbinds.forEach((unbind) => {
2585
+ unbind();
2586
+ });
2587
+ state.unbinds = [];
2588
+ state.validator?.destroy();
2589
+ state.validator = null;
2590
+ for (const moduleInstance of state.modules) await moduleInstance.destroy();
2591
+ state.modules = [];
2592
+ state.bus.clear();
2593
+ instances.delete(target);
2594
+ dispatchFormieDomEvent(target, "formie:unmount:after", { id: state.instance.id });
2595
+ debug$1.log("Unmount complete.", {
2596
+ id: state.instance.id,
2597
+ target: getTargetDebugLabel(target)
2598
+ });
2599
+ })().finally(() => {
2600
+ pendingUnmounts.delete(target);
2601
+ });
2602
+ pendingUnmounts.set(target, unmountPromise);
2603
+ await unmountPromise;
2604
+ };
2605
+ const mount = async (target, options) => {
2606
+ debug$1.log("Mount requested.", {
2607
+ target: getTargetDebugLabel(target),
2608
+ mode: options.mode,
2609
+ autoVisible: options.autoVisible
2610
+ });
2611
+ const pendingMount = pendingVisibilityMounts.get(target);
2612
+ if (pendingMount) {
2613
+ pendingMount();
2614
+ pendingVisibilityMounts.delete(target);
2615
+ }
2616
+ const existing = instances.get(target);
2617
+ if (existing) {
2618
+ debug$1.log("Mount skipped (already mounted).", {
2619
+ id: existing.instance.id,
2620
+ target: getTargetDebugLabel(target)
2621
+ });
2622
+ return existing.instance;
2623
+ }
2624
+ const bus = new EventBus();
2625
+ const unbinds = [];
2626
+ const id = target?.id || `formie-${instances.size + 1}`;
2627
+ const mergedFromDom = inferOptionsFromElement(target);
2628
+ const normalizedOptions = {
2629
+ ...mergedFromDom,
2630
+ ...options,
2631
+ mode: normalizeMode(options.mode ?? mergedFromDom.mode),
2632
+ transport: normalizeTransport(options.transport ?? mergedFromDom.transport)
2633
+ };
2634
+ const compatibilityOptions = resolveLegacyCompatibilityOptions(normalizedOptions.compatibility);
2635
+ if (normalizedOptions.mode !== "server-rendered" && !getFormFromTarget(target)) throw new Error(`Formie ${normalizedOptions.mode} mode is not implemented yet in the browser client.`);
2636
+ const renderPayload = await ensureHtmlRender(target, normalizedOptions);
2637
+ const form = getFormFromTarget(target);
2638
+ normalizedOptions.staticCache = options.staticCache ?? (form ? inferStaticCacheOnLoadFromDataset(form.dataset) : inferStaticCacheOnLoadFromDataset(target.dataset));
2639
+ const embeddedPayload = getEmbeddedPayload(target, form);
2640
+ const payload = renderPayload || embeddedPayload ? {
2641
+ ...renderPayload || {},
2642
+ ...embeddedPayload || {}
2643
+ } : null;
2644
+ const themeClassMap = payload?.theme;
2645
+ const stateStore = {};
2646
+ const moduleManifest = (payload?.modules || []).filter((item) => {
2647
+ return !!item?.id && !!item?.type;
2648
+ });
2649
+ debug$1.log("Resolved mount payload.", {
2650
+ target: getTargetDebugLabel(target),
2651
+ hasRenderPayload: !!renderPayload,
2652
+ hasEmbeddedPayload: !!embeddedPayload,
2653
+ moduleCount: moduleManifest.length
2654
+ });
2655
+ const resolvedThemeClassMap = registerThemeClassMap(target, themeClassMap, form);
2656
+ const validator = form ? new FormieValidator(form, {
2657
+ live: parseBooleanDatasetValue(form.dataset.formieValidationOnFocus),
2658
+ errorMessage: form.dataset.formieErrorMessage || "",
2659
+ fieldContainerErrorClass: resolvedThemeClassMap.fieldLayoutError || [],
2660
+ inputErrorClass: resolvedThemeClassMap.fieldControlError || [],
2661
+ messagesClass: resolvedThemeClassMap.fieldErrors || [],
2662
+ messageClass: resolvedThemeClassMap.fieldError || []
2663
+ }) : null;
2664
+ if (form && validator) {
2665
+ const formWithValidationApi = form;
2666
+ formWithValidationApi.formieValidation = validator;
2667
+ stateStore.validation = validator;
2668
+ const validatorDetail = {
2669
+ validator,
2670
+ addValidator: validator.addValidator.bind(validator),
2671
+ removeValidator: validator.removeValidator.bind(validator)
2672
+ };
2673
+ dispatchFormieDomEvent(form, "formie:validator:ready", validatorDetail);
2674
+ dispatchFormieDomEvent(target, "formie:validator:ready", validatorDetail);
2675
+ }
2676
+ if (form) {
2677
+ if (renderPayload || normalizedOptions.endpoint || target.dataset.formieEndpoint) normalizeHeadlessManagedUrls(target, form, normalizedOptions);
2678
+ syncPageTabErrors(form);
2679
+ }
2680
+ if (Object.keys(resolvedThemeClassMap).length) dispatchFormieDomEvent(target, "formie:theme:applied", { hasClasses: true });
2681
+ const modules = await loadModulesFromManifest(moduleManifest, {
2682
+ registry: moduleRegistry,
2683
+ matchContext: {
2684
+ root: target,
2685
+ form,
2686
+ mode: normalizedOptions.mode
2687
+ },
2688
+ setupContext: {
2689
+ formId: id,
2690
+ root: target,
2691
+ form,
2692
+ target,
2693
+ scope: "form",
2694
+ state: stateStore,
2695
+ on: (eventName, callback) => {
2696
+ return bus.on(eventName, callback);
2697
+ },
2698
+ emit: (eventName, payload) => {
2699
+ dispatchFormieDomEvent(target, eventName, payload);
2700
+ return bus.emitSafe(eventName, payload).then((emitReport) => {
2701
+ if (emitReport.failed.length > 0) debug$1.warn("Lifecycle listeners failed.", {
2702
+ eventName,
2703
+ failed: emitReport.failed.length
2704
+ });
2705
+ });
2706
+ }
2707
+ }
2708
+ });
2709
+ debug$1.log("Module setup complete.", {
2710
+ target: getTargetDebugLabel(target),
2711
+ moduleInstances: modules.length
2712
+ });
2713
+ const instance = {
2714
+ id,
2715
+ root: target,
2716
+ submit: async (action = "submit") => {
2717
+ debug$1.log("Submit requested.", {
2718
+ id,
2719
+ target: getTargetDebugLabel(target),
2720
+ action
2721
+ });
2722
+ if (!form) return {
2723
+ ok: false,
2724
+ code: "FORM_NOT_FOUND",
2725
+ message: "No form element found for mount target.",
2726
+ formErrors: ["No form element found for mount target."]
2727
+ };
2728
+ const submitAction = form.querySelector("input[name=\"submitAction\"]");
2729
+ if (submitAction) submitAction.value = action;
2730
+ if (form.getAttribute("data-formie-loading") === "true") return {
2731
+ ok: false,
2732
+ code: "SUBMIT_IN_PROGRESS",
2733
+ message: "Submission already in progress.",
2734
+ formErrors: []
2735
+ };
2736
+ const fallbackSubmitter = form.querySelector(`[data-formie-action="${action}"]`);
2737
+ const result = await executeAjaxSubmitFlow({
2738
+ id,
2739
+ target,
2740
+ form,
2741
+ bus,
2742
+ validator,
2743
+ validateOnSubmit: shouldValidateOnSubmit(form),
2744
+ action,
2745
+ submitter: fallbackSubmitter,
2746
+ waitForSubmitDelay,
2747
+ onRefreshTokensAfterSubmit: async () => {
2748
+ await refreshTokensAfterSubmitIfNeeded(target, normalizedOptions, form);
2749
+ },
2750
+ dispatchSubmitResult: (submitResult) => {
2751
+ dispatchFormieDomEvent(target, "formie:submit:result", submitResult);
2752
+ }
2753
+ });
2754
+ debug$1.log("Submit completed.", {
2755
+ id,
2756
+ action,
2757
+ ok: result.ok,
2758
+ code: result.code,
2759
+ message: result.message
2760
+ });
2761
+ return result;
2762
+ },
2763
+ destroy: async () => {
2764
+ await unmount(target);
2765
+ },
2766
+ on: (eventName, callback) => {
2767
+ return bus.on(eventName, callback);
2768
+ }
2769
+ };
2770
+ if (form) {
2771
+ bindLegacyValidatorCompatibility({
2772
+ target,
2773
+ form,
2774
+ validatorDetail: validator ? {
2775
+ validator,
2776
+ addValidator: validator.addValidator.bind(validator),
2777
+ removeValidator: validator.removeValidator.bind(validator)
2778
+ } : null,
2779
+ options: compatibilityOptions,
2780
+ unbinds
2781
+ });
2782
+ bindLegacyDomEventCompatibility({
2783
+ target,
2784
+ form,
2785
+ instance,
2786
+ options: compatibilityOptions,
2787
+ unbinds
2788
+ });
2789
+ }
2790
+ if (form) {
2791
+ bindFormEvents(target, form, normalizedOptions, bus, validator, unbinds);
2792
+ await refreshTokensIfNeeded(target, normalizedOptions, form);
2793
+ }
2794
+ stageNames.forEach((stageName) => {
2795
+ const beforeDomUnbind = bus.on(`formie:stage:${stageName}:before`, async (payload) => {
2796
+ dispatchFormieDomEvent(target, `formie:stage:${stageName}:before`, payload);
2797
+ });
2798
+ const beforeUnbind = bus.on(`formie:stage:${stageName}:before`, async (payload) => {
2799
+ for (const moduleInstance of modules) if (moduleInstance.onBeforeStage) await moduleInstance.onBeforeStage(payload);
2800
+ });
2801
+ const afterDomUnbind = bus.on(`formie:stage:${stageName}:after`, async (payload) => {
2802
+ dispatchFormieDomEvent(target, `formie:stage:${stageName}:after`, payload);
2803
+ });
2804
+ const afterUnbind = bus.on(`formie:stage:${stageName}:after`, async (payload) => {
2805
+ const stagePayload = payload;
2806
+ for (const moduleInstance of modules) if (moduleInstance.onAfterStage) await moduleInstance.onAfterStage(stagePayload, stagePayload.result);
2807
+ });
2808
+ unbinds.push(beforeDomUnbind, beforeUnbind, afterDomUnbind, afterUnbind);
2809
+ });
2810
+ const submitBeforeUnbind = bus.on("formie:submit:before", async (payload) => {
2811
+ dispatchFormieDomEvent(target, "formie:submit:before", payload);
2812
+ });
2813
+ const submitAfterUnbind = bus.on("formie:submit:after", async (payload) => {
2814
+ dispatchFormieDomEvent(target, "formie:submit:after", payload);
2815
+ });
2816
+ const submitFinalBeforeUnbind = bus.on("formie:submit:final:before", async (payload) => {
2817
+ dispatchFormieDomEvent(target, "formie:submit:final:before", payload);
2818
+ });
2819
+ const submitFinalAfterUnbind = bus.on("formie:submit:final:after", async (payload) => {
2820
+ dispatchFormieDomEvent(target, "formie:submit:final:after", payload);
2821
+ });
2822
+ unbinds.push(submitBeforeUnbind, submitAfterUnbind, submitFinalBeforeUnbind, submitFinalAfterUnbind);
2823
+ instances.set(target, {
2824
+ options: normalizedOptions,
2825
+ bus,
2826
+ form,
2827
+ validator,
2828
+ modules,
2829
+ unbinds,
2830
+ instance
2831
+ });
2832
+ dispatchFormieDomEvent(target, "formie:mount:after", {
2833
+ id,
2834
+ mode: normalizedOptions.mode
2835
+ });
2836
+ debug$1.log("Mount complete.", {
2837
+ id,
2838
+ target: getTargetDebugLabel(target),
2839
+ mode: normalizedOptions.mode
2840
+ });
2841
+ return instance;
2842
+ };
2843
+ const mountWhenVisible = (target, options) => {
2844
+ if (!options.autoVisible || isElementVisible(target) || typeof IntersectionObserver === "undefined") return mount(target, options);
2845
+ if (instances.has(target)) return Promise.resolve(instances.get(target)?.instance || null);
2846
+ if (pendingVisibilityMounts.has(target)) {
2847
+ debug$1.log("Mount deferred (already waiting visibility).", { target: getTargetDebugLabel(target) });
2848
+ return Promise.resolve(null);
2849
+ }
2850
+ const observer = new IntersectionObserver((entries) => {
2851
+ if (!entries.some((entry) => {
2852
+ return entry.target === target && entry.isIntersecting;
2853
+ })) return;
2854
+ observer.disconnect();
2855
+ pendingVisibilityMounts.delete(target);
2856
+ debug$1.log("Visibility reached, proceeding mount.", { target: getTargetDebugLabel(target) });
2857
+ mount(target, {
2858
+ ...options,
2859
+ autoVisible: false
2860
+ });
2861
+ }, { threshold: .01 });
2862
+ observer.observe(target);
2863
+ pendingVisibilityMounts.set(target, () => {
2864
+ observer.disconnect();
2865
+ });
2866
+ debug$1.log("Mount deferred until visible.", { target: getTargetDebugLabel(target) });
2867
+ return Promise.resolve(null);
2868
+ };
2869
+ const update = async (target, options) => {
2870
+ const state = instances.get(target);
2871
+ if (!state) return mount(target, {
2872
+ ...inferOptionsFromElement(target),
2873
+ ...options,
2874
+ mode: options.mode || "server-rendered"
2875
+ });
2876
+ state.options = {
2877
+ ...state.options,
2878
+ ...options
2879
+ };
2880
+ const resolvedThemeClassMap = registerThemeClassMap(target, options.payload?.theme || state.options.payload?.theme || getEmbeddedPayload(target, state.form)?.theme, state.form);
2881
+ if (state.validator) {
2882
+ state.validator.config.fieldContainerErrorClass = resolvedThemeClassMap.fieldLayoutError || [];
2883
+ state.validator.config.inputErrorClass = resolvedThemeClassMap.fieldControlError || [];
2884
+ state.validator.config.messagesClass = resolvedThemeClassMap.fieldErrors || [];
2885
+ state.validator.config.messageClass = resolvedThemeClassMap.fieldError || [];
2886
+ }
2887
+ if (Object.keys(resolvedThemeClassMap).length) dispatchFormieDomEvent(target, "formie:theme:applied", {
2888
+ hasClasses: true,
2889
+ reason: "update"
2890
+ });
2891
+ return state.instance;
2892
+ };
2893
+ const getInstance = (target) => {
2894
+ return instances.get(target)?.instance || null;
2895
+ };
2896
+ const refreshForCache = async (targetOrId) => {
2897
+ warnCompatibilityOnce("refreshForCache", "Global `Formie.refreshForCache()` has been deprecated. Use built-in static-cache token refresh handling instead.");
2898
+ let target = null;
2899
+ if (typeof targetOrId === "string") {
2900
+ const byId = document.getElementById(targetOrId);
2901
+ if (byId) target = byId;
2902
+ else target = document.querySelector(`[data-formie-form-id="${targetOrId}"]`);
2903
+ } else target = targetOrId;
2904
+ if (!target) {
2905
+ debug$1.warn("refreshForCache target not found.", { targetOrId });
2906
+ return;
2907
+ }
2908
+ const state = instances.get(target);
2909
+ const form = getFormFromTarget(target);
2910
+ const options = state?.options || inferOptionsFromElement(target);
2911
+ if (!form) {
2912
+ debug$1.warn("refreshForCache found no form element for target.", { target: getTargetDebugLabel(target) });
2913
+ return;
2914
+ }
2915
+ const formHandle = options.formHandle || target.dataset.formieHandle || form.dataset.formieHandle;
2916
+ const endpoint = resolveRefreshTokensEndpoint(options, target);
2917
+ const renderId = form.querySelector("input[name=\"renderId\"]")?.value || void 0;
2918
+ if (!formHandle) {
2919
+ debug$1.warn("refreshForCache found no form handle for target.", { target: getTargetDebugLabel(target) });
2920
+ return;
2921
+ }
2922
+ const refreshTokens = await requestRefreshTokens(endpoint, formHandle, renderId);
2923
+ if (!refreshTokens) return;
2924
+ applyRefreshTokensToForm(form, refreshTokens);
2925
+ dispatchFormieDomEvent(target, "formie:refresh-tokens:after", refreshTokens);
2926
+ };
2927
+ const registerModule = (moduleDefinition, options) => {
2928
+ return moduleRegistry.register(moduleDefinition, options);
2929
+ };
2930
+ const unregisterModule = (moduleId) => {
2931
+ moduleRegistry.unregister(moduleId);
2932
+ };
2933
+ const getRegisteredModules = () => {
2934
+ return moduleRegistry.getAll();
2935
+ };
2936
+ const scan = async (root) => {
2937
+ const scope = root || document;
2938
+ const targets = Array.from(scope.querySelectorAll(ROOT_SELECTORS));
2939
+ debug$1.log("Scan started.", {
2940
+ scope: scope === document ? "document" : scope,
2941
+ targetCount: targets.length
2942
+ });
2943
+ const instances = (await Promise.all(targets.map((target) => {
2944
+ return mountWhenVisible(target, inferOptionsFromElement(target));
2945
+ }))).filter((item) => !!item);
2946
+ debug$1.log("Scan finished.", {
2947
+ mountedCount: instances.length,
2948
+ deferredCount: targets.length - instances.length
2949
+ });
2950
+ return instances;
2951
+ };
2952
+ const observe = (root) => {
2953
+ if (typeof MutationObserver === "undefined") return () => {};
2954
+ const scope = root || document;
2955
+ debug$1.log("Observer started.", { scope: scope === document ? "document" : scope });
2956
+ const observer = new MutationObserver((mutations) => {
2957
+ mutations.forEach((mutation) => {
2958
+ mutation.addedNodes.forEach((node) => {
2959
+ if (!(node instanceof Element)) return;
2960
+ if (node.matches(ROOT_SELECTORS)) {
2961
+ debug$1.log("Observer detected new root.", { target: getTargetDebugLabel(node) });
2962
+ mountWhenVisible(node, inferOptionsFromElement(node));
2963
+ }
2964
+ node.querySelectorAll(ROOT_SELECTORS).forEach((child) => {
2965
+ debug$1.log("Observer detected new nested root.", { target: getTargetDebugLabel(child) });
2966
+ mountWhenVisible(child, inferOptionsFromElement(child));
2967
+ });
2968
+ });
2969
+ mutation.removedNodes.forEach((node) => {
2970
+ if (!(node instanceof Element)) return;
2971
+ if (instances.has(node)) {
2972
+ debug$1.log("Observer detected removed root.", { target: getTargetDebugLabel(node) });
2973
+ unmount(node);
2974
+ }
2975
+ node.querySelectorAll(ROOT_SELECTORS).forEach((child) => {
2976
+ if (instances.has(child)) {
2977
+ debug$1.log("Observer detected removed nested root.", { target: getTargetDebugLabel(child) });
2978
+ unmount(child);
2979
+ }
2980
+ });
2981
+ });
2982
+ });
2983
+ });
2984
+ observer.observe(scope, {
2985
+ childList: true,
2986
+ subtree: true
2987
+ });
2988
+ return () => {
2989
+ observer.disconnect();
2990
+ debug$1.log("Observer stopped.");
2991
+ pendingVisibilityMounts.forEach((cleanup, target) => {
2992
+ if (isWithinScope(target, scope)) {
2993
+ cleanup();
2994
+ pendingVisibilityMounts.delete(target);
2995
+ }
2996
+ });
2997
+ const roots = [];
2998
+ if (scope instanceof Element && scope.matches(ROOT_SELECTORS)) roots.push(scope);
2999
+ scope.querySelectorAll(ROOT_SELECTORS).forEach((target) => {
3000
+ roots.push(target);
3001
+ });
3002
+ roots.forEach((target) => {
3003
+ if (instances.has(target)) unmount(target);
3004
+ });
3005
+ };
3006
+ };
3007
+ return {
3008
+ mount,
3009
+ unmount,
3010
+ update,
3011
+ getInstance,
3012
+ refreshForCache,
3013
+ registerModule,
3014
+ unregisterModule,
3015
+ getRegisteredModules,
3016
+ scan,
3017
+ observe
3018
+ };
3019
+ }
3020
+ //#endregion
3021
+ //#region src/js/core/hydrate-modules.ts
3022
+ var debug = createDebug("general", "module-hydrator");
3023
+ async function hydrateFormieModules(options) {
3024
+ const root = options.root;
3025
+ const form = options.form ?? (root instanceof HTMLFormElement ? root : root.closest("form"));
3026
+ const modules = options.modules ?? [];
3027
+ const mode = options.mode ?? "server-rendered";
3028
+ const registry = options.registry ?? new ModuleRegistry();
3029
+ const bus = new EventBus();
3030
+ const instances = await loadModulesFromManifest(modules, {
3031
+ registry,
3032
+ setupContext: {
3033
+ formId: form?.id || root.id || "formie-modules",
3034
+ root,
3035
+ form,
3036
+ target: root,
3037
+ scope: "form",
3038
+ state: {},
3039
+ options: {},
3040
+ on: (eventName, callback) => {
3041
+ return bus.on(eventName, callback);
3042
+ },
3043
+ emit: async (eventName, payload) => {
3044
+ await bus.emit(eventName, payload);
3045
+ }
3046
+ },
3047
+ matchContext: {
3048
+ root,
3049
+ form,
3050
+ mode
3051
+ }
3052
+ });
3053
+ debug.log("Hydrated module manifest.", {
3054
+ moduleCount: modules.length,
3055
+ instanceCount: instances.length,
3056
+ mode
3057
+ });
3058
+ return {
3059
+ destroy: async () => {
3060
+ await destroyModuleInstances(instances);
3061
+ bus.clear();
3062
+ },
3063
+ on: (eventName, callback) => {
3064
+ return bus.on(eventName, callback);
3065
+ },
3066
+ emit: async (eventName, payload) => {
3067
+ await bus.emit(eventName, payload);
3068
+ },
3069
+ registerModule: (moduleDefinition, registrationOptions = {}) => {
3070
+ return registry.register(moduleDefinition, registrationOptions);
3071
+ },
3072
+ unregisterModule: (moduleId) => {
3073
+ registry.unregister(moduleId);
3074
+ },
3075
+ getRegisteredModules: () => {
3076
+ return registry.getAll();
3077
+ }
3078
+ };
3079
+ }
3080
+ async function destroyModuleInstances(instances) {
3081
+ for (const instance of instances) try {
3082
+ await instance.destroy();
3083
+ } catch (error) {
3084
+ console.error("[formie] Failed to destroy module instance.", error);
3085
+ debug.warn("Failed destroying module instance.", { error });
3086
+ }
3087
+ }
3088
+ //#endregion
3089
+ //#region src/js/core/formie.ts
3090
+ function isElement(value) {
3091
+ return value instanceof Element;
3092
+ }
3093
+ function isSuccessfulResult(result) {
3094
+ return result.ok;
3095
+ }
3096
+ function describeTarget(target) {
3097
+ if (typeof target === "string") return `selector "${target}"`;
3098
+ if (isElement(target)) return `element "${target.tagName.toLowerCase()}"`;
3099
+ return "provided element collection";
3100
+ }
3101
+ function toUniqueElements(values) {
3102
+ const seen = /* @__PURE__ */ new Set();
3103
+ const elements = [];
3104
+ for (const value of values) {
3105
+ if (!isElement(value) || seen.has(value)) continue;
3106
+ seen.add(value);
3107
+ elements.push(value);
3108
+ }
3109
+ return elements;
3110
+ }
3111
+ function resolveElements(target) {
3112
+ if (typeof target === "string") return Array.from(document.querySelectorAll(target));
3113
+ if (isElement(target)) return [target];
3114
+ return toUniqueElements(target);
3115
+ }
3116
+ function waitForDomReady() {
3117
+ if (document.readyState !== "loading") return Promise.resolve();
3118
+ return new Promise((resolve) => {
3119
+ document.addEventListener("DOMContentLoaded", () => resolve(), { once: true });
3120
+ });
3121
+ }
3122
+ async function resolveElementsWhenReady(target) {
3123
+ const elements = resolveElements(target);
3124
+ if (elements.length > 0 || typeof target !== "string") return elements;
3125
+ await waitForDomReady();
3126
+ return resolveElements(target);
3127
+ }
3128
+ function resolveObservationScope(target) {
3129
+ if (typeof target === "string") return document;
3130
+ if (isElement(target)) return target.getRootNode();
3131
+ return document;
3132
+ }
3133
+ function buildMountOptions(options) {
3134
+ const { element: _element, observe: _observe, allowEmpty: _allowEmpty, client: _client, onReady: _onReady, onResult: _onResult, onSuccess: _onSuccess, onError: _onError, onEvent: _onEvent, ...mountOptions } = options;
3135
+ return {
3136
+ mode: "server-rendered",
3137
+ ...mountOptions
3138
+ };
3139
+ }
3140
+ async function mountResolvedElements(options, client, states, targets) {
3141
+ const mounted = [];
3142
+ const mountOptions = buildMountOptions(options);
3143
+ for (const target of targets) {
3144
+ const existing = states.get(target);
3145
+ if (existing) {
3146
+ mounted.push(existing.instance);
3147
+ continue;
3148
+ }
3149
+ const instance = await client.mount(target, mountOptions);
3150
+ const unsubs = [];
3151
+ options.onReady?.(instance);
3152
+ unsubs.push(instance.on("formie:submit:result", (payload) => {
3153
+ const result = payload;
3154
+ options.onResult?.(result, instance);
3155
+ if (isSuccessfulResult(result)) options.onSuccess?.(result, instance);
3156
+ else options.onError?.(result, instance);
3157
+ }));
3158
+ if (options.onEvent) for (const eventName of FORMIE_HTML_EVENT_NAMES) unsubs.push(instance.on(eventName, (payload) => {
3159
+ options.onEvent?.({
3160
+ name: eventName,
3161
+ payload
3162
+ }, instance);
3163
+ }));
3164
+ states.set(target, {
3165
+ instance,
3166
+ unsubs
3167
+ });
3168
+ mounted.push(instance);
3169
+ }
3170
+ return mounted;
3171
+ }
3172
+ async function formie(options) {
3173
+ const client = options.client ?? createFormieClient();
3174
+ const states = /* @__PURE__ */ new Map();
3175
+ const matchedElements = await resolveElementsWhenReady(options.element);
3176
+ if (matchedElements.length === 0 && !options.allowEmpty) throw new Error(`Formie could not find any elements for ${describeTarget(options.element)}.`);
3177
+ await mountResolvedElements(options, client, states, matchedElements);
3178
+ const stopObserving = options.observe ? client.observe(resolveObservationScope(options.element)) : null;
3179
+ return {
3180
+ client,
3181
+ get instances() {
3182
+ return Array.from(states.values()).map(({ instance }) => instance);
3183
+ },
3184
+ get(target) {
3185
+ const element = typeof target === "string" ? document.querySelector(target) : target;
3186
+ if (!element) return null;
3187
+ return states.get(element)?.instance ?? client.getInstance(element);
3188
+ },
3189
+ async rescan() {
3190
+ const nextTargets = resolveElements(options.element);
3191
+ if (nextTargets.length === 0) return Array.from(states.values()).map(({ instance }) => instance);
3192
+ return mountResolvedElements(options, client, states, nextTargets);
3193
+ },
3194
+ async destroy() {
3195
+ stopObserving?.();
3196
+ const mountedEntries = Array.from(states.entries());
3197
+ for (const [target, state] of mountedEntries) {
3198
+ state.unsubs.forEach((unsubscribe) => unsubscribe());
3199
+ await client.unmount(target);
3200
+ states.delete(target);
3201
+ }
3202
+ }
3203
+ };
3204
+ }
3205
+ //#endregion
3206
+ export { FORMIE_HTML_EVENT_NAMES, FormieValidator, LEGACY_FORMIE_DOM_EVENT_BRIDGES, LEGACY_FORMIE_VALIDATOR_EVENT_BRIDGES, ModuleRegistry, bindLegacyDomEventCompatibility, bindLegacyValidatorCompatibility, buildFieldValueRegistry, createDebug, createFormieClient, debugLog, debugWarn, defineAddressModule, defineCaptchaModule, definePassiveCaptchaModule, definePaymentModule, fieldKeyToInputName, formie, getFieldModuleEventName, getFormieTranslations, getGlobalModuleLifecycleEventName, getScopedModuleLifecycleEventName, hydrateFormieModules, inputNameToFieldKey, isFormieDebugEnabled, mergeFormieTranslations, normalizeFieldKey, normalizeFormieEventName, parseFieldReference, resolveFieldReferenceFromFormData, resolveFieldReferenceLive, resolveLegacyCompatibilityOptions, setFormieDebugEnabled, setFormieTranslations, t, toDomEventName, translate };