@verbb/formie-browser 1.0.12 → 1.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +57 -0
- package/dist/chunks/{address-country-Rx6GQTND.js → address-country-Dn71jroa.js} +10 -4
- package/dist/chunks/{address-finder-k7_BXaRe.js → address-finder-O49uDRoR.js} +2 -2
- package/dist/chunks/{address-state-BwE01m2_.js → address-state-ByYatUur.js} +154 -143
- package/dist/chunks/{api-DqpfkZWL.js → api-D6kJ7kXZ.js} +183 -179
- package/dist/chunks/{api-BUb6P-xu.js → api-DYYsVIub.js} +77 -47
- package/dist/chunks/{api-sPqGbOww.js → api-ghNr2uxX.js} +15 -9
- package/dist/chunks/{bpoint-Dlq34XH1.js → bpoint-D0RKFM4F.js} +3 -3
- package/dist/chunks/calculations-YEoVCG2q.js +310 -0
- package/dist/chunks/{captcha-eu-CGm8Lbrj.js → captcha-eu-DERJbXnH.js} +5 -4
- package/dist/chunks/{checkbox-radio-BY2aTCOG.js → checkbox-radio-gsm8QPJg.js} +74 -75
- package/dist/chunks/{combobox-C0EuExSI.js → combobox-CWNdx4Fk.js} +290 -279
- package/dist/chunks/conditions-DqNHLTbN.js +464 -0
- package/dist/chunks/country-from-ip-DDj_mFki.js +29 -0
- package/dist/chunks/csrf-DxHg_ZYt.js +61 -0
- package/dist/chunks/{custom-google-maps-BsaSirEZ.js → custom-google-maps-C4l2S3GO.js} +9 -3
- package/dist/chunks/{custom-link-CJ1-FjEM.js → custom-link-CLazgKYH.js} +8 -2
- package/dist/chunks/{custom-maps-DYW_pBid.js → custom-maps-DqcAlD0v.js} +10 -4
- package/dist/chunks/{date-picker-5CA_-zGb.js → date-picker-RUnevF7l.js} +456 -430
- package/dist/chunks/{dist-BdUy8m_p.js → dist-ZLeW0zZ3.js} +1280 -452
- package/dist/chunks/{eway-D9_m8ooj.js → eway-or6dtjoT.js} +3 -3
- package/dist/chunks/field-references.resolver-Ca8MguFv.js +104 -0
- package/dist/chunks/{file-upload-rqfZNqlH.js → file-upload-Bm-TXyNB.js} +104 -96
- package/dist/chunks/friendly-captcha-v1-GFqCt1Mh.js +34 -0
- package/dist/chunks/{friendly-captcha-v2-CLSAbkqx.js → friendly-captcha-v2-WoW246JG.js} +6 -5
- package/dist/chunks/{friendly-challenge-8uPatWqk.js → friendly-challenge-DPG9MJb1.js} +111 -102
- package/dist/chunks/{go-cardless-DAT3ZaQf.js → go-cardless-DzJ-0FKg.js} +2 -2
- package/dist/chunks/google-address-C1P1nTDM.js +163 -0
- package/dist/chunks/{hcaptcha-CGLAmgjO.js → hcaptcha-D0T8aIHz.js} +3 -3
- package/dist/chunks/{hidden-D7_Ch-QN.js → hidden-BZhXnNPe.js} +8 -2
- package/dist/chunks/http-C2QdHuWO.js +27 -0
- package/dist/chunks/{leaflet-src-j-lHNmhR.js → leaflet-src-DE6rv6M-.js} +42 -46
- package/dist/chunks/{loqate-CJPzBmSm.js → loqate-DD1S7PY9.js} +2 -2
- package/dist/chunks/{mollie-Bibhl67p.js → mollie-DG8Ju83x.js} +2 -2
- package/dist/chunks/{moneris-H2wSqk9h.js → moneris-C8m3Fvqu.js} +3 -3
- package/dist/chunks/opayo-B3EvrVxw.js +188 -0
- package/dist/chunks/{paddle-DkvIxQdG.js → paddle-BIYR9Um3.js} +3 -3
- package/dist/chunks/{password-validation-T0vDQPCr.js → password-validation-C8_uO_c_.js} +18 -12
- package/dist/chunks/{paypal-CQpAF7Ua.js → paypal-B_yxIo2d.js} +7 -5
- package/dist/chunks/{payway-CwDkC7YZ.js → payway-CeOzS0sL.js} +3 -3
- package/dist/chunks/{phone-country-D3ayr60L.js → phone-country-bAqje17P.js} +80 -63
- package/dist/chunks/{place-kit-BGHklIZ-.js → place-kit-BE5gi3vo.js} +3 -3
- package/dist/chunks/{placekit-autocomplete.esm-DWVabQlq.js → placekit-autocomplete.esm-CZZERYur.js} +11 -15
- package/dist/chunks/{recaptcha-enterprise-XPId5-bS.js → recaptcha-enterprise-CruXddZq.js} +4 -4
- package/dist/chunks/{recaptcha-shared-CLYJvojk.js → recaptcha-shared-AQRMDMme.js} +1 -1
- package/dist/chunks/{recaptcha-v2-checkbox-Cy-0PEPc.js → recaptcha-v2-checkbox-CCnJYCnG.js} +4 -4
- package/dist/chunks/{recaptcha-v2-invisible-BwRH540O.js → recaptcha-v2-invisible-BuVqRRYn.js} +4 -4
- package/dist/chunks/{recaptcha-v3-No4Ykrhk.js → recaptcha-v3-CloqhO2A.js} +4 -4
- package/dist/chunks/{repeater-BVnPUqTj.js → repeater-DwE27jI1.js} +25 -19
- package/dist/chunks/request-profile-DhwkeCpS.js +10 -0
- package/dist/chunks/rich-text-uV4o_pGk.js +361 -0
- package/dist/chunks/{chunk-3b4jIN3o.js → rolldown-runtime-DtPi1Y-2.js} +2 -2
- package/dist/chunks/{sdk-BhHAYgga.js → sdk-lkwSvlpM.js} +282 -234
- package/dist/chunks/{shared-Bx9s0i0P.js → shared-OKhSay59.js} +27 -21
- package/dist/chunks/{signature-xz4QO7CR.js → signature-7cldFbqj.js} +160 -112
- package/dist/chunks/{snaptcha-DKx98oon.js → snaptcha-C04kNGYQ.js} +2 -2
- package/dist/chunks/{square-DwdcOI1G.js → square-DEzxv9D9.js} +8 -6
- package/dist/chunks/{stripe-DaoG2FT1.js → stripe-CVPQGDz3.js} +10 -11
- package/dist/chunks/{summary-Dks0gXS3.js → summary-BF_8mrXI.js} +47 -45
- package/dist/chunks/{survey-likert-DkE6bR7B.js → survey-likert-fk1hUPff.js} +7 -1
- package/dist/chunks/{survey-rank-DN6x4IZM.js → survey-rank-BsLGl2LX.js} +37 -25
- package/dist/chunks/{survey-rating-BnsNL9U5.js → survey-rating-DVS6e6fM.js} +17 -5
- package/dist/chunks/{table-CAjCJHrL.js → table-DnIBdeKF.js} +21 -15
- package/dist/chunks/{text-limit-Bn18WrPU.js → text-limit-LGMPhFuC.js} +40 -34
- package/dist/chunks/{theme-classes-Tv7q7ToE.js → theme-classes-DAQuEqdP.js} +1 -1
- package/dist/chunks/{turnstile-DJakPzQD.js → turnstile-n9DNyPxi.js} +3 -3
- package/dist/chunks/{upload-manager-W-QDgxKD.js → upload-manager-BbiUosZq.js} +410 -350
- package/dist/chunks/{utils-Vqp8i_RM.js → utils-DpUBPadZ.js} +20 -14
- package/dist/css/formie-base.css +104 -1
- package/dist/css/theme/_messages.css +2 -0
- package/dist/css/theme/_tokens.css +31 -25
- package/dist/css/theme/fields/_signature.css +2 -1
- package/dist/css/theme/forms/_form.css +5 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1778 -1425
- package/dist/js/contracts/client.d.ts +5 -3
- package/dist/js/contracts/client.d.ts.map +1 -1
- package/dist/js/contracts/common.d.ts +2 -2
- package/dist/js/contracts/common.d.ts.map +1 -1
- package/dist/js/contracts/modules.d.ts +37 -12
- package/dist/js/contracts/modules.d.ts.map +1 -1
- package/dist/js/contracts/schema.d.ts +20 -38
- package/dist/js/contracts/schema.d.ts.map +1 -1
- package/dist/js/contracts/theme.d.ts +4 -1
- package/dist/js/contracts/theme.d.ts.map +1 -1
- package/dist/js/core/client-rendered-modules.d.ts +17 -0
- package/dist/js/core/client-rendered-modules.d.ts.map +1 -0
- package/dist/js/core/create-formie-client.d.ts.map +1 -1
- package/dist/js/core/field-error-aria.d.ts +23 -0
- package/dist/js/core/field-error-aria.d.ts.map +1 -0
- package/dist/js/core/hydrate-modules.d.ts +10 -8
- package/dist/js/core/hydrate-modules.d.ts.map +1 -1
- package/dist/js/core/submit-result-state.d.ts.map +1 -1
- package/dist/js/core/submit-result-ui.d.ts.map +1 -1
- package/dist/js/core/validation-focus.d.ts.map +1 -1
- package/dist/js/modules/address/address-finder.d.ts +1 -1
- package/dist/js/modules/address/address-finder.d.ts.map +1 -1
- package/dist/js/modules/address/factories.d.ts +3 -3
- package/dist/js/modules/address/factories.d.ts.map +1 -1
- package/dist/js/modules/address/google-address.d.ts +2 -1
- package/dist/js/modules/address/google-address.d.ts.map +1 -1
- package/dist/js/modules/address/index.d.ts +2 -2
- package/dist/js/modules/address/index.d.ts.map +1 -1
- package/dist/js/modules/address/loqate.d.ts +1 -1
- package/dist/js/modules/address/loqate.d.ts.map +1 -1
- package/dist/js/modules/address/place-kit.d.ts +1 -1
- package/dist/js/modules/address/place-kit.d.ts.map +1 -1
- package/dist/js/modules/captchas/captcha-eu.d.ts +1 -1
- package/dist/js/modules/captchas/captcha-eu.d.ts.map +1 -1
- package/dist/js/modules/captchas/factories.d.ts +11 -11
- package/dist/js/modules/captchas/factories.d.ts.map +1 -1
- package/dist/js/modules/captchas/friendly-captcha-v1.d.ts +1 -1
- package/dist/js/modules/captchas/friendly-captcha-v1.d.ts.map +1 -1
- package/dist/js/modules/captchas/friendly-captcha-v2.d.ts +1 -1
- package/dist/js/modules/captchas/friendly-captcha-v2.d.ts.map +1 -1
- package/dist/js/modules/captchas/hcaptcha.d.ts +1 -1
- package/dist/js/modules/captchas/hcaptcha.d.ts.map +1 -1
- package/dist/js/modules/captchas/index.d.ts +2 -2
- package/dist/js/modules/captchas/index.d.ts.map +1 -1
- package/dist/js/modules/captchas/recaptcha-enterprise.d.ts +1 -1
- package/dist/js/modules/captchas/recaptcha-enterprise.d.ts.map +1 -1
- package/dist/js/modules/captchas/recaptcha-v2-checkbox.d.ts +1 -1
- package/dist/js/modules/captchas/recaptcha-v2-checkbox.d.ts.map +1 -1
- package/dist/js/modules/captchas/recaptcha-v2-invisible.d.ts +1 -1
- package/dist/js/modules/captchas/recaptcha-v2-invisible.d.ts.map +1 -1
- package/dist/js/modules/captchas/recaptcha-v3.d.ts +1 -1
- package/dist/js/modules/captchas/recaptcha-v3.d.ts.map +1 -1
- package/dist/js/modules/captchas/snaptcha.d.ts +1 -1
- package/dist/js/modules/captchas/snaptcha.d.ts.map +1 -1
- package/dist/js/modules/captchas/turnstile.d.ts +1 -1
- package/dist/js/modules/captchas/turnstile.d.ts.map +1 -1
- package/dist/js/modules/fields/address-country.d.ts +2 -2
- package/dist/js/modules/fields/address-country.d.ts.map +1 -1
- package/dist/js/modules/fields/address-state.d.ts +2 -2
- package/dist/js/modules/fields/address-state.d.ts.map +1 -1
- package/dist/js/modules/fields/calculations.d.ts +2 -2
- package/dist/js/modules/fields/calculations.d.ts.map +1 -1
- package/dist/js/modules/fields/checkbox-radio.d.ts +2 -2
- package/dist/js/modules/fields/checkbox-radio.d.ts.map +1 -1
- package/dist/js/modules/fields/combobox.d.ts +2 -2
- package/dist/js/modules/fields/combobox.d.ts.map +1 -1
- package/dist/js/modules/fields/conditions/config.d.ts.map +1 -1
- package/dist/js/modules/fields/conditions/effects.d.ts +1 -0
- package/dist/js/modules/fields/conditions/effects.d.ts.map +1 -1
- package/dist/js/modules/fields/conditions/evaluator.d.ts +4 -1
- package/dist/js/modules/fields/conditions/evaluator.d.ts.map +1 -1
- package/dist/js/modules/fields/conditions/references.d.ts.map +1 -1
- package/dist/js/modules/fields/conditions/submission-context.d.ts +15 -0
- package/dist/js/modules/fields/conditions/submission-context.d.ts.map +1 -0
- package/dist/js/modules/fields/conditions/types.d.ts +3 -1
- package/dist/js/modules/fields/conditions/types.d.ts.map +1 -1
- package/dist/js/modules/fields/conditions/values.d.ts +1 -1
- package/dist/js/modules/fields/conditions/values.d.ts.map +1 -1
- package/dist/js/modules/fields/conditions.d.ts +2 -2
- package/dist/js/modules/fields/conditions.d.ts.map +1 -1
- package/dist/js/modules/fields/custom-google-maps.d.ts +2 -2
- package/dist/js/modules/fields/custom-google-maps.d.ts.map +1 -1
- package/dist/js/modules/fields/custom-link.d.ts +2 -2
- package/dist/js/modules/fields/custom-link.d.ts.map +1 -1
- package/dist/js/modules/fields/custom-maps.d.ts +2 -2
- package/dist/js/modules/fields/custom-maps.d.ts.map +1 -1
- package/dist/js/modules/fields/date-picker.d.ts +2 -2
- package/dist/js/modules/fields/date-picker.d.ts.map +1 -1
- package/dist/js/modules/fields/file-upload.d.ts +2 -2
- package/dist/js/modules/fields/file-upload.d.ts.map +1 -1
- package/dist/js/modules/fields/hidden.d.ts +2 -2
- package/dist/js/modules/fields/hidden.d.ts.map +1 -1
- package/dist/js/modules/fields/index.d.ts +2 -2
- package/dist/js/modules/fields/index.d.ts.map +1 -1
- package/dist/js/modules/fields/password-validation.d.ts +2 -2
- package/dist/js/modules/fields/password-validation.d.ts.map +1 -1
- package/dist/js/modules/fields/phone-country.d.ts +2 -2
- package/dist/js/modules/fields/phone-country.d.ts.map +1 -1
- package/dist/js/modules/fields/repeater.d.ts +2 -2
- package/dist/js/modules/fields/repeater.d.ts.map +1 -1
- package/dist/js/modules/fields/rich-text.d.ts +2 -2
- package/dist/js/modules/fields/rich-text.d.ts.map +1 -1
- package/dist/js/modules/fields/shared.d.ts +1 -0
- package/dist/js/modules/fields/shared.d.ts.map +1 -1
- package/dist/js/modules/fields/signature.d.ts +2 -2
- package/dist/js/modules/fields/signature.d.ts.map +1 -1
- package/dist/js/modules/fields/summary.d.ts +2 -2
- package/dist/js/modules/fields/summary.d.ts.map +1 -1
- package/dist/js/modules/fields/survey-likert.d.ts +2 -2
- package/dist/js/modules/fields/survey-likert.d.ts.map +1 -1
- package/dist/js/modules/fields/survey-rank.d.ts +2 -2
- package/dist/js/modules/fields/survey-rank.d.ts.map +1 -1
- package/dist/js/modules/fields/survey-rating.d.ts +2 -2
- package/dist/js/modules/fields/survey-rating.d.ts.map +1 -1
- package/dist/js/modules/fields/table.d.ts +2 -2
- package/dist/js/modules/fields/table.d.ts.map +1 -1
- package/dist/js/modules/fields/text-limit.d.ts +2 -2
- package/dist/js/modules/fields/text-limit.d.ts.map +1 -1
- package/dist/js/modules/fields/upload-manager.d.ts +2 -2
- package/dist/js/modules/fields/upload-manager.d.ts.map +1 -1
- package/dist/js/modules/loader.d.ts +10 -4
- package/dist/js/modules/loader.d.ts.map +1 -1
- package/dist/js/modules/payments/bpoint.d.ts +1 -1
- package/dist/js/modules/payments/bpoint.d.ts.map +1 -1
- package/dist/js/modules/payments/eway.d.ts +1 -1
- package/dist/js/modules/payments/eway.d.ts.map +1 -1
- package/dist/js/modules/payments/factories.d.ts +7 -7
- package/dist/js/modules/payments/factories.d.ts.map +1 -1
- package/dist/js/modules/payments/go-cardless.d.ts +1 -1
- package/dist/js/modules/payments/go-cardless.d.ts.map +1 -1
- package/dist/js/modules/payments/index.d.ts +2 -2
- package/dist/js/modules/payments/index.d.ts.map +1 -1
- package/dist/js/modules/payments/mollie.d.ts +1 -1
- package/dist/js/modules/payments/mollie.d.ts.map +1 -1
- package/dist/js/modules/payments/moneris.d.ts +1 -1
- package/dist/js/modules/payments/moneris.d.ts.map +1 -1
- package/dist/js/modules/payments/opayo.d.ts +1 -1
- package/dist/js/modules/payments/opayo.d.ts.map +1 -1
- package/dist/js/modules/payments/paddle.d.ts +1 -1
- package/dist/js/modules/payments/paddle.d.ts.map +1 -1
- package/dist/js/modules/payments/paypal.d.ts +1 -1
- package/dist/js/modules/payments/paypal.d.ts.map +1 -1
- package/dist/js/modules/payments/payway.d.ts +1 -1
- package/dist/js/modules/payments/payway.d.ts.map +1 -1
- package/dist/js/modules/payments/square.d.ts +1 -1
- package/dist/js/modules/payments/square.d.ts.map +1 -1
- package/dist/js/modules/payments/stripe.d.ts +1 -1
- package/dist/js/modules/payments/stripe.d.ts.map +1 -1
- package/dist/js/modules/payments/utils.d.ts +6 -0
- package/dist/js/modules/payments/utils.d.ts.map +1 -1
- package/dist/js/modules/registry.d.ts +6 -4
- package/dist/js/modules/registry.d.ts.map +1 -1
- package/dist/js/submit/pipeline.d.ts.map +1 -1
- package/dist/js/theme/browser-theme-state.generated.d.ts +24 -0
- package/dist/js/theme/browser-theme-state.generated.d.ts.map +1 -0
- package/dist/js/theme/theme-classes.d.ts +3 -3
- package/dist/js/theme/theme-classes.d.ts.map +1 -1
- package/dist/js/transport/forms-api.d.ts +5 -3
- package/dist/js/transport/forms-api.d.ts.map +1 -1
- package/dist/js/utils/country-from-ip.d.ts +2 -2
- package/dist/js/utils/country-from-ip.d.ts.map +1 -1
- package/dist/js/utils/csrf.d.ts +17 -0
- package/dist/js/utils/csrf.d.ts.map +1 -0
- package/dist/js/utils/field-references.parser.d.ts +1 -0
- package/dist/js/utils/field-references.parser.d.ts.map +1 -1
- package/dist/js/utils/field-references.resolver.d.ts.map +1 -1
- package/dist/js/utils/field-references.types.d.ts +1 -0
- package/dist/js/utils/field-references.types.d.ts.map +1 -1
- package/dist/js/utils/http.d.ts +3 -1
- package/dist/js/utils/http.d.ts.map +1 -1
- package/dist/js/utils/request-profile.d.ts +4 -0
- package/dist/js/utils/request-profile.d.ts.map +1 -0
- package/dist/js/utils/unload-warning.d.ts.map +1 -1
- package/dist/js/validation/rules/email.d.ts.map +1 -1
- package/dist/js/validation/rules/match.d.ts.map +1 -1
- package/dist/js/validation/rules/number.d.ts.map +1 -1
- package/dist/js/validation/rules/required.d.ts.map +1 -1
- package/dist/js/validation/rules/shared.d.ts.map +1 -1
- package/dist/js/validation/rules/url.d.ts.map +1 -1
- package/dist/js/validation/skip.d.ts +7 -0
- package/dist/js/validation/skip.d.ts.map +1 -0
- package/dist/js/validation/submit-readiness.d.ts.map +1 -1
- package/dist/js/validation/validator.d.ts.map +1 -1
- package/package.json +43 -12
- package/src/css/formie-base.css +104 -1
- package/src/css/theme/_messages.css +2 -0
- package/src/css/theme/_tokens.css +31 -25
- package/src/css/theme/fields/_signature.css +2 -1
- package/src/css/theme/forms/_form.css +5 -1
- package/src/index.ts +13 -8
- package/src/js/contracts/client.ts +5 -3
- package/src/js/contracts/common.ts +5 -6
- package/src/js/contracts/modules.ts +41 -12
- package/src/js/contracts/schema.ts +21 -43
- package/src/js/contracts/theme.ts +6 -1
- package/src/js/core/client-rendered-modules.ts +69 -0
- package/src/js/core/create-formie-client.ts +119 -73
- package/src/js/core/field-error-aria.ts +93 -0
- package/src/js/core/hydrate-modules.ts +54 -29
- package/src/js/core/submit-result-state.ts +34 -45
- package/src/js/core/submit-result-ui.ts +21 -65
- package/src/js/core/validation-focus.ts +20 -20
- package/src/js/modules/address/address-finder.ts +1 -1
- package/src/js/modules/address/factories.ts +15 -13
- package/src/js/modules/address/google-address.ts +10 -6
- package/src/js/modules/address/index.ts +2 -2
- package/src/js/modules/address/loqate.ts +1 -1
- package/src/js/modules/address/place-kit.ts +1 -1
- package/src/js/modules/captchas/captcha-eu.ts +2 -2
- package/src/js/modules/captchas/factories.ts +66 -42
- package/src/js/modules/captchas/friendly-captcha-v1.ts +12 -2
- package/src/js/modules/captchas/friendly-captcha-v2.ts +4 -2
- package/src/js/modules/captchas/hcaptcha.ts +5 -5
- package/src/js/modules/captchas/index.ts +2 -2
- package/src/js/modules/captchas/recaptcha-enterprise.ts +2 -2
- package/src/js/modules/captchas/recaptcha-v2-checkbox.ts +3 -3
- package/src/js/modules/captchas/recaptcha-v2-invisible.ts +2 -2
- package/src/js/modules/captchas/recaptcha-v3.ts +2 -2
- package/src/js/modules/captchas/snaptcha.ts +1 -1
- package/src/js/modules/captchas/turnstile.ts +3 -3
- package/src/js/modules/fields/address-country.ts +6 -4
- package/src/js/modules/fields/address-state.ts +20 -12
- package/src/js/modules/fields/calculations.ts +5 -3
- package/src/js/modules/fields/checkbox-radio.ts +24 -42
- package/src/js/modules/fields/combobox.ts +25 -9
- package/src/js/modules/fields/conditions/config.ts +17 -20
- package/src/js/modules/fields/conditions/effects.ts +23 -26
- package/src/js/modules/fields/conditions/evaluator.ts +21 -29
- package/src/js/modules/fields/conditions/references.ts +16 -5
- package/src/js/modules/fields/conditions/submission-context.ts +80 -0
- package/src/js/modules/fields/conditions/types.ts +3 -1
- package/src/js/modules/fields/conditions/values.ts +31 -6
- package/src/js/modules/fields/conditions.ts +59 -18
- package/src/js/modules/fields/custom-google-maps.ts +5 -3
- package/src/js/modules/fields/custom-link.ts +5 -3
- package/src/js/modules/fields/custom-maps.ts +5 -3
- package/src/js/modules/fields/date-picker.ts +40 -4
- package/src/js/modules/fields/file-upload.ts +19 -10
- package/src/js/modules/fields/hidden.ts +5 -3
- package/src/js/modules/fields/index.ts +2 -2
- package/src/js/modules/fields/password-validation.ts +5 -3
- package/src/js/modules/fields/phone-country.ts +33 -6
- package/src/js/modules/fields/repeater.ts +5 -3
- package/src/js/modules/fields/rich-text.ts +20 -4
- package/src/js/modules/fields/shared.ts +13 -0
- package/src/js/modules/fields/signature.ts +64 -6
- package/src/js/modules/fields/summary.ts +8 -20
- package/src/js/modules/fields/survey-likert.ts +5 -3
- package/src/js/modules/fields/survey-rank.ts +21 -3
- package/src/js/modules/fields/survey-rating.ts +17 -3
- package/src/js/modules/fields/table.ts +5 -3
- package/src/js/modules/fields/text-limit.ts +5 -3
- package/src/js/modules/fields/upload-manager.ts +190 -49
- package/src/js/modules/loader.ts +345 -281
- package/src/js/modules/payments/bpoint.ts +2 -2
- package/src/js/modules/payments/eway.ts +2 -2
- package/src/js/modules/payments/factories.ts +53 -52
- package/src/js/modules/payments/go-cardless.ts +1 -1
- package/src/js/modules/payments/index.ts +2 -2
- package/src/js/modules/payments/mollie.ts +1 -1
- package/src/js/modules/payments/moneris.ts +2 -2
- package/src/js/modules/payments/opayo.ts +21 -8
- package/src/js/modules/payments/paddle.ts +10 -6
- package/src/js/modules/payments/payment.ts +22 -18
- package/src/js/modules/payments/paypal.ts +1 -1
- package/src/js/modules/payments/payway.ts +2 -2
- package/src/js/modules/payments/square.ts +2 -2
- package/src/js/modules/payments/stripe.ts +5 -5
- package/src/js/modules/payments/utils.ts +14 -0
- package/src/js/modules/registry.ts +19 -11
- package/src/js/submit/pipeline.ts +10 -11
- package/src/js/theme/browser-theme-state.generated.ts +25 -0
- package/src/js/theme/theme-classes.ts +3 -3
- package/src/js/transport/forms-api.ts +66 -67
- package/src/js/utils/country-from-ip.ts +14 -9
- package/src/js/utils/csrf.ts +136 -0
- package/src/js/utils/field-references.parser.ts +13 -113
- package/src/js/utils/field-references.resolver.ts +27 -64
- package/src/js/utils/field-references.row-scope.ts +1 -1
- package/src/js/utils/field-references.types.ts +1 -0
- package/src/js/utils/http.ts +5 -5
- package/src/js/utils/request-profile.ts +10 -0
- package/src/js/utils/unload-warning.ts +12 -4
- package/src/js/validation/rules/email.ts +3 -5
- package/src/js/validation/rules/match.ts +2 -1
- package/src/js/validation/rules/minmax.ts +4 -43
- package/src/js/validation/rules/number.ts +3 -47
- package/src/js/validation/rules/pattern.ts +3 -8
- package/src/js/validation/rules/required.ts +2 -1
- package/src/js/validation/rules/shared.ts +5 -1
- package/src/js/validation/rules/url.ts +3 -10
- package/src/js/validation/skip.ts +9 -0
- package/src/js/validation/submit-readiness.ts +9 -2
- package/src/js/validation/validator.ts +35 -59
- package/dist/chunks/calculations-DERi2xaC.js +0 -299
- package/dist/chunks/conditions-65kBcFWW.js +0 -424
- package/dist/chunks/country-from-ip-BwxKaBuJ.js +0 -26
- package/dist/chunks/field-references.resolver-CHwn0G0L.js +0 -145
- package/dist/chunks/friendly-captcha-v1-C_2reOXr.js +0 -31
- package/dist/chunks/google-address-BH3Zhi06.js +0 -161
- package/dist/chunks/http-D-JExro7.js +0 -27
- package/dist/chunks/opayo-CR0DtsLa.js +0 -179
- package/dist/chunks/rich-text-Bg_--4TG.js +0 -349
- package/dist/js/modules/fields/conditions/transforms.d.ts +0 -3
- package/dist/js/modules/fields/conditions/transforms.d.ts.map +0 -1
- package/src/js/modules/fields/conditions/transforms.ts +0 -206
- package/src/js/modules/payments/stub-payment-module.ts +0 -87
|
@@ -66,7 +66,7 @@ type StripeFieldState = Element & {
|
|
|
66
66
|
|
|
67
67
|
const ZERO_DECIMAL_CURRENCIES = new Set([
|
|
68
68
|
'BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG',
|
|
69
|
-
'RWF', '
|
|
69
|
+
'RWF', 'VND', 'VUV', 'XAF', 'XOF', 'XPF',
|
|
70
70
|
]);
|
|
71
71
|
|
|
72
72
|
function toStripeSubunitAmount(amount: number, currency: string): number {
|
|
@@ -74,7 +74,7 @@ function toStripeSubunitAmount(amount: number, currency: string): number {
|
|
|
74
74
|
return Math.ceil(amount);
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
return Math.
|
|
77
|
+
return Math.round((amount + Number.EPSILON) * 100);
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
function clearPlaceholderError(placeholder: HTMLElement | null, themeSource: Element | null): void {
|
|
@@ -97,7 +97,7 @@ function renderPlaceholderLoading(placeholder: HTMLElement | null, themeSource:
|
|
|
97
97
|
placeholder.removeAttribute('hidden');
|
|
98
98
|
placeholder.innerHTML = '';
|
|
99
99
|
const spinner = document.createElement('div');
|
|
100
|
-
spinner
|
|
100
|
+
addThemeClasses(spinner, themeSource, 'loading');
|
|
101
101
|
const text = document.createElement('div');
|
|
102
102
|
text.textContent = message;
|
|
103
103
|
placeholder.append(spinner, text);
|
|
@@ -120,7 +120,7 @@ function showPlaceholderMessage(placeholder: HTMLElement | null, themeSource: El
|
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
export const stripeModule = definePaymentModule<StripeProviderOptions, StripeInstance | null, StripeWidget | null>({
|
|
123
|
-
|
|
123
|
+
moduleId: 'formie:stripe',
|
|
124
124
|
defaultRequiredInputSuffixes: ['stripePaymentIntentId'],
|
|
125
125
|
load: async (ctx) => {
|
|
126
126
|
const { provider } = ctx.options;
|
|
@@ -288,7 +288,7 @@ export const stripeModule = definePaymentModule<StripeProviderOptions, StripeIns
|
|
|
288
288
|
stripeField.__formieStripeDynamicUnbind?.();
|
|
289
289
|
stripeField.__formieStripeDynamicUnbind = null;
|
|
290
290
|
},
|
|
291
|
-
|
|
291
|
+
onBeforePayment: async (args) => {
|
|
292
292
|
const { widget, services, field } = args;
|
|
293
293
|
const stripeField = field as StripeFieldState;
|
|
294
294
|
let activeWidget = widget;
|
|
@@ -15,6 +15,20 @@ export function getPaymentProviderHandle(id: string, options: PaymentProviderOpt
|
|
|
15
15
|
return id;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Payment widgets should neither mount nor enforce authorize tokens when the
|
|
20
|
+
* field (or an ancestor row/page) is hidden by conditions / page flow.
|
|
21
|
+
* Matches server-side `isConditionallyHidden()` skips in payment workflow tasks.
|
|
22
|
+
*/
|
|
23
|
+
export function isPaymentFieldActive(element: Element): boolean {
|
|
24
|
+
const node = element as HTMLElement;
|
|
25
|
+
|
|
26
|
+
return !node.closest('[data-formie-conditionally-hidden]')
|
|
27
|
+
&& !node.closest('[data-formie-row-hidden]')
|
|
28
|
+
&& !node.closest('[data-formie-page-hidden]')
|
|
29
|
+
&& !node.closest('[hidden]');
|
|
30
|
+
}
|
|
31
|
+
|
|
18
32
|
export function findPaymentInputBySuffix(root: Element, suffix: string): HTMLInputElement | null {
|
|
19
33
|
const escapedSuffix = suffix.replace(/"/g, '\\"');
|
|
20
34
|
return (root.querySelector(`input[name$="[${escapedSuffix}]"]`) ||
|
|
@@ -1,12 +1,17 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { BrowserModuleDefinition, ModuleRegistrationOptions } from '#contracts/modules';
|
|
2
2
|
|
|
3
3
|
export class ModuleRegistry {
|
|
4
|
-
private modules = new Map<string,
|
|
5
|
-
|
|
6
|
-
register(moduleDefinition:
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
private modules = new Map<string, BrowserModuleDefinition>();
|
|
5
|
+
|
|
6
|
+
register(moduleDefinition: BrowserModuleDefinition, options: ModuleRegistrationOptions = {}): boolean {
|
|
7
|
+
if (!/^[a-z][a-z0-9.-]*:[a-z][a-z0-9.-]*$/.test(moduleDefinition.moduleId) ||
|
|
8
|
+
moduleDefinition.version !== 2 || !Array.isArray(moduleDefinition.surfaces) || moduleDefinition.surfaces.length === 0 ||
|
|
9
|
+
moduleDefinition.surfaces.some((surface) => !['server-rendered', 'client-rendered', 'cp-edit'].includes(surface)) ||
|
|
10
|
+
!['field', 'captcha', 'payment', 'address', 'core'].includes(moduleDefinition.kind) ||
|
|
11
|
+
typeof moduleDefinition.match !== 'function' || typeof moduleDefinition.setup !== 'function') {
|
|
12
|
+
throw new Error('Unsupported browser module definition. Register a namespaced moduleId compatible with version 2.');
|
|
13
|
+
}
|
|
14
|
+
const existing = this.modules.get(moduleDefinition.moduleId);
|
|
10
15
|
|
|
11
16
|
if (existing === moduleDefinition) {
|
|
12
17
|
return true;
|
|
@@ -14,13 +19,13 @@ export class ModuleRegistry {
|
|
|
14
19
|
|
|
15
20
|
if (existing && !options.replace) {
|
|
16
21
|
console.warn(
|
|
17
|
-
`[formie] Module "${moduleDefinition.
|
|
22
|
+
`[formie] Module "${moduleDefinition.moduleId}" is already registered. `
|
|
18
23
|
+ 'Pass { replace: true } to override the existing definition.',
|
|
19
24
|
);
|
|
20
25
|
return false;
|
|
21
26
|
}
|
|
22
27
|
|
|
23
|
-
this.modules.set(moduleDefinition.
|
|
28
|
+
this.modules.set(moduleDefinition.moduleId, moduleDefinition);
|
|
24
29
|
return true;
|
|
25
30
|
}
|
|
26
31
|
|
|
@@ -28,11 +33,14 @@ export class ModuleRegistry {
|
|
|
28
33
|
this.modules.delete(moduleId);
|
|
29
34
|
}
|
|
30
35
|
|
|
31
|
-
get(moduleId: string):
|
|
36
|
+
get(moduleId: string): BrowserModuleDefinition | null {
|
|
32
37
|
return this.modules.get(moduleId) || null;
|
|
33
38
|
}
|
|
34
39
|
|
|
35
|
-
getAll():
|
|
40
|
+
getAll(): BrowserModuleDefinition[] {
|
|
36
41
|
return Array.from(this.modules.values());
|
|
37
42
|
}
|
|
38
43
|
}
|
|
44
|
+
|
|
45
|
+
/** Trusted application registrations shared by client-rendered framework hosts. */
|
|
46
|
+
export const clientRenderedModuleRegistry = new ModuleRegistry();
|
|
@@ -17,8 +17,8 @@ export type SubmitPipelineContext = {
|
|
|
17
17
|
|
|
18
18
|
type StageRunner = (ctx: SubmitPipelineContext) => Promise<FormSubmitResult | null>;
|
|
19
19
|
|
|
20
|
-
const STAGES: SubmitStage[] = ['prepare', '
|
|
21
|
-
const PREFLIGHT_STAGES: SubmitStage[] = ['prepare', '
|
|
20
|
+
const STAGES: SubmitStage[] = ['prepare', 'validate', 'challenge', 'payment', 'send', 'result'];
|
|
21
|
+
const PREFLIGHT_STAGES: SubmitStage[] = ['prepare', 'validate', 'challenge', 'payment'];
|
|
22
22
|
const debug = createDebug('general', 'pipeline');
|
|
23
23
|
|
|
24
24
|
function getAbortedResult(stage: SubmitStage, reason?: string): FormSubmitResult {
|
|
@@ -231,9 +231,6 @@ export async function runSubmitPipeline(
|
|
|
231
231
|
ctx.formData.set('submitAction', ctx.action);
|
|
232
232
|
return null;
|
|
233
233
|
},
|
|
234
|
-
normalize: async() => {
|
|
235
|
-
return null;
|
|
236
|
-
},
|
|
237
234
|
validate: async(ctx) => {
|
|
238
235
|
if (ctx.action !== 'submit') {
|
|
239
236
|
// Back/save actions bypass final validation so they can persist
|
|
@@ -290,13 +287,13 @@ export async function runSubmitPipeline(
|
|
|
290
287
|
|
|
291
288
|
return null;
|
|
292
289
|
},
|
|
293
|
-
|
|
290
|
+
challenge: async() => {
|
|
294
291
|
return null;
|
|
295
292
|
},
|
|
296
|
-
|
|
293
|
+
payment: async() => {
|
|
297
294
|
return null;
|
|
298
295
|
},
|
|
299
|
-
|
|
296
|
+
send: async(ctx) => {
|
|
300
297
|
// Rehydrate just-in-time so provider hooks can mutate hidden inputs
|
|
301
298
|
// during `screen` / `authorize` and still be submitted.
|
|
302
299
|
ctx.formData = buildSubmitFormData(ctx.form, ctx.action);
|
|
@@ -306,7 +303,7 @@ export async function runSubmitPipeline(
|
|
|
306
303
|
// success and failure outcomes (e.g. provider token/element resets).
|
|
307
304
|
return result;
|
|
308
305
|
},
|
|
309
|
-
|
|
306
|
+
result: async(resultCtx) => {
|
|
310
307
|
if (!dispatchResult) {
|
|
311
308
|
return null;
|
|
312
309
|
}
|
|
@@ -315,8 +312,9 @@ export async function runSubmitPipeline(
|
|
|
315
312
|
// rest of the browser client can react to one result shape first.
|
|
316
313
|
if (dispatchResult.ok && dispatchResult.redirect?.url) {
|
|
317
314
|
if (dispatchResult.redirect.target === 'new-tab') {
|
|
318
|
-
window.open(dispatchResult.redirect.url, '_blank');
|
|
315
|
+
window.open(dispatchResult.redirect.url, '_blank', 'noopener,noreferrer');
|
|
319
316
|
} else {
|
|
317
|
+
resultCtx.form.setAttribute('data-formie-internal-navigation', 'redirect');
|
|
320
318
|
window.location.href = dispatchResult.redirect.url;
|
|
321
319
|
}
|
|
322
320
|
}
|
|
@@ -469,7 +467,8 @@ export async function runSubmitPipeline(
|
|
|
469
467
|
|
|
470
468
|
const successResult: FormSubmitResult = dispatchResult || {
|
|
471
469
|
ok: true,
|
|
472
|
-
stage: options.preflightOnly ? '
|
|
470
|
+
stage: options.preflightOnly ? 'payment' : 'result',
|
|
471
|
+
code: options.preflightOnly ? 'PREFLIGHT_COMPLETE' : undefined,
|
|
473
472
|
message: options.preflightOnly ? 'Submission preflight completed.' : 'Submission completed.',
|
|
474
473
|
};
|
|
475
474
|
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Generated from src/config/browser-theme-state.json. Do not edit by hand.
|
|
2
|
+
export const BROWSER_THEME_STATE_DEFAULTS = {
|
|
3
|
+
errors: ["formie-errors"],
|
|
4
|
+
successes: ["formie-successes"],
|
|
5
|
+
message: ["formie-message"],
|
|
6
|
+
messageError: ["formie-message-error"],
|
|
7
|
+
messageSuccess: ["formie-message-success"],
|
|
8
|
+
tabError: ["formie-tab-error"],
|
|
9
|
+
tabCurrent: ["formie-tab-current"],
|
|
10
|
+
tabComplete: ["formie-tab-complete"],
|
|
11
|
+
tabLinkCurrent: [],
|
|
12
|
+
tabLinkInactive: [],
|
|
13
|
+
pageHidden: ["formie-page-hidden"],
|
|
14
|
+
conditionalHidden: ["formie-conditionally-hidden"],
|
|
15
|
+
rowHidden: ["formie-row-hidden"],
|
|
16
|
+
loading: ["formie-loading"],
|
|
17
|
+
success: ["formie-success"],
|
|
18
|
+
error: ["formie-error"],
|
|
19
|
+
fieldLayoutError: ["formie-field-has-error"],
|
|
20
|
+
fieldControlError: ["formie-input-error"],
|
|
21
|
+
fieldErrors: ["formie-field-errors"],
|
|
22
|
+
fieldError: ["formie-field-error"],
|
|
23
|
+
} as const;
|
|
24
|
+
|
|
25
|
+
export type BrowserThemeStateKey = keyof typeof BROWSER_THEME_STATE_DEFAULTS;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { BrowserThemeClassMap } from '#contracts/theme';
|
|
2
2
|
|
|
3
3
|
type NormalizedThemeClassMap = Record<string, string[]>;
|
|
4
4
|
|
|
@@ -46,7 +46,7 @@ function resolveThemeClassMap(source: Element | null): NormalizedThemeClassMap {
|
|
|
46
46
|
return themeRegistry.get(root) || {};
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
export function normalizeThemeClassMap(theme?:
|
|
49
|
+
export function normalizeThemeClassMap(theme?: BrowserThemeClassMap | null): NormalizedThemeClassMap {
|
|
50
50
|
const normalized: NormalizedThemeClassMap = {};
|
|
51
51
|
|
|
52
52
|
Object.entries(theme || {}).forEach(([key, value]) => {
|
|
@@ -60,7 +60,7 @@ export function normalizeThemeClassMap(theme?: ThemeClassMap | null): Normalized
|
|
|
60
60
|
return normalized;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
export function registerThemeClassMap(target: Element, theme?:
|
|
63
|
+
export function registerThemeClassMap(target: Element, theme?: BrowserThemeClassMap | null, form?: HTMLFormElement | null): NormalizedThemeClassMap {
|
|
64
64
|
const normalized = normalizeThemeClassMap(theme);
|
|
65
65
|
const resolvedForm = form || (target instanceof HTMLFormElement ? target : target.querySelector('form'));
|
|
66
66
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { browserRequest, type BrowserRequestOptions } from '@verbb/formie-core';
|
|
1
2
|
import type { FormEndpointPayload, FormSubmitResult } from '#contracts/schema';
|
|
3
|
+
import { appendFormCsrfToFormData } from '#utils/csrf';
|
|
2
4
|
import { createDebug } from '#utils/debug';
|
|
3
|
-
import { requestJson } from '#utils/http';
|
|
5
|
+
import { request, requestJson } from '#utils/http';
|
|
4
6
|
|
|
5
7
|
const debug = createDebug('general', 'transport');
|
|
6
8
|
|
|
@@ -25,40 +27,15 @@ function toServerRenderPayloadInput(renderOptions: Record<string, unknown>): Rec
|
|
|
25
27
|
return input;
|
|
26
28
|
}
|
|
27
29
|
|
|
28
|
-
function flattenErrors(errors: unknown, path = '', output: Record<string, string[]> = {}): Record<string, string[]> {
|
|
29
|
-
if (Array.isArray(errors)) {
|
|
30
|
-
const messages = errors
|
|
31
|
-
.map((value) => {
|
|
32
|
-
return typeof value === 'string' ? value : String(value ?? '');
|
|
33
|
-
})
|
|
34
|
-
.filter((value) => {
|
|
35
|
-
return value.trim() !== '';
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
if (path && messages.length) {
|
|
39
|
-
output[path] = (output[path] || []).concat(messages);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return output;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Craft/Formie error payloads can be nested by page/field/path. Flatten first
|
|
46
|
-
// so the browser client can map them back onto field handles consistently.
|
|
47
|
-
if (errors && typeof errors === 'object') {
|
|
48
|
-
Object.entries(errors as Record<string, unknown>).forEach(([key, value]) => {
|
|
49
|
-
const nextPath = path ? `${path}.${key}` : key;
|
|
50
|
-
flattenErrors(value, nextPath, output);
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return output;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
30
|
function normalizePayload(payload: Record<string, unknown>, fallbackFormError?: string): FormSubmitResult {
|
|
58
31
|
const success = payload.success === true;
|
|
59
|
-
const
|
|
32
|
+
const completion = payload.completion && typeof payload.completion === 'object'
|
|
33
|
+
? payload.completion as NonNullable<FormSubmitResult['completion']>
|
|
34
|
+
: null;
|
|
35
|
+
const payment = payload.payment && typeof payload.payment === 'object' ? payload.payment as FormSubmitResult['payment'] : null;
|
|
36
|
+
const keepSubmitLoading = ['requiresAction', 'pending', 'unknown'].includes(payment?.status || '');
|
|
60
37
|
const errors = payload.errors;
|
|
61
|
-
const fieldErrorsFlat =
|
|
38
|
+
const fieldErrorsFlat: Record<string, string[]> = Object.fromEntries(Object.entries(errors && typeof errors === 'object' ? errors : {}).map(([path, messages]) => [path, Array.isArray(messages) ? messages.filter((message): message is string => typeof message === 'string') : []]));
|
|
62
39
|
const formErrors = fieldErrorsFlat.form || [];
|
|
63
40
|
const fieldErrors: Record<string, string[]> = {};
|
|
64
41
|
|
|
@@ -67,10 +44,8 @@ function normalizePayload(payload: Record<string, unknown>, fallbackFormError?:
|
|
|
67
44
|
return;
|
|
68
45
|
}
|
|
69
46
|
|
|
70
|
-
// The
|
|
71
|
-
|
|
72
|
-
const topKey = key.split('.')[0];
|
|
73
|
-
fieldErrors[topKey] = (fieldErrors[topKey] || []).concat(value);
|
|
47
|
+
// The server normalises Yii keys; retain the entire control value path.
|
|
48
|
+
fieldErrors[key] = value;
|
|
74
49
|
});
|
|
75
50
|
|
|
76
51
|
const resolvedFormErrors = !success && formErrors.length === 0 && Object.keys(fieldErrors).length > 0
|
|
@@ -84,15 +59,24 @@ function normalizePayload(payload: Record<string, unknown>, fallbackFormError?:
|
|
|
84
59
|
|
|
85
60
|
const result: FormSubmitResult = {
|
|
86
61
|
ok: success,
|
|
62
|
+
outcome: typeof payload.outcome === 'string' ? payload.outcome : undefined,
|
|
63
|
+
version: typeof payload.version === 'number' ? payload.version : null,
|
|
64
|
+
submissionUid: typeof payload.submissionUid === 'string' ? payload.submissionUid : null,
|
|
65
|
+
errors: payload.errors,
|
|
66
|
+
session: payload.session,
|
|
67
|
+
completion,
|
|
87
68
|
action: (payload.submitAction === 'back' || payload.submitAction === 'save' || payload.submitAction === 'submit')
|
|
88
69
|
? payload.submitAction
|
|
89
70
|
: undefined,
|
|
90
71
|
message: (
|
|
91
|
-
|
|
72
|
+
completion?.message
|
|
73
|
+
|| payload.successMessage
|
|
74
|
+
|| payload.submitActionMessage
|
|
92
75
|
|| (success ? 'Submission completed.' : (isTransientPendingResult ? '' : (resolvedFormErrors[0] || 'Submission failed.')))
|
|
93
76
|
) as string,
|
|
94
77
|
code: success ? undefined : String(payload.code || 'SUBMIT_ERROR'),
|
|
95
78
|
keepSubmitLoading,
|
|
79
|
+
payment,
|
|
96
80
|
fieldErrors: Object.keys(fieldErrors).length ? fieldErrors : undefined,
|
|
97
81
|
formErrors: resolvedFormErrors.length ? resolvedFormErrors : undefined,
|
|
98
82
|
nextPage: payload.nextPageId
|
|
@@ -100,10 +84,20 @@ function normalizePayload(payload: Record<string, unknown>, fallbackFormError?:
|
|
|
100
84
|
id: String(payload.nextPageId),
|
|
101
85
|
}
|
|
102
86
|
: null,
|
|
103
|
-
redirect:
|
|
87
|
+
redirect: payment?.status === 'requiresAction' && payment.action?.type === 'redirect' && payment.action.url
|
|
88
|
+
? {
|
|
89
|
+
url: payment.action.url,
|
|
90
|
+
target: 'same-tab',
|
|
91
|
+
}
|
|
92
|
+
: completion?.url
|
|
93
|
+
? {
|
|
94
|
+
url: completion.url,
|
|
95
|
+
target: completion.target,
|
|
96
|
+
}
|
|
97
|
+
: payload.redirectUrl
|
|
104
98
|
? {
|
|
105
99
|
url: String(payload.redirectUrl),
|
|
106
|
-
target: payload.
|
|
100
|
+
target: payload.redirectTarget === 'new-tab' ? 'new-tab' : 'same-tab',
|
|
107
101
|
}
|
|
108
102
|
: null,
|
|
109
103
|
submitData: Array.isArray(payload.submitData) ? payload.submitData : undefined,
|
|
@@ -114,7 +108,7 @@ function normalizePayload(payload: Record<string, unknown>, fallbackFormError?:
|
|
|
114
108
|
return result;
|
|
115
109
|
}
|
|
116
110
|
|
|
117
|
-
export async function requestRender(endpoint: string, handle: string, renderOptions: Record<string, unknown> = {}): Promise<FormEndpointPayload> {
|
|
111
|
+
export async function requestRender(endpoint: string, handle: string, renderOptions: Record<string, unknown> = {}, requestOptions: BrowserRequestOptions = {}): Promise<FormEndpointPayload> {
|
|
118
112
|
const body = JSON.stringify({
|
|
119
113
|
handle,
|
|
120
114
|
renderOptions,
|
|
@@ -122,6 +116,7 @@ export async function requestRender(endpoint: string, handle: string, renderOpti
|
|
|
122
116
|
|
|
123
117
|
debug.log('requestRender start.', { endpoint, handle });
|
|
124
118
|
const result = await requestJson<FormEndpointPayload>(endpoint, {
|
|
119
|
+
...requestOptions,
|
|
125
120
|
method: 'POST',
|
|
126
121
|
body,
|
|
127
122
|
headers: {
|
|
@@ -134,7 +129,7 @@ export async function requestRender(endpoint: string, handle: string, renderOpti
|
|
|
134
129
|
return result;
|
|
135
130
|
}
|
|
136
131
|
|
|
137
|
-
export async function requestGraphqlRender(endpoint: string, handle: string, renderOptions: Record<string, unknown> = {}): Promise<FormEndpointPayload> {
|
|
132
|
+
export async function requestGraphqlRender(endpoint: string, handle: string, renderOptions: Record<string, unknown> = {}, requestOptions: BrowserRequestOptions = {}): Promise<FormEndpointPayload> {
|
|
138
133
|
const query = `
|
|
139
134
|
query FormieHtmlForm($handle: String!, $input: ServerRenderPayloadInput) {
|
|
140
135
|
formieHtmlForm(handle: $handle, input: $input) {
|
|
@@ -151,6 +146,7 @@ query FormieHtmlForm($handle: String!, $input: ServerRenderPayloadInput) {
|
|
|
151
146
|
|
|
152
147
|
debug.log('requestGraphqlRender start.', { endpoint, handle });
|
|
153
148
|
const result = await requestJson<GraphqlResponse<GraphqlFormQueryResult>>(endpoint, {
|
|
149
|
+
...requestOptions,
|
|
154
150
|
method: 'POST',
|
|
155
151
|
body,
|
|
156
152
|
headers: {
|
|
@@ -174,7 +170,7 @@ query FormieHtmlForm($handle: String!, $input: ServerRenderPayloadInput) {
|
|
|
174
170
|
return payload;
|
|
175
171
|
}
|
|
176
172
|
|
|
177
|
-
export async function requestRefreshTokens(endpoint: string, handle: string, renderId?: string): Promise<FormEndpointPayload['refreshTokens']> {
|
|
173
|
+
export async function requestRefreshTokens(endpoint: string, handle: string, renderId?: string, requestOptions: BrowserRequestOptions = {}, requestToken?: string): Promise<FormEndpointPayload['refreshTokens']> {
|
|
178
174
|
const url = new URL(endpoint, window.location.origin);
|
|
179
175
|
url.searchParams.set('handle', handle);
|
|
180
176
|
|
|
@@ -182,12 +178,14 @@ export async function requestRefreshTokens(endpoint: string, handle: string, ren
|
|
|
182
178
|
url.searchParams.set('renderId', renderId);
|
|
183
179
|
}
|
|
184
180
|
|
|
181
|
+
if (requestToken) url.searchParams.set('requestToken', requestToken);
|
|
182
|
+
|
|
185
183
|
debug.log('requestRefreshTokens start.', {
|
|
186
184
|
endpoint: url.toString(),
|
|
187
185
|
handle,
|
|
188
186
|
hasRenderId: !!renderId,
|
|
189
187
|
});
|
|
190
|
-
const response = await requestJson<FormEndpointPayload>(url.toString());
|
|
188
|
+
const response = await requestJson<FormEndpointPayload>(url.toString(), requestOptions);
|
|
191
189
|
debug.log('requestRefreshTokens complete.', {
|
|
192
190
|
hasRefreshTokens: !!response.refreshTokens,
|
|
193
191
|
});
|
|
@@ -198,6 +196,7 @@ export async function requestRefreshTokens(endpoint: string, handle: string, ren
|
|
|
198
196
|
export async function requestSetPage(url: string, form?: HTMLFormElement, pageId?: string): Promise<{
|
|
199
197
|
success?: boolean;
|
|
200
198
|
pageId?: string | number;
|
|
199
|
+
errors?: Record<string, string[]>;
|
|
201
200
|
}> {
|
|
202
201
|
const requestUrl = new URL(url, window.location.origin);
|
|
203
202
|
const body = new FormData();
|
|
@@ -209,7 +208,7 @@ export async function requestSetPage(url: string, form?: HTMLFormElement, pageId
|
|
|
209
208
|
if (form) {
|
|
210
209
|
// Page changes must carry the same continuity identifiers the submit flow
|
|
211
210
|
// uses so the backend can persist draft/session state for multipage forms.
|
|
212
|
-
const inputNames = ['handle', 'renderId', 'draftContextToken', 'draftContext', '
|
|
211
|
+
const inputNames = ['handle', 'renderId', 'draftContextToken', 'draftContext', 'progressId', 'requestToken', 'expectedVersion'];
|
|
213
212
|
|
|
214
213
|
inputNames.forEach((name) => {
|
|
215
214
|
const input = form.querySelector(`input[name="${name}"]`) as HTMLInputElement | null;
|
|
@@ -220,11 +219,9 @@ export async function requestSetPage(url: string, form?: HTMLFormElement, pageId
|
|
|
220
219
|
}
|
|
221
220
|
});
|
|
222
221
|
|
|
223
|
-
|
|
224
|
-
const
|
|
225
|
-
|
|
226
|
-
if (csrfValue) {
|
|
227
|
-
body.append('CRAFT_CSRF_TOKEN', csrfValue);
|
|
222
|
+
appendFormCsrfToFormData(body, form);
|
|
223
|
+
for (const [name, value] of new FormData(form)) {
|
|
224
|
+
if (name.startsWith('fields[')) body.append(name, value);
|
|
228
225
|
}
|
|
229
226
|
}
|
|
230
227
|
|
|
@@ -232,13 +229,22 @@ export async function requestSetPage(url: string, form?: HTMLFormElement, pageId
|
|
|
232
229
|
requestUrl: requestUrl.toString(),
|
|
233
230
|
pageId: pageId || null,
|
|
234
231
|
});
|
|
235
|
-
const
|
|
232
|
+
const response = await request(requestUrl.toString(), {
|
|
233
|
+
method: 'POST', body, profile: form?.dataset.formieRequestProfile as BrowserRequestOptions['profile'],
|
|
234
|
+
});
|
|
235
|
+
const result = await response.json() as {
|
|
236
236
|
success?: boolean;
|
|
237
237
|
pageId?: string | number;
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
238
|
+
errors?: Record<string, string[]>;
|
|
239
|
+
session?: { version: number; tokens?: { request?: string } };
|
|
240
|
+
};
|
|
241
|
+
if (form && result.session) {
|
|
242
|
+
const session = result.session;
|
|
243
|
+
const version = form.querySelector<HTMLInputElement>('input[name="expectedVersion"]');
|
|
244
|
+
const token = form.querySelector<HTMLInputElement>('input[name="requestToken"]');
|
|
245
|
+
if (version) version.value = String(session.version);
|
|
246
|
+
if (token && session.tokens?.request) token.value = session.tokens.request;
|
|
247
|
+
}
|
|
242
248
|
debug.log('requestSetPage complete.', result);
|
|
243
249
|
return result;
|
|
244
250
|
}
|
|
@@ -257,34 +263,28 @@ export function clearSubmissionOnUnload(endpoint: string, form: HTMLFormElement)
|
|
|
257
263
|
}
|
|
258
264
|
});
|
|
259
265
|
|
|
260
|
-
|
|
261
|
-
const csrfValue = csrfInput?.value?.trim();
|
|
262
|
-
|
|
263
|
-
if (csrfValue) {
|
|
264
|
-
body.append('CRAFT_CSRF_TOKEN', csrfValue);
|
|
265
|
-
}
|
|
266
|
+
appendFormCsrfToFormData(body, form);
|
|
266
267
|
|
|
267
268
|
debug.log('clearSubmissionOnUnload start.', {
|
|
268
269
|
requestUrl: requestUrl.toString(),
|
|
269
270
|
});
|
|
270
271
|
|
|
271
272
|
try {
|
|
272
|
-
if (typeof navigator.sendBeacon === 'function' && navigator.sendBeacon(requestUrl.toString(), body)) {
|
|
273
|
+
if (form.dataset.formieRequestProfile !== 'cross-origin-public' && typeof navigator.sendBeacon === 'function' && navigator.sendBeacon(requestUrl.toString(), body)) {
|
|
273
274
|
return;
|
|
274
275
|
}
|
|
275
276
|
} catch (_error) {
|
|
276
277
|
// Fall back to keepalive fetch below when Beacon is unavailable or rejects the payload.
|
|
277
278
|
}
|
|
278
279
|
|
|
279
|
-
void
|
|
280
|
+
void browserRequest(requestUrl.toString(), {
|
|
280
281
|
method: 'POST',
|
|
281
282
|
body,
|
|
282
|
-
credentials: 'include',
|
|
283
283
|
keepalive: true,
|
|
284
284
|
headers: {
|
|
285
285
|
Accept: 'application/json',
|
|
286
286
|
},
|
|
287
|
-
});
|
|
287
|
+
}, { profile: form.dataset.formieRequestProfile as BrowserRequestOptions['profile'] });
|
|
288
288
|
}
|
|
289
289
|
|
|
290
290
|
export async function submitForm(form: HTMLFormElement, formData: FormData): Promise<FormSubmitResult> {
|
|
@@ -297,14 +297,13 @@ export async function submitForm(form: HTMLFormElement, formData: FormData): Pro
|
|
|
297
297
|
action,
|
|
298
298
|
submitAction: formData.get('submitAction'),
|
|
299
299
|
});
|
|
300
|
-
const response = await
|
|
300
|
+
const response = await browserRequest(action, {
|
|
301
301
|
method,
|
|
302
302
|
body: formData,
|
|
303
|
-
credentials: 'include',
|
|
304
303
|
headers: {
|
|
305
304
|
Accept: 'application/json',
|
|
306
305
|
},
|
|
307
|
-
});
|
|
306
|
+
}, { profile: form.dataset.formieRequestProfile as BrowserRequestOptions['profile'] });
|
|
308
307
|
|
|
309
308
|
const contentType = response.headers.get('content-type') || '';
|
|
310
309
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { browserRequest } from '@verbb/formie-core';
|
|
2
|
+
import { getFormBrowserRequestOptions } from './request-profile';
|
|
1
3
|
export type CountryFromIpResponse = {
|
|
2
4
|
countryCode?: string | null;
|
|
3
5
|
countryName?: string | null;
|
|
@@ -5,23 +7,25 @@ export type CountryFromIpResponse = {
|
|
|
5
7
|
|
|
6
8
|
const DEFAULT_COUNTRY_FROM_IP_ACTION = 'formie/address/country-from-ip';
|
|
7
9
|
|
|
8
|
-
|
|
10
|
+
const cachedLookups = new Map<string, Promise<CountryFromIpResponse | null>>();
|
|
9
11
|
|
|
10
12
|
function buildActionUrl(action: string): string {
|
|
11
|
-
return new URL(action.startsWith('/') ? action : `/actions/${action}`, window.location.origin).toString();
|
|
13
|
+
return new URL(/^https?:\/\//.test(action) || action.startsWith('/') ? action : `/actions/${action}`, window.location.origin).toString();
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
export async function fetchCountryFromIp(
|
|
15
17
|
action: string = DEFAULT_COUNTRY_FROM_IP_ACTION,
|
|
18
|
+
form?: HTMLFormElement | null,
|
|
16
19
|
): Promise<CountryFromIpResponse | null> {
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
const key = buildActionUrl(action);
|
|
21
|
+
if (!cachedLookups.has(key)) {
|
|
22
|
+
cachedLookups.set(key, (async () => {
|
|
19
23
|
try {
|
|
20
|
-
const response = await
|
|
24
|
+
const response = await browserRequest(key, {
|
|
21
25
|
headers: {
|
|
22
26
|
Accept: 'application/json',
|
|
23
27
|
},
|
|
24
|
-
});
|
|
28
|
+
}, getFormBrowserRequestOptions(form));
|
|
25
29
|
|
|
26
30
|
if (!response.ok) {
|
|
27
31
|
return null;
|
|
@@ -37,17 +41,18 @@ export async function fetchCountryFromIp(
|
|
|
37
41
|
} catch {
|
|
38
42
|
return null;
|
|
39
43
|
}
|
|
40
|
-
})();
|
|
44
|
+
})());
|
|
41
45
|
}
|
|
42
46
|
|
|
43
|
-
return
|
|
47
|
+
return cachedLookups.get(key)!;
|
|
44
48
|
}
|
|
45
49
|
|
|
46
50
|
export function createGeoIpLookup(
|
|
47
51
|
action: string = DEFAULT_COUNTRY_FROM_IP_ACTION,
|
|
52
|
+
form?: HTMLFormElement | null,
|
|
48
53
|
): (callback: (countryCode: string) => void) => void {
|
|
49
54
|
return (callback) => {
|
|
50
|
-
void fetchCountryFromIp(action).then((data) => {
|
|
55
|
+
void fetchCountryFromIp(action, form).then((data) => {
|
|
51
56
|
callback(data?.countryCode?.toLowerCase() || '');
|
|
52
57
|
});
|
|
53
58
|
};
|