@verbb/formie-browser 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (490) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/LICENSE.md +40 -0
  3. package/README.md +34 -0
  4. package/dist/chunks/address-finder-DfMCiW89.js +47 -0
  5. package/dist/chunks/api-CbqEMQT5.js +181 -0
  6. package/dist/chunks/api-DE7LfK-R.js +960 -0
  7. package/dist/chunks/api-DOfDzYC_.js +538 -0
  8. package/dist/chunks/async-B3DUf1GZ.js +26 -0
  9. package/dist/chunks/bpoint-Ciy3yY9Q.js +34 -0
  10. package/dist/chunks/calculations-CkYAqO_-.js +197 -0
  11. package/dist/chunks/captcha-eu-DnOWhMwr.js +43 -0
  12. package/dist/chunks/checkbox-radio-0x7Tc0br.js +197 -0
  13. package/dist/chunks/chunk-K6L4z4UQ.js +24 -0
  14. package/dist/chunks/conditions-4fXKhEJS.js +609 -0
  15. package/dist/chunks/date-picker-B6iZkjHS.js +6204 -0
  16. package/dist/chunks/debug-KnZeKYBI.js +39 -0
  17. package/dist/chunks/dist-D09GnXMW.js +2663 -0
  18. package/dist/chunks/event-names-DamGPtXR.js +51 -0
  19. package/dist/chunks/eway-DEAYcwT0.js +86 -0
  20. package/dist/chunks/field-references.keys-BpBZ_quS.js +24 -0
  21. package/dist/chunks/field-references.resolver-Ba6xhiJC.js +183 -0
  22. package/dist/chunks/file-upload-Bh63PQSE.js +430 -0
  23. package/dist/chunks/friendly-captcha-v1-CqO4WVre.js +40 -0
  24. package/dist/chunks/friendly-captcha-v2-CyykcJcM.js +47 -0
  25. package/dist/chunks/friendly-challenge-Dg8XkStd.js +1101 -0
  26. package/dist/chunks/go-cardless-CuND59rR.js +26 -0
  27. package/dist/chunks/google-address--uR8WDSm.js +208 -0
  28. package/dist/chunks/hcaptcha-CmaFUesv.js +72 -0
  29. package/dist/chunks/hidden-CYnZYple.js +36 -0
  30. package/dist/chunks/http-18nn97DZ.js +29 -0
  31. package/dist/chunks/i18n-vUh-KGiH.js +55 -0
  32. package/dist/chunks/loqate-BICNJlVK.js +97 -0
  33. package/dist/chunks/mollie-DwlsgHZ1.js +26 -0
  34. package/dist/chunks/moneris-B_IFZFTx.js +159 -0
  35. package/dist/chunks/opayo-U2x_TOII.js +192 -0
  36. package/dist/chunks/paddle-BqXFrc79.js +75 -0
  37. package/dist/chunks/paypal-Cn_DYGDb.js +121 -0
  38. package/dist/chunks/payway-Rnq796eC.js +75 -0
  39. package/dist/chunks/phone-country-B6Me4lK0.js +3317 -0
  40. package/dist/chunks/place-kit-ldUl-u9w.js +56 -0
  41. package/dist/chunks/placekit-autocomplete.esm-D-lGeaZl.js +1771 -0
  42. package/dist/chunks/recaptcha-enterprise-DPJNyv1X.js +72 -0
  43. package/dist/chunks/recaptcha-shared-DTI4qWVR.js +22 -0
  44. package/dist/chunks/recaptcha-v2-checkbox-zFjpvJ5c.js +49 -0
  45. package/dist/chunks/recaptcha-v2-invisible-CnYtkNvz.js +62 -0
  46. package/dist/chunks/recaptcha-v3-EAlWhnkX.js +33 -0
  47. package/dist/chunks/repeater-CXD1eLSn.js +151 -0
  48. package/dist/chunks/rich-text-DkmZRhGj.js +442 -0
  49. package/dist/chunks/scripts-BGD_iU_6.js +41 -0
  50. package/dist/chunks/sdk-B7u9fTlP.js +2103 -0
  51. package/dist/chunks/shared-DC6_1u8X.js +85 -0
  52. package/dist/chunks/signature-E9KyYXS1.js +765 -0
  53. package/dist/chunks/snaptcha-CCDunGeb.js +8 -0
  54. package/dist/chunks/square-BLqK51rS.js +61 -0
  55. package/dist/chunks/stripe-B8gHpZNC.js +273 -0
  56. package/dist/chunks/styles-BIh6g7V_.js +22 -0
  57. package/dist/chunks/summary-EcNE0cvg.js +191 -0
  58. package/dist/chunks/table-yxEDL6kA.js +124 -0
  59. package/dist/chunks/text-limit-D0H_Ca2c.js +179 -0
  60. package/dist/chunks/theme-classes-vSHpdCUO.js +59 -0
  61. package/dist/chunks/turnstile-DP0bdR7T.js +68 -0
  62. package/dist/chunks/utils-ByrEVYrJ.js +49584 -0
  63. package/dist/css/formie-base.css +78 -0
  64. package/dist/css/formie-theme.css +19 -0
  65. package/dist/css/formie.css +2 -0
  66. package/dist/css/theme/_buttons.css +249 -0
  67. package/dist/css/theme/_loading.css +37 -0
  68. package/dist/css/theme/_messages.css +39 -0
  69. package/dist/css/theme/_progress.css +62 -0
  70. package/dist/css/theme/_tokens.css +361 -0
  71. package/dist/css/theme/_typography.css +70 -0
  72. package/dist/css/theme/fields/_address.css +17 -0
  73. package/dist/css/theme/fields/_check-radio.css +108 -0
  74. package/dist/css/theme/fields/_file.css +58 -0
  75. package/dist/css/theme/fields/_group.css +13 -0
  76. package/dist/css/theme/fields/_input.css +48 -0
  77. package/dist/css/theme/fields/_nested.css +19 -0
  78. package/dist/css/theme/fields/_repeater.css +69 -0
  79. package/dist/css/theme/fields/_rich-text.css +201 -0
  80. package/dist/css/theme/fields/_select.css +37 -0
  81. package/dist/css/theme/fields/_signature.css +39 -0
  82. package/dist/css/theme/fields/_summary.css +53 -0
  83. package/dist/css/theme/fields/_table.css +121 -0
  84. package/dist/css/theme/fields/_text-limit.css +10 -0
  85. package/dist/css/theme/forms/_field.css +62 -0
  86. package/dist/css/theme/forms/_form.css +166 -0
  87. package/dist/css/theme/integrations/_payment-modal.css +32 -0
  88. package/dist/css/theme/integrations/_paypal.css +10 -0
  89. package/dist/css/theme/integrations/_payway.css +10 -0
  90. package/dist/css/theme/integrations/_stripe.css +24 -0
  91. package/dist/css/theme/utilities/_accessibility.css +13 -0
  92. package/dist/css/theme-base/_controls.css +41 -0
  93. package/dist/css/theme-base/_primitives.css +34 -0
  94. package/dist/index.d.ts +30 -0
  95. package/dist/index.d.ts.map +1 -0
  96. package/dist/index.js +3206 -0
  97. package/dist/js/compatibility/dom-adapter.d.ts +12 -0
  98. package/dist/js/compatibility/dom-adapter.d.ts.map +1 -0
  99. package/dist/js/compatibility/event-map.d.ts +25 -0
  100. package/dist/js/compatibility/event-map.d.ts.map +1 -0
  101. package/dist/js/compatibility/validator-adapter.d.ts +17 -0
  102. package/dist/js/compatibility/validator-adapter.d.ts.map +1 -0
  103. package/dist/js/contracts/client.d.ts +40 -0
  104. package/dist/js/contracts/client.d.ts.map +1 -0
  105. package/dist/js/contracts/common.d.ts +5 -0
  106. package/dist/js/contracts/common.d.ts.map +1 -0
  107. package/dist/js/contracts/modules.d.ts +47 -0
  108. package/dist/js/contracts/modules.d.ts.map +1 -0
  109. package/dist/js/contracts/schema.d.ts +79 -0
  110. package/dist/js/contracts/schema.d.ts.map +1 -0
  111. package/dist/js/contracts/theme.d.ts +2 -0
  112. package/dist/js/contracts/theme.d.ts.map +1 -0
  113. package/dist/js/core/create-formie-client.d.ts +3 -0
  114. package/dist/js/core/create-formie-client.d.ts.map +1 -0
  115. package/dist/js/core/dom-events.d.ts +2 -0
  116. package/dist/js/core/dom-events.d.ts.map +1 -0
  117. package/dist/js/core/formie.d.ts +27 -0
  118. package/dist/js/core/formie.d.ts.map +1 -0
  119. package/dist/js/core/hydrate-modules.d.ts +22 -0
  120. package/dist/js/core/hydrate-modules.d.ts.map +1 -0
  121. package/dist/js/core/page-client-event.d.ts +9 -0
  122. package/dist/js/core/page-client-event.d.ts.map +1 -0
  123. package/dist/js/core/page-tab-errors.d.ts +2 -0
  124. package/dist/js/core/page-tab-errors.d.ts.map +1 -0
  125. package/dist/js/core/submit-flow.d.ts +21 -0
  126. package/dist/js/core/submit-flow.d.ts.map +1 -0
  127. package/dist/js/core/submit-result-state.d.ts +8 -0
  128. package/dist/js/core/submit-result-state.d.ts.map +1 -0
  129. package/dist/js/core/submit-result-ui.d.ts +10 -0
  130. package/dist/js/core/submit-result-ui.d.ts.map +1 -0
  131. package/dist/js/events/event-bus.d.ts +21 -0
  132. package/dist/js/events/event-bus.d.ts.map +1 -0
  133. package/dist/js/modules/address/address-finder.d.ts +2 -0
  134. package/dist/js/modules/address/address-finder.d.ts.map +1 -0
  135. package/dist/js/modules/address/api.d.ts +8 -0
  136. package/dist/js/modules/address/api.d.ts.map +1 -0
  137. package/dist/js/modules/address/constants.d.ts +15 -0
  138. package/dist/js/modules/address/constants.d.ts.map +1 -0
  139. package/dist/js/modules/address/factories.d.ts +35 -0
  140. package/dist/js/modules/address/factories.d.ts.map +1 -0
  141. package/dist/js/modules/address/google-address.d.ts +2 -0
  142. package/dist/js/modules/address/google-address.d.ts.map +1 -0
  143. package/dist/js/modules/address/host.d.ts +30 -0
  144. package/dist/js/modules/address/host.d.ts.map +1 -0
  145. package/dist/js/modules/address/index.d.ts +3 -0
  146. package/dist/js/modules/address/index.d.ts.map +1 -0
  147. package/dist/js/modules/address/loqate.d.ts +2 -0
  148. package/dist/js/modules/address/loqate.d.ts.map +1 -0
  149. package/dist/js/modules/address/place-kit.d.ts +2 -0
  150. package/dist/js/modules/address/place-kit.d.ts.map +1 -0
  151. package/dist/js/modules/captchas/api.d.ts +9 -0
  152. package/dist/js/modules/captchas/api.d.ts.map +1 -0
  153. package/dist/js/modules/captchas/captcha-eu.d.ts +2 -0
  154. package/dist/js/modules/captchas/captcha-eu.d.ts.map +1 -0
  155. package/dist/js/modules/captchas/constants.d.ts +5 -0
  156. package/dist/js/modules/captchas/constants.d.ts.map +1 -0
  157. package/dist/js/modules/captchas/factories.d.ts +63 -0
  158. package/dist/js/modules/captchas/factories.d.ts.map +1 -0
  159. package/dist/js/modules/captchas/friendly-captcha-v1.d.ts +2 -0
  160. package/dist/js/modules/captchas/friendly-captcha-v1.d.ts.map +1 -0
  161. package/dist/js/modules/captchas/friendly-captcha-v2.d.ts +2 -0
  162. package/dist/js/modules/captchas/friendly-captcha-v2.d.ts.map +1 -0
  163. package/dist/js/modules/captchas/hcaptcha.d.ts +2 -0
  164. package/dist/js/modules/captchas/hcaptcha.d.ts.map +1 -0
  165. package/dist/js/modules/captchas/host.d.ts +78 -0
  166. package/dist/js/modules/captchas/host.d.ts.map +1 -0
  167. package/dist/js/modules/captchas/index.d.ts +3 -0
  168. package/dist/js/modules/captchas/index.d.ts.map +1 -0
  169. package/dist/js/modules/captchas/recaptcha-enterprise.d.ts +2 -0
  170. package/dist/js/modules/captchas/recaptcha-enterprise.d.ts.map +1 -0
  171. package/dist/js/modules/captchas/recaptcha-shared.d.ts +26 -0
  172. package/dist/js/modules/captchas/recaptcha-shared.d.ts.map +1 -0
  173. package/dist/js/modules/captchas/recaptcha-v2-checkbox.d.ts +2 -0
  174. package/dist/js/modules/captchas/recaptcha-v2-checkbox.d.ts.map +1 -0
  175. package/dist/js/modules/captchas/recaptcha-v2-invisible.d.ts +2 -0
  176. package/dist/js/modules/captchas/recaptcha-v2-invisible.d.ts.map +1 -0
  177. package/dist/js/modules/captchas/recaptcha-v3.d.ts +2 -0
  178. package/dist/js/modules/captchas/recaptcha-v3.d.ts.map +1 -0
  179. package/dist/js/modules/captchas/snaptcha.d.ts +2 -0
  180. package/dist/js/modules/captchas/snaptcha.d.ts.map +1 -0
  181. package/dist/js/modules/captchas/turnstile.d.ts +2 -0
  182. package/dist/js/modules/captchas/turnstile.d.ts.map +1 -0
  183. package/dist/js/modules/captchas/utils.d.ts +13 -0
  184. package/dist/js/modules/captchas/utils.d.ts.map +1 -0
  185. package/dist/js/modules/fields/calculations.d.ts +3 -0
  186. package/dist/js/modules/fields/calculations.d.ts.map +1 -0
  187. package/dist/js/modules/fields/checkbox-radio.d.ts +3 -0
  188. package/dist/js/modules/fields/checkbox-radio.d.ts.map +1 -0
  189. package/dist/js/modules/fields/conditions/config.d.ts +5 -0
  190. package/dist/js/modules/fields/conditions/config.d.ts.map +1 -0
  191. package/dist/js/modules/fields/conditions/effects.d.ts +2 -0
  192. package/dist/js/modules/fields/conditions/effects.d.ts.map +1 -0
  193. package/dist/js/modules/fields/conditions/evaluator.d.ts +6 -0
  194. package/dist/js/modules/fields/conditions/evaluator.d.ts.map +1 -0
  195. package/dist/js/modules/fields/conditions/references.d.ts +5 -0
  196. package/dist/js/modules/fields/conditions/references.d.ts.map +1 -0
  197. package/dist/js/modules/fields/conditions/transforms.d.ts +3 -0
  198. package/dist/js/modules/fields/conditions/transforms.d.ts.map +1 -0
  199. package/dist/js/modules/fields/conditions/types.d.ts +30 -0
  200. package/dist/js/modules/fields/conditions/types.d.ts.map +1 -0
  201. package/dist/js/modules/fields/conditions/values.d.ts +5 -0
  202. package/dist/js/modules/fields/conditions/values.d.ts.map +1 -0
  203. package/dist/js/modules/fields/conditions.d.ts +3 -0
  204. package/dist/js/modules/fields/conditions.d.ts.map +1 -0
  205. package/dist/js/modules/fields/date-picker.d.ts +3 -0
  206. package/dist/js/modules/fields/date-picker.d.ts.map +1 -0
  207. package/dist/js/modules/fields/file-upload.d.ts +3 -0
  208. package/dist/js/modules/fields/file-upload.d.ts.map +1 -0
  209. package/dist/js/modules/fields/hidden.d.ts +3 -0
  210. package/dist/js/modules/fields/hidden.d.ts.map +1 -0
  211. package/dist/js/modules/fields/index.d.ts +3 -0
  212. package/dist/js/modules/fields/index.d.ts.map +1 -0
  213. package/dist/js/modules/fields/phone-country.d.ts +3 -0
  214. package/dist/js/modules/fields/phone-country.d.ts.map +1 -0
  215. package/dist/js/modules/fields/repeater.d.ts +3 -0
  216. package/dist/js/modules/fields/repeater.d.ts.map +1 -0
  217. package/dist/js/modules/fields/rich-text.d.ts +3 -0
  218. package/dist/js/modules/fields/rich-text.d.ts.map +1 -0
  219. package/dist/js/modules/fields/shared.d.ts +20 -0
  220. package/dist/js/modules/fields/shared.d.ts.map +1 -0
  221. package/dist/js/modules/fields/signature.d.ts +3 -0
  222. package/dist/js/modules/fields/signature.d.ts.map +1 -0
  223. package/dist/js/modules/fields/summary.d.ts +3 -0
  224. package/dist/js/modules/fields/summary.d.ts.map +1 -0
  225. package/dist/js/modules/fields/table.d.ts +3 -0
  226. package/dist/js/modules/fields/table.d.ts.map +1 -0
  227. package/dist/js/modules/fields/text-limit.d.ts +3 -0
  228. package/dist/js/modules/fields/text-limit.d.ts.map +1 -0
  229. package/dist/js/modules/loader.d.ts +11 -0
  230. package/dist/js/modules/loader.d.ts.map +1 -0
  231. package/dist/js/modules/payments/api.d.ts +8 -0
  232. package/dist/js/modules/payments/api.d.ts.map +1 -0
  233. package/dist/js/modules/payments/bpoint.d.ts +2 -0
  234. package/dist/js/modules/payments/bpoint.d.ts.map +1 -0
  235. package/dist/js/modules/payments/constants.d.ts +5 -0
  236. package/dist/js/modules/payments/constants.d.ts.map +1 -0
  237. package/dist/js/modules/payments/eway.d.ts +9 -0
  238. package/dist/js/modules/payments/eway.d.ts.map +1 -0
  239. package/dist/js/modules/payments/factories.d.ts +54 -0
  240. package/dist/js/modules/payments/factories.d.ts.map +1 -0
  241. package/dist/js/modules/payments/go-cardless.d.ts +2 -0
  242. package/dist/js/modules/payments/go-cardless.d.ts.map +1 -0
  243. package/dist/js/modules/payments/host.d.ts +70 -0
  244. package/dist/js/modules/payments/host.d.ts.map +1 -0
  245. package/dist/js/modules/payments/index.d.ts +3 -0
  246. package/dist/js/modules/payments/index.d.ts.map +1 -0
  247. package/dist/js/modules/payments/mollie.d.ts +2 -0
  248. package/dist/js/modules/payments/mollie.d.ts.map +1 -0
  249. package/dist/js/modules/payments/moneris.d.ts +2 -0
  250. package/dist/js/modules/payments/moneris.d.ts.map +1 -0
  251. package/dist/js/modules/payments/opayo.d.ts +25 -0
  252. package/dist/js/modules/payments/opayo.d.ts.map +1 -0
  253. package/dist/js/modules/payments/paddle.d.ts +2 -0
  254. package/dist/js/modules/payments/paddle.d.ts.map +1 -0
  255. package/dist/js/modules/payments/paypal.d.ts +2 -0
  256. package/dist/js/modules/payments/paypal.d.ts.map +1 -0
  257. package/dist/js/modules/payments/payway.d.ts +2 -0
  258. package/dist/js/modules/payments/payway.d.ts.map +1 -0
  259. package/dist/js/modules/payments/square.d.ts +2 -0
  260. package/dist/js/modules/payments/square.d.ts.map +1 -0
  261. package/dist/js/modules/payments/stripe.d.ts +2 -0
  262. package/dist/js/modules/payments/stripe.d.ts.map +1 -0
  263. package/dist/js/modules/payments/utils.d.ts +17 -0
  264. package/dist/js/modules/payments/utils.d.ts.map +1 -0
  265. package/dist/js/modules/registry.d.ts +9 -0
  266. package/dist/js/modules/registry.d.ts.map +1 -0
  267. package/dist/js/modules/styles.d.ts +2 -0
  268. package/dist/js/modules/styles.d.ts.map +1 -0
  269. package/dist/js/submit/pipeline.d.ts +18 -0
  270. package/dist/js/submit/pipeline.d.ts.map +1 -0
  271. package/dist/js/theme/theme-classes.d.ts +10 -0
  272. package/dist/js/theme/theme-classes.d.ts.map +1 -0
  273. package/dist/js/transport/forms-api.d.ts +11 -0
  274. package/dist/js/transport/forms-api.d.ts.map +1 -0
  275. package/dist/js/utils/async.d.ts +8 -0
  276. package/dist/js/utils/async.d.ts.map +1 -0
  277. package/dist/js/utils/debug.d.ts +10 -0
  278. package/dist/js/utils/debug.d.ts.map +1 -0
  279. package/dist/js/utils/event-names.d.ts +13 -0
  280. package/dist/js/utils/event-names.d.ts.map +1 -0
  281. package/dist/js/utils/field-references.d.ts +6 -0
  282. package/dist/js/utils/field-references.d.ts.map +1 -0
  283. package/dist/js/utils/field-references.keys.d.ts +4 -0
  284. package/dist/js/utils/field-references.keys.d.ts.map +1 -0
  285. package/dist/js/utils/field-references.parser.d.ts +3 -0
  286. package/dist/js/utils/field-references.parser.d.ts.map +1 -0
  287. package/dist/js/utils/field-references.registry.d.ts +3 -0
  288. package/dist/js/utils/field-references.registry.d.ts.map +1 -0
  289. package/dist/js/utils/field-references.resolver.d.ts +4 -0
  290. package/dist/js/utils/field-references.resolver.d.ts.map +1 -0
  291. package/dist/js/utils/field-references.types.d.ts +27 -0
  292. package/dist/js/utils/field-references.types.d.ts.map +1 -0
  293. package/dist/js/utils/fields.d.ts +5 -0
  294. package/dist/js/utils/fields.d.ts.map +1 -0
  295. package/dist/js/utils/http.d.ts +9 -0
  296. package/dist/js/utils/http.d.ts.map +1 -0
  297. package/dist/js/utils/i18n.d.ts +7 -0
  298. package/dist/js/utils/i18n.d.ts.map +1 -0
  299. package/dist/js/utils/scripts.d.ts +13 -0
  300. package/dist/js/utils/scripts.d.ts.map +1 -0
  301. package/dist/js/utils/unload-warning.d.ts +10 -0
  302. package/dist/js/utils/unload-warning.d.ts.map +1 -0
  303. package/dist/js/validation/rules/email.d.ts +4 -0
  304. package/dist/js/validation/rules/email.d.ts.map +1 -0
  305. package/dist/js/validation/rules/match.d.ts +4 -0
  306. package/dist/js/validation/rules/match.d.ts.map +1 -0
  307. package/dist/js/validation/rules/number.d.ts +4 -0
  308. package/dist/js/validation/rules/number.d.ts.map +1 -0
  309. package/dist/js/validation/rules/required.d.ts +4 -0
  310. package/dist/js/validation/rules/required.d.ts.map +1 -0
  311. package/dist/js/validation/rules/shared.d.ts +7 -0
  312. package/dist/js/validation/rules/shared.d.ts.map +1 -0
  313. package/dist/js/validation/rules/url.d.ts +4 -0
  314. package/dist/js/validation/rules/url.d.ts.map +1 -0
  315. package/dist/js/validation/rules.d.ts +10 -0
  316. package/dist/js/validation/rules.d.ts.map +1 -0
  317. package/dist/js/validation/types.d.ts +44 -0
  318. package/dist/js/validation/types.d.ts.map +1 -0
  319. package/dist/js/validation/validator.d.ts +53 -0
  320. package/dist/js/validation/validator.d.ts.map +1 -0
  321. package/package.json +78 -0
  322. package/src/css/formie-base.css +78 -0
  323. package/src/css/formie-theme.css +19 -0
  324. package/src/css/formie.css +2 -0
  325. package/src/css/theme/_buttons.css +249 -0
  326. package/src/css/theme/_loading.css +37 -0
  327. package/src/css/theme/_messages.css +39 -0
  328. package/src/css/theme/_progress.css +62 -0
  329. package/src/css/theme/_tokens.css +361 -0
  330. package/src/css/theme/_typography.css +70 -0
  331. package/src/css/theme/fields/_address.css +17 -0
  332. package/src/css/theme/fields/_check-radio.css +108 -0
  333. package/src/css/theme/fields/_file.css +58 -0
  334. package/src/css/theme/fields/_group.css +13 -0
  335. package/src/css/theme/fields/_input.css +48 -0
  336. package/src/css/theme/fields/_nested.css +19 -0
  337. package/src/css/theme/fields/_repeater.css +69 -0
  338. package/src/css/theme/fields/_rich-text.css +201 -0
  339. package/src/css/theme/fields/_select.css +37 -0
  340. package/src/css/theme/fields/_signature.css +39 -0
  341. package/src/css/theme/fields/_summary.css +53 -0
  342. package/src/css/theme/fields/_table.css +121 -0
  343. package/src/css/theme/fields/_text-limit.css +10 -0
  344. package/src/css/theme/forms/_field.css +62 -0
  345. package/src/css/theme/forms/_form.css +166 -0
  346. package/src/css/theme/integrations/_payment-modal.css +32 -0
  347. package/src/css/theme/integrations/_paypal.css +10 -0
  348. package/src/css/theme/integrations/_payway.css +10 -0
  349. package/src/css/theme/integrations/_stripe.css +24 -0
  350. package/src/css/theme/utilities/_accessibility.css +13 -0
  351. package/src/css/theme-base/_controls.css +41 -0
  352. package/src/css/theme-base/_primitives.css +34 -0
  353. package/src/icons/rich-text/aligncenter.svg +6 -0
  354. package/src/icons/rich-text/alignleft.svg +6 -0
  355. package/src/icons/rich-text/alignright.svg +6 -0
  356. package/src/icons/rich-text/bold.svg +4 -0
  357. package/src/icons/rich-text/clear.svg +6 -0
  358. package/src/icons/rich-text/code.svg +4 -0
  359. package/src/icons/rich-text/heading1.svg +3 -0
  360. package/src/icons/rich-text/heading2.svg +3 -0
  361. package/src/icons/rich-text/image.svg +6 -0
  362. package/src/icons/rich-text/italic.svg +5 -0
  363. package/src/icons/rich-text/line.svg +3 -0
  364. package/src/icons/rich-text/link.svg +4 -0
  365. package/src/icons/rich-text/olist.svg +8 -0
  366. package/src/icons/rich-text/paragraph.svg +3 -0
  367. package/src/icons/rich-text/quote.svg +4 -0
  368. package/src/icons/rich-text/strikethrough.svg +4 -0
  369. package/src/icons/rich-text/ulist.svg +8 -0
  370. package/src/icons/rich-text/underline.svg +4 -0
  371. package/src/index.ts +125 -0
  372. package/src/js/compatibility/dom-adapter.ts +129 -0
  373. package/src/js/compatibility/event-map.ts +72 -0
  374. package/src/js/compatibility/validator-adapter.ts +105 -0
  375. package/src/js/contracts/client.ts +43 -0
  376. package/src/js/contracts/common.ts +14 -0
  377. package/src/js/contracts/modules.ts +53 -0
  378. package/src/js/contracts/schema.ts +83 -0
  379. package/src/js/contracts/theme.ts +1 -0
  380. package/src/js/core/create-formie-client.ts +1519 -0
  381. package/src/js/core/dom-events.ts +8 -0
  382. package/src/js/core/formie.ts +242 -0
  383. package/src/js/core/hydrate-modules.ts +102 -0
  384. package/src/js/core/page-client-event.ts +129 -0
  385. package/src/js/core/page-tab-errors.ts +37 -0
  386. package/src/js/core/submit-flow.ts +120 -0
  387. package/src/js/core/submit-result-state.ts +597 -0
  388. package/src/js/core/submit-result-ui.ts +448 -0
  389. package/src/js/events/event-bus.ts +109 -0
  390. package/src/js/modules/address/address-finder.ts +85 -0
  391. package/src/js/modules/address/api.ts +22 -0
  392. package/src/js/modules/address/constants.ts +15 -0
  393. package/src/js/modules/address/factories.ts +203 -0
  394. package/src/js/modules/address/google-address.ts +345 -0
  395. package/src/js/modules/address/host.ts +137 -0
  396. package/src/js/modules/address/index.ts +10 -0
  397. package/src/js/modules/address/loqate.ts +128 -0
  398. package/src/js/modules/address/place-kit.ts +94 -0
  399. package/src/js/modules/captchas/api.ts +25 -0
  400. package/src/js/modules/captchas/captcha-eu.ts +86 -0
  401. package/src/js/modules/captchas/constants.ts +4 -0
  402. package/src/js/modules/captchas/factories.ts +485 -0
  403. package/src/js/modules/captchas/friendly-captcha-v1.ts +65 -0
  404. package/src/js/modules/captchas/friendly-captcha-v2.ts +84 -0
  405. package/src/js/modules/captchas/hcaptcha.ts +153 -0
  406. package/src/js/modules/captchas/host.ts +448 -0
  407. package/src/js/modules/captchas/index.ts +16 -0
  408. package/src/js/modules/captchas/recaptcha-enterprise.ts +138 -0
  409. package/src/js/modules/captchas/recaptcha-shared.ts +69 -0
  410. package/src/js/modules/captchas/recaptcha-v2-checkbox.ts +72 -0
  411. package/src/js/modules/captchas/recaptcha-v2-invisible.ts +108 -0
  412. package/src/js/modules/captchas/recaptcha-v3.ts +62 -0
  413. package/src/js/modules/captchas/snaptcha.ts +10 -0
  414. package/src/js/modules/captchas/turnstile.ts +131 -0
  415. package/src/js/modules/captchas/utils.ts +85 -0
  416. package/src/js/modules/fields/calculations.ts +273 -0
  417. package/src/js/modules/fields/checkbox-radio.ts +295 -0
  418. package/src/js/modules/fields/conditions/config.ts +79 -0
  419. package/src/js/modules/fields/conditions/effects.ts +166 -0
  420. package/src/js/modules/fields/conditions/evaluator.ts +44 -0
  421. package/src/js/modules/fields/conditions/references.ts +165 -0
  422. package/src/js/modules/fields/conditions/transforms.ts +206 -0
  423. package/src/js/modules/fields/conditions/types.ts +33 -0
  424. package/src/js/modules/fields/conditions/values.ts +115 -0
  425. package/src/js/modules/fields/conditions.ts +229 -0
  426. package/src/js/modules/fields/date-picker.ts +272 -0
  427. package/src/js/modules/fields/file-upload.ts +628 -0
  428. package/src/js/modules/fields/hidden.ts +58 -0
  429. package/src/js/modules/fields/index.ts +19 -0
  430. package/src/js/modules/fields/phone-country.ts +226 -0
  431. package/src/js/modules/fields/repeater.ts +231 -0
  432. package/src/js/modules/fields/rich-text.ts +217 -0
  433. package/src/js/modules/fields/shared.ts +238 -0
  434. package/src/js/modules/fields/signature.ts +202 -0
  435. package/src/js/modules/fields/summary.ts +272 -0
  436. package/src/js/modules/fields/table.ts +197 -0
  437. package/src/js/modules/fields/text-limit.ts +280 -0
  438. package/src/js/modules/loader.ts +331 -0
  439. package/src/js/modules/payments/api.ts +20 -0
  440. package/src/js/modules/payments/bpoint.ts +48 -0
  441. package/src/js/modules/payments/constants.ts +17 -0
  442. package/src/js/modules/payments/eway.ts +132 -0
  443. package/src/js/modules/payments/factories.ts +332 -0
  444. package/src/js/modules/payments/go-cardless.ts +37 -0
  445. package/src/js/modules/payments/host.ts +459 -0
  446. package/src/js/modules/payments/index.ts +17 -0
  447. package/src/js/modules/payments/mollie.ts +38 -0
  448. package/src/js/modules/payments/moneris.ts +216 -0
  449. package/src/js/modules/payments/opayo.ts +272 -0
  450. package/src/js/modules/payments/paddle.ts +111 -0
  451. package/src/js/modules/payments/payment.ts +183 -0
  452. package/src/js/modules/payments/paypal.ts +214 -0
  453. package/src/js/modules/payments/payway.ts +114 -0
  454. package/src/js/modules/payments/square.ts +106 -0
  455. package/src/js/modules/payments/stripe.ts +426 -0
  456. package/src/js/modules/payments/stub-payment-module.ts +87 -0
  457. package/src/js/modules/payments/utils.ts +60 -0
  458. package/src/js/modules/registry.ts +38 -0
  459. package/src/js/modules/styles.ts +29 -0
  460. package/src/js/submit/pipeline.ts +514 -0
  461. package/src/js/theme/theme-classes.ts +106 -0
  462. package/src/js/transport/forms-api.ts +345 -0
  463. package/src/js/utils/async.ts +81 -0
  464. package/src/js/utils/debug.ts +59 -0
  465. package/src/js/utils/event-names.ts +60 -0
  466. package/src/js/utils/field-references.keys.ts +47 -0
  467. package/src/js/utils/field-references.parser.ts +121 -0
  468. package/src/js/utils/field-references.registry.ts +50 -0
  469. package/src/js/utils/field-references.resolver.ts +115 -0
  470. package/src/js/utils/field-references.ts +11 -0
  471. package/src/js/utils/field-references.types.ts +31 -0
  472. package/src/js/utils/fields.ts +58 -0
  473. package/src/js/utils/http.ts +51 -0
  474. package/src/js/utils/i18n.ts +98 -0
  475. package/src/js/utils/scripts.ts +84 -0
  476. package/src/js/utils/unload-warning.ts +190 -0
  477. package/src/js/validation/rules/email.ts +18 -0
  478. package/src/js/validation/rules/match.ts +26 -0
  479. package/src/js/validation/rules/minmax.ts +47 -0
  480. package/src/js/validation/rules/number.ts +55 -0
  481. package/src/js/validation/rules/pattern.ts +29 -0
  482. package/src/js/validation/rules/required.ts +30 -0
  483. package/src/js/validation/rules/shared.ts +47 -0
  484. package/src/js/validation/rules/url.ts +23 -0
  485. package/src/js/validation/rules.ts +16 -0
  486. package/src/js/validation/types.ts +50 -0
  487. package/src/js/validation/validator.ts +643 -0
  488. package/src/vendor.d.ts +100 -0
  489. package/src/vite-env.d.ts +22 -0
  490. package/vite-dev.mjs +22 -0
@@ -0,0 +1,514 @@
1
+ import type { FormAction, SubmitStage } from '#contracts/common';
2
+ import type { FormSubmitResult } from '#contracts/schema';
3
+ import { EventBus } from '#events/event-bus';
4
+ import { submitForm } from '#transport/forms-api';
5
+ import { createDebug } from '#utils/debug';
6
+ import type { FormieValidator } from '#validation/validator';
7
+
8
+ export type SubmitPipelineContext = {
9
+ form: HTMLFormElement;
10
+ action: FormAction;
11
+ formData: FormData;
12
+ abort: (reason?: string) => void;
13
+ isAborted: () => boolean;
14
+ abortReason: () => string | undefined;
15
+ };
16
+
17
+ type StageRunner = (ctx: SubmitPipelineContext) => Promise<FormSubmitResult | null>;
18
+
19
+ const STAGES: SubmitStage[] = ['prepare', 'normalize', 'validate', 'screen', 'authorize', 'dispatch', 'finalize'];
20
+ const PREFLIGHT_STAGES: SubmitStage[] = ['prepare', 'normalize', 'validate', 'screen', 'authorize'];
21
+ const debug = createDebug('general', 'pipeline');
22
+
23
+ function getAbortedResult(stage: SubmitStage, reason?: string): FormSubmitResult {
24
+ return {
25
+ ok: false,
26
+ stage,
27
+ code: 'ABORTED',
28
+ message: reason || 'Submission aborted.',
29
+ formErrors: [reason || 'Submission aborted.'],
30
+ };
31
+ }
32
+
33
+ function getPages(form: HTMLFormElement): HTMLElement[] {
34
+ return Array.from(form.querySelectorAll('[data-formie-page]')) as HTMLElement[];
35
+ }
36
+
37
+ function getValidationScope(form: HTMLFormElement): { scope: Element; final: boolean } {
38
+ const pages = getPages(form);
39
+
40
+ if (!pages.length) {
41
+ return {
42
+ scope: form,
43
+ final: true,
44
+ };
45
+ }
46
+
47
+ // Multi-page submits validate the visible page until the user reaches the
48
+ // final step, where hidden earlier pages are included again.
49
+ const currentPage = pages.find((page) => {
50
+ return !page.hasAttribute('data-formie-page-hidden');
51
+ }) || pages[pages.length - 1];
52
+
53
+ return {
54
+ scope: currentPage,
55
+ final: currentPage === pages[pages.length - 1],
56
+ };
57
+ }
58
+
59
+ function isSubmittableControl(element: Element): element is HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement {
60
+ return element instanceof HTMLInputElement
61
+ || element instanceof HTMLSelectElement
62
+ || element instanceof HTMLTextAreaElement;
63
+ }
64
+
65
+ function shouldIncludeControl(control: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement): boolean {
66
+ if (!control.name || control.disabled) {
67
+ return false;
68
+ }
69
+
70
+ if (control instanceof HTMLInputElement) {
71
+ if (control.type === 'submit' || control.type === 'button' || control.type === 'reset' || control.type === 'image') {
72
+ return false;
73
+ }
74
+
75
+ if ((control.type === 'checkbox' || control.type === 'radio') && !control.checked) {
76
+ return false;
77
+ }
78
+
79
+ if (control.type === 'file' && (!control.files || control.files.length === 0)) {
80
+ return false;
81
+ }
82
+ }
83
+
84
+ return true;
85
+ }
86
+
87
+ function appendControlValue(
88
+ formData: FormData,
89
+ control: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement,
90
+ ): void {
91
+ if (control instanceof HTMLInputElement) {
92
+ if (control.type === 'file') {
93
+ Array.from(control.files || []).forEach((file) => {
94
+ formData.append(control.name, file);
95
+ });
96
+
97
+ return;
98
+ }
99
+
100
+ formData.append(control.name, control.value);
101
+ return;
102
+ }
103
+
104
+ if (control instanceof HTMLSelectElement && control.multiple) {
105
+ Array.from(control.selectedOptions).forEach((option) => {
106
+ formData.append(control.name, option.value);
107
+ });
108
+
109
+ return;
110
+ }
111
+
112
+ formData.append(control.name, control.value);
113
+ }
114
+
115
+ function appendControlsFromRoot(formData: FormData, form: HTMLFormElement): void {
116
+ form.querySelectorAll('input, select, textarea').forEach((node) => {
117
+ const control = isSubmittableControl(node) ? node : null;
118
+
119
+ // Form-level transport inputs live outside page wrappers and must always
120
+ // ride along, even when the visible page payload is partial.
121
+ if (!control || control.closest('[data-formie-page]')) {
122
+ return;
123
+ }
124
+
125
+ if (!shouldIncludeControl(control)) {
126
+ return;
127
+ }
128
+
129
+ appendControlValue(formData, control);
130
+ });
131
+ }
132
+
133
+ function appendControlsFromPage(formData: FormData, page: HTMLElement): Set<string> {
134
+ const fieldNames = new Set<string>();
135
+
136
+ page.querySelectorAll('input, select, textarea').forEach((node) => {
137
+ const control = isSubmittableControl(node) ? node : null;
138
+
139
+ if (!control || !control.name || control.disabled) {
140
+ return;
141
+ }
142
+
143
+ if (
144
+ control instanceof HTMLInputElement
145
+ && (control.type === 'submit' || control.type === 'button' || control.type === 'reset' || control.type === 'image')
146
+ ) {
147
+ return;
148
+ }
149
+
150
+ if (control.name.startsWith('fields[')) {
151
+ fieldNames.add(control.name);
152
+ }
153
+
154
+ if (!shouldIncludeControl(control)) {
155
+ return;
156
+ }
157
+
158
+ appendControlValue(formData, control);
159
+ });
160
+
161
+ return fieldNames;
162
+ }
163
+
164
+ function appendMissingFieldClears(formData: FormData, fieldNames: Set<string>): void {
165
+ fieldNames.forEach((name) => {
166
+ // Unchecked checkbox/radio groups disappear from FormData by default.
167
+ // Appending an empty value lets the backend treat them as an intentional clear.
168
+ if (!formData.has(name)) {
169
+ formData.append(name, '');
170
+ }
171
+ });
172
+ }
173
+
174
+ function buildSubmitFormData(form: HTMLFormElement, action: FormAction): FormData {
175
+ const pages = getPages(form);
176
+ const currentPage = pages.find((page) => {
177
+ return !page.hasAttribute('data-formie-page-hidden');
178
+ }) || null;
179
+
180
+ if (!pages.length || !currentPage) {
181
+ const formData = new FormData(form);
182
+ formData.set('submitAction', action);
183
+
184
+ return formData;
185
+ }
186
+
187
+ // Multi-page AJAX submits only send the current page plus root transport
188
+ // inputs so page transitions behave like the server-rendered workflow.
189
+ const formData = new FormData();
190
+ appendControlsFromRoot(formData, form);
191
+ const fieldNames = appendControlsFromPage(formData, currentPage);
192
+ appendMissingFieldClears(formData, fieldNames);
193
+ formData.set('submitAction', action);
194
+
195
+ return formData;
196
+ }
197
+
198
+ function isFinalSubmitAttempt(form: HTMLFormElement, action: FormAction): boolean {
199
+ if (action !== 'submit') {
200
+ return false;
201
+ }
202
+
203
+ const pages = getPages(form);
204
+
205
+ if (!pages.length) {
206
+ return true;
207
+ }
208
+
209
+ const currentPage = pages.find((page) => {
210
+ return !page.hasAttribute('data-formie-page-hidden');
211
+ }) || pages[pages.length - 1];
212
+
213
+ return currentPage === pages[pages.length - 1];
214
+ }
215
+
216
+ export async function runSubmitPipeline(
217
+ form: HTMLFormElement,
218
+ action: FormAction,
219
+ bus: EventBus,
220
+ options: {
221
+ validator?: FormieValidator | null;
222
+ validateOnSubmit?: boolean;
223
+ preflightOnly?: boolean;
224
+ } = {},
225
+ ): Promise<FormSubmitResult> {
226
+ debug.log('Starting submit pipeline.', {
227
+ action,
228
+ preflightOnly: options.preflightOnly === true,
229
+ });
230
+ let aborted = false;
231
+ let abortReason: string | undefined;
232
+ let dispatchResult: FormSubmitResult | null = null;
233
+ const finalSubmitAttempt = isFinalSubmitAttempt(form, action);
234
+
235
+ const context: SubmitPipelineContext = {
236
+ form,
237
+ action,
238
+ formData: buildSubmitFormData(form, action),
239
+ abort: (reason?: string) => {
240
+ aborted = true;
241
+ abortReason = reason;
242
+ debug.warn('Pipeline aborted.', { reason });
243
+ },
244
+ isAborted: () => aborted,
245
+ abortReason: () => abortReason,
246
+ };
247
+
248
+ const runners: Record<SubmitStage, StageRunner> = {
249
+ prepare: async(ctx) => {
250
+ const submitAction = ctx.form.querySelector('input[name="submitAction"]') as HTMLInputElement | null;
251
+
252
+ if (submitAction) {
253
+ submitAction.value = ctx.action;
254
+ }
255
+
256
+ ctx.formData.set('submitAction', ctx.action);
257
+ return null;
258
+ },
259
+ normalize: async() => {
260
+ return null;
261
+ },
262
+ validate: async(ctx) => {
263
+ if (ctx.action !== 'submit') {
264
+ // Back/save actions bypass final validation so they can persist
265
+ // navigation intent without forcing the whole form valid.
266
+ return null;
267
+ }
268
+
269
+ if (options.validateOnSubmit === false) {
270
+ return null;
271
+ }
272
+
273
+ if (options.validator) {
274
+ const { scope, final } = getValidationScope(ctx.form);
275
+ const errors = options.validator.submit(final ? ctx.form : scope, { final });
276
+
277
+ if (errors.length > 0) {
278
+ errors[0]?.input.focus();
279
+
280
+ return {
281
+ ok: false,
282
+ stage: 'validate',
283
+ code: 'VALIDATION_FAILED',
284
+ message: options.validator.config.errorMessage || 'Validation failed.',
285
+ fieldErrors: options.validator.getFieldErrors(errors),
286
+ formErrors: [options.validator.config.errorMessage || 'Validation failed.'],
287
+ };
288
+ }
289
+
290
+ return null;
291
+ }
292
+
293
+ if (!ctx.form.checkValidity()) {
294
+ const invalidField = ctx.form.querySelector(':invalid') as HTMLElement | null;
295
+ invalidField?.focus();
296
+
297
+ return {
298
+ ok: false,
299
+ stage: 'validate',
300
+ code: 'VALIDATION_FAILED',
301
+ message: 'Validation failed.',
302
+ formErrors: ['Validation failed.'],
303
+ };
304
+ }
305
+
306
+ return null;
307
+ },
308
+ screen: async() => {
309
+ return null;
310
+ },
311
+ authorize: async() => {
312
+ return null;
313
+ },
314
+ dispatch: async(ctx) => {
315
+ // Rehydrate just-in-time so provider hooks can mutate hidden inputs
316
+ // during `screen` / `authorize` and still be submitted.
317
+ ctx.formData = buildSubmitFormData(ctx.form, ctx.action);
318
+ const result = await submitForm(ctx.form, ctx.formData);
319
+ dispatchResult = result;
320
+ // Always return dispatch result so stage after-hooks can react to both
321
+ // success and failure outcomes (e.g. provider token/element resets).
322
+ return result;
323
+ },
324
+ finalize: async(resultCtx) => {
325
+ if (!dispatchResult) {
326
+ return null;
327
+ }
328
+
329
+ // Redirects happen after the dispatch response is normalized so the
330
+ // rest of the browser client can react to one result shape first.
331
+ if (dispatchResult.ok && dispatchResult.redirect?.url) {
332
+ if (dispatchResult.redirect.target === 'new-tab') {
333
+ window.open(dispatchResult.redirect.url, '_blank');
334
+ } else {
335
+ window.location.href = dispatchResult.redirect.url;
336
+ }
337
+ }
338
+
339
+ return null;
340
+ },
341
+ };
342
+
343
+ {
344
+ const emitReport = await bus.emitSafe('formie:submit:before', context);
345
+ if (emitReport.failed.length > 0) {
346
+ debug.warn('Submit before listeners failed.', {
347
+ eventName: emitReport.eventName,
348
+ failed: emitReport.failed.length,
349
+ });
350
+ }
351
+ }
352
+
353
+ if (finalSubmitAttempt) {
354
+ const emitReport = await bus.emitSafe('formie:submit:final:before', context);
355
+ if (emitReport.failed.length > 0) {
356
+ debug.warn('Final submit before listeners failed.', {
357
+ eventName: emitReport.eventName,
358
+ failed: emitReport.failed.length,
359
+ });
360
+ }
361
+ }
362
+
363
+ const stages = options.preflightOnly ? PREFLIGHT_STAGES : STAGES;
364
+
365
+ for (const stage of stages) {
366
+ debug.log('Stage start.', { stage, action });
367
+ if (aborted) {
368
+ debug.warn('Stage skipped due to abort.', { stage, reason: abortReason });
369
+ return getAbortedResult(stage, abortReason);
370
+ }
371
+
372
+ {
373
+ const emitReport = await bus.emitSafe(`formie:stage:${stage}:before`, {
374
+ ...context,
375
+ stage,
376
+ });
377
+ if (emitReport.failed.length > 0) {
378
+ debug.warn('Stage before listeners failed.', {
379
+ stage,
380
+ failed: emitReport.failed.length,
381
+ });
382
+ }
383
+ }
384
+
385
+ if (aborted) {
386
+ const abortedResult = getAbortedResult(stage, abortReason);
387
+ {
388
+ const emitReport = await bus.emitSafe('formie:submit:after', abortedResult);
389
+ if (emitReport.failed.length > 0) {
390
+ debug.warn('Submit after listeners failed (abort before stage).', {
391
+ stage,
392
+ failed: emitReport.failed.length,
393
+ });
394
+ }
395
+ }
396
+ if (finalSubmitAttempt) {
397
+ const emitReport = await bus.emitSafe('formie:submit:final:after', abortedResult);
398
+ if (emitReport.failed.length > 0) {
399
+ debug.warn('Final submit after listeners failed (abort before stage).', {
400
+ stage,
401
+ failed: emitReport.failed.length,
402
+ });
403
+ }
404
+ }
405
+ debug.warn('Aborted after stage before-hooks.', { stage, reason: abortReason });
406
+ return abortedResult;
407
+ }
408
+
409
+ const stageResult = await runners[stage](context);
410
+ debug.log('Stage runner complete.', {
411
+ stage,
412
+ hasResult: !!stageResult,
413
+ ok: stageResult ? stageResult.ok : undefined,
414
+ code: stageResult?.code,
415
+ });
416
+
417
+ {
418
+ const emitReport = await bus.emitSafe(`formie:stage:${stage}:after`, {
419
+ ...context,
420
+ stage,
421
+ result: stageResult,
422
+ });
423
+ if (emitReport.failed.length > 0) {
424
+ debug.warn('Stage after listeners failed.', {
425
+ stage,
426
+ failed: emitReport.failed.length,
427
+ });
428
+ }
429
+ }
430
+
431
+ if (aborted) {
432
+ const abortedResult = getAbortedResult(stage, abortReason);
433
+ {
434
+ const emitReport = await bus.emitSafe('formie:submit:after', abortedResult);
435
+ if (emitReport.failed.length > 0) {
436
+ debug.warn('Submit after listeners failed (abort after stage).', {
437
+ stage,
438
+ failed: emitReport.failed.length,
439
+ });
440
+ }
441
+ }
442
+ if (finalSubmitAttempt) {
443
+ const emitReport = await bus.emitSafe('formie:submit:final:after', abortedResult);
444
+ if (emitReport.failed.length > 0) {
445
+ debug.warn('Final submit after listeners failed (abort after stage).', {
446
+ stage,
447
+ failed: emitReport.failed.length,
448
+ });
449
+ }
450
+ }
451
+ debug.warn('Aborted after stage after-hooks.', { stage, reason: abortReason });
452
+ return abortedResult;
453
+ }
454
+
455
+ // The first failing stage short-circuits the pipeline but still emits the
456
+ // matching stage after-hook so modules can clean up their own state.
457
+ if (stageResult && !stageResult.ok) {
458
+ {
459
+ const emitReport = await bus.emitSafe('formie:submit:after', stageResult);
460
+ if (emitReport.failed.length > 0) {
461
+ debug.warn('Submit after listeners failed (failed stage).', {
462
+ stage,
463
+ failed: emitReport.failed.length,
464
+ });
465
+ }
466
+ }
467
+ if (finalSubmitAttempt) {
468
+ const emitReport = await bus.emitSafe('formie:submit:final:after', stageResult);
469
+ if (emitReport.failed.length > 0) {
470
+ debug.warn('Final submit after listeners failed (failed stage).', {
471
+ stage,
472
+ failed: emitReport.failed.length,
473
+ });
474
+ }
475
+ }
476
+ debug.warn('Pipeline short-circuited by failed stage.', {
477
+ stage,
478
+ code: stageResult.code,
479
+ message: stageResult.message,
480
+ });
481
+ return stageResult;
482
+ }
483
+ }
484
+
485
+ const successResult: FormSubmitResult = dispatchResult || {
486
+ ok: true,
487
+ stage: options.preflightOnly ? 'authorize' : 'finalize',
488
+ message: options.preflightOnly ? 'Submission preflight completed.' : 'Submission completed.',
489
+ };
490
+
491
+ {
492
+ const emitReport = await bus.emitSafe('formie:submit:after', successResult);
493
+ if (emitReport.failed.length > 0) {
494
+ debug.warn('Submit after listeners failed (success).', {
495
+ failed: emitReport.failed.length,
496
+ });
497
+ }
498
+ }
499
+ if (finalSubmitAttempt) {
500
+ const emitReport = await bus.emitSafe('formie:submit:final:after', successResult);
501
+ if (emitReport.failed.length > 0) {
502
+ debug.warn('Final submit after listeners failed (success).', {
503
+ failed: emitReport.failed.length,
504
+ });
505
+ }
506
+ }
507
+ debug.log('Pipeline completed.', {
508
+ ok: successResult.ok,
509
+ stage: successResult.stage,
510
+ code: successResult.code,
511
+ });
512
+
513
+ return successResult;
514
+ }
@@ -0,0 +1,106 @@
1
+ import type { ThemeClassMap } from '#contracts/theme';
2
+
3
+ type NormalizedThemeClassMap = Record<string, string[]>;
4
+
5
+ const themeRegistry = new WeakMap<Element, NormalizedThemeClassMap>();
6
+ const THEME_ROOT_SELECTORS = '[data-formie-form], [data-formie], form';
7
+
8
+ function splitClasses(value: string[] | string | null | undefined): string[] {
9
+ if (!value) {
10
+ return [];
11
+ }
12
+
13
+ const parts = Array.isArray(value) ? value : [value];
14
+
15
+ return parts
16
+ .flatMap((item) => {
17
+ return String(item).split(/\s+/);
18
+ })
19
+ .map((item) => {
20
+ return item.trim();
21
+ })
22
+ .filter(Boolean);
23
+ }
24
+
25
+ function uniqueClasses(classes: string[]): string[] {
26
+ return Array.from(new Set(classes));
27
+ }
28
+
29
+ function resolveThemeClassMap(source: Element | null): NormalizedThemeClassMap {
30
+ if (!source) {
31
+ return {};
32
+ }
33
+
34
+ const directMatch = themeRegistry.get(source);
35
+ if (directMatch) {
36
+ return directMatch;
37
+ }
38
+
39
+ // Most browser helpers only know the current field/page node, so theme lookup
40
+ // walks back to the registered form root and reuses its flat class map.
41
+ const root = source.closest(THEME_ROOT_SELECTORS);
42
+ if (!root) {
43
+ return {};
44
+ }
45
+
46
+ return themeRegistry.get(root) || {};
47
+ }
48
+
49
+ export function normalizeThemeClassMap(theme?: ThemeClassMap | null): NormalizedThemeClassMap {
50
+ const normalized: NormalizedThemeClassMap = {};
51
+
52
+ Object.entries(theme || {}).forEach(([key, value]) => {
53
+ const classes = uniqueClasses(splitClasses(value));
54
+
55
+ if (classes.length) {
56
+ normalized[key] = classes;
57
+ }
58
+ });
59
+
60
+ return normalized;
61
+ }
62
+
63
+ export function registerThemeClassMap(target: Element, theme?: ThemeClassMap | null, form?: HTMLFormElement | null): NormalizedThemeClassMap {
64
+ const normalized = normalizeThemeClassMap(theme);
65
+ const resolvedForm = form || (target instanceof HTMLFormElement ? target : target.querySelector('form'));
66
+
67
+ // Store the same normalized map against both the mount target and the actual
68
+ // form element so browser helpers can resolve classes from either surface.
69
+ themeRegistry.set(target, normalized);
70
+
71
+ if (resolvedForm) {
72
+ themeRegistry.set(resolvedForm, normalized);
73
+ }
74
+
75
+ return normalized;
76
+ }
77
+
78
+ export function getThemeClasses(source: Element | null, key: string): string[] {
79
+ return resolveThemeClassMap(source)[key] || [];
80
+ }
81
+
82
+ export function addThemeClasses(target: Element, source: Element | null, ...keys: string[]): void {
83
+ const classes = uniqueClasses(keys.flatMap((key) => {
84
+ return getThemeClasses(source, key);
85
+ }));
86
+
87
+ if (classes.length) {
88
+ target.classList.add(...classes);
89
+ }
90
+ }
91
+
92
+ export function removeThemeClasses(target: Element, source: Element | null, ...keys: string[]): void {
93
+ const classes = uniqueClasses(keys.flatMap((key) => {
94
+ return getThemeClasses(source, key);
95
+ }));
96
+
97
+ if (classes.length) {
98
+ target.classList.remove(...classes);
99
+ }
100
+ }
101
+
102
+ export function toggleThemeClasses(target: Element, source: Element | null, key: string, enabled: boolean): void {
103
+ getThemeClasses(source, key).forEach((className) => {
104
+ target.classList.toggle(className, enabled);
105
+ });
106
+ }