@verbb/formie-browser 1.0.13 → 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 +50 -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-F9BUBDSW.js → date-picker-RUnevF7l.js} +455 -432
- package/dist/chunks/{dist-D6i-VNgM.js → dist-ZLeW0zZ3.js} +1281 -453
- 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-D06uH9va.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-IOhuicje.js → signature-7cldFbqj.js} +138 -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-BGaY0jhI.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/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 -1427
- 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/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 +116 -77
- 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 +34 -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 +24 -4
- 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-Dv3hYb8_.js +0 -299
- package/dist/chunks/conditions-CPH1snCx.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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
BrowserModuleDefinition,
|
|
3
|
+
BrowserModuleInstance,
|
|
4
4
|
ModuleSetupContext,
|
|
5
5
|
} from '#contracts/modules';
|
|
6
6
|
import {
|
|
@@ -30,7 +30,7 @@ export type ManagedAddressModuleAdapter<
|
|
|
30
30
|
TApi,
|
|
31
31
|
TWidget,
|
|
32
32
|
> = {
|
|
33
|
-
|
|
33
|
+
moduleId: string;
|
|
34
34
|
load: (ctx: AddressModuleSetupContext<TProvider>) => Promise<TApi>;
|
|
35
35
|
mount: (args: {
|
|
36
36
|
api: TApi;
|
|
@@ -61,9 +61,11 @@ export function createManagedAddressModule<
|
|
|
61
61
|
TProvider extends Record<string, unknown>,
|
|
62
62
|
TApi,
|
|
63
63
|
TWidget,
|
|
64
|
-
>(adapter: ManagedAddressModuleAdapter<TProvider, TApi, TWidget>):
|
|
64
|
+
>(adapter: ManagedAddressModuleAdapter<TProvider, TApi, TWidget>): BrowserModuleDefinition {
|
|
65
65
|
return {
|
|
66
|
-
|
|
66
|
+
moduleId: adapter.moduleId,
|
|
67
|
+
version: 2,
|
|
68
|
+
surfaces: ['server-rendered', 'client-rendered', 'cp-edit'],
|
|
67
69
|
kind: 'address',
|
|
68
70
|
match: (ctx) => {
|
|
69
71
|
const input = ctx.target.querySelector('[data-formie-address-autocomplete-input]');
|
|
@@ -71,10 +73,10 @@ export function createManagedAddressModule<
|
|
|
71
73
|
return !!input;
|
|
72
74
|
},
|
|
73
75
|
setup: async (ctx) => {
|
|
74
|
-
const options = normalizeAddressModuleOptions<TProvider>(adapter.
|
|
76
|
+
const options = normalizeAddressModuleOptions<TProvider>(adapter.moduleId.split(':')[1], ctx.options || {});
|
|
75
77
|
const services = createAddressHostServices(ctx);
|
|
76
78
|
debug.log('Setup module.', {
|
|
77
|
-
moduleId: adapter.
|
|
79
|
+
moduleId: adapter.moduleId,
|
|
78
80
|
});
|
|
79
81
|
|
|
80
82
|
const setupCtx: AddressModuleSetupContext<TProvider> = {
|
|
@@ -90,11 +92,11 @@ export function createManagedAddressModule<
|
|
|
90
92
|
|
|
91
93
|
if (!input) {
|
|
92
94
|
console.warn(
|
|
93
|
-
`[formie] Address module "${adapter.
|
|
95
|
+
`[formie] Address module "${adapter.moduleId}" skipped: no autocomplete input found in target. ` +
|
|
94
96
|
'Ensure the Address field has the Auto-Complete subfield enabled.',
|
|
95
97
|
);
|
|
96
98
|
debug.warn('Autocomplete input missing; skipping module.', {
|
|
97
|
-
moduleId: adapter.
|
|
99
|
+
moduleId: adapter.moduleId,
|
|
98
100
|
});
|
|
99
101
|
return {
|
|
100
102
|
destroy: () => { },
|
|
@@ -104,7 +106,7 @@ export function createManagedAddressModule<
|
|
|
104
106
|
const getApi = async(): Promise<TApi> => {
|
|
105
107
|
if (!apiPromise) {
|
|
106
108
|
debug.log('Loading provider API.', {
|
|
107
|
-
moduleId: adapter.
|
|
109
|
+
moduleId: adapter.moduleId,
|
|
108
110
|
});
|
|
109
111
|
apiPromise = adapter.load(setupCtx);
|
|
110
112
|
}
|
|
@@ -126,7 +128,7 @@ export function createManagedAddressModule<
|
|
|
126
128
|
provider: options.provider,
|
|
127
129
|
});
|
|
128
130
|
debug.log('Widget mounted.', {
|
|
129
|
-
moduleId: adapter.
|
|
131
|
+
moduleId: adapter.moduleId,
|
|
130
132
|
});
|
|
131
133
|
};
|
|
132
134
|
|
|
@@ -178,7 +180,7 @@ export function createManagedAddressModule<
|
|
|
178
180
|
return {
|
|
179
181
|
destroy: async () => {
|
|
180
182
|
debug.log('Destroying module.', {
|
|
181
|
-
moduleId: adapter.
|
|
183
|
+
moduleId: adapter.moduleId,
|
|
182
184
|
});
|
|
183
185
|
cleanups.forEach((c) => c());
|
|
184
186
|
|
|
@@ -193,7 +195,7 @@ export function createManagedAddressModule<
|
|
|
193
195
|
provider: options.provider,
|
|
194
196
|
});
|
|
195
197
|
debug.log('Widget unmounted.', {
|
|
196
|
-
moduleId: adapter.
|
|
198
|
+
moduleId: adapter.moduleId,
|
|
197
199
|
});
|
|
198
200
|
}
|
|
199
201
|
},
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { appendFormCsrfToFormData } from '#utils/csrf';
|
|
2
|
+
import { browserRequest } from '@verbb/formie-core';
|
|
3
|
+
import { getFormBrowserRequestOptions } from '#utils/request-profile';
|
|
1
4
|
import { defineAddressModule } from '#modules/address/api';
|
|
2
5
|
import type { AddressHostServices } from '#modules/address/host';
|
|
3
6
|
import { getAddressProviderEventName } from '#utils/event-names';
|
|
@@ -7,6 +10,7 @@ type GoogleMaps = typeof google;
|
|
|
7
10
|
|
|
8
11
|
type GoogleAddressProviderOptions = {
|
|
9
12
|
apiKey?: string;
|
|
13
|
+
geocodeEndpoint?: string;
|
|
10
14
|
options?: Record<string, unknown>;
|
|
11
15
|
countryDefaultValue?: string;
|
|
12
16
|
};
|
|
@@ -231,7 +235,7 @@ export const googleAddressModule = defineAddressModule<
|
|
|
231
235
|
GoogleMaps,
|
|
232
236
|
google.maps.places.PlaceAutocompleteElement
|
|
233
237
|
>({
|
|
234
|
-
|
|
238
|
+
moduleId: 'formie:google-address',
|
|
235
239
|
load: async ({ options }) => {
|
|
236
240
|
const apiKey = options.provider.apiKey;
|
|
237
241
|
|
|
@@ -335,10 +339,10 @@ export const googleAddressModule = defineAddressModule<
|
|
|
335
339
|
|
|
336
340
|
return autocomplete;
|
|
337
341
|
},
|
|
338
|
-
onCurrentLocation: async (position, { field, services }) => {
|
|
342
|
+
onCurrentLocation: async (position, { field, services, provider }) => {
|
|
339
343
|
const { latitude, longitude } = position.coords;
|
|
340
344
|
const form = services.form;
|
|
341
|
-
const actionUrl = form?.action || window.location.href;
|
|
345
|
+
const actionUrl = provider.geocodeEndpoint || form?.action || window.location.href;
|
|
342
346
|
const fieldHandle = field.getAttribute('data-formie-field-handle')?.trim();
|
|
343
347
|
const formHandle = (form?.querySelector('[name="handle"]') as HTMLInputElement | null)?.value?.trim();
|
|
344
348
|
|
|
@@ -346,20 +350,20 @@ export const googleAddressModule = defineAddressModule<
|
|
|
346
350
|
|
|
347
351
|
try {
|
|
348
352
|
const formData = new FormData();
|
|
353
|
+
if (form) appendFormCsrfToFormData(formData, form);
|
|
349
354
|
formData.append('action', 'formie/address/google-places-geocode');
|
|
350
355
|
formData.append('latlng', `${latitude},${longitude}`);
|
|
351
356
|
formData.append('handle', formHandle);
|
|
352
357
|
formData.append('fieldHandle', fieldHandle);
|
|
353
358
|
|
|
354
|
-
const response = await
|
|
359
|
+
const response = await browserRequest(actionUrl, {
|
|
355
360
|
method: 'POST',
|
|
356
361
|
body: formData,
|
|
357
|
-
credentials: 'include',
|
|
358
362
|
headers: {
|
|
359
363
|
'X-Requested-With': 'XMLHttpRequest',
|
|
360
364
|
Accept: 'application/json',
|
|
361
365
|
},
|
|
362
|
-
});
|
|
366
|
+
}, getFormBrowserRequestOptions(form));
|
|
363
367
|
|
|
364
368
|
const data = await response.json();
|
|
365
369
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { BrowserModuleDefinition } from '#contracts/modules';
|
|
2
2
|
|
|
3
|
-
export const builtinAddressModuleLoaders: Record<string, () => Promise<
|
|
3
|
+
export const builtinAddressModuleLoaders: Record<string, () => Promise<BrowserModuleDefinition>> = {
|
|
4
4
|
// Address providers stay behind lazy importer entries because their SDKs are
|
|
5
5
|
// optional and often much heavier than the base form client.
|
|
6
6
|
'address-finder': () => import('#modules/address/address-finder').then((m) => m.addressFinderModule),
|
|
@@ -28,7 +28,7 @@ export const placeKitModule = defineAddressModule<
|
|
|
28
28
|
(apiKey: string, options: Record<string, unknown>) => PlaceKitPicker,
|
|
29
29
|
PlaceKitPicker
|
|
30
30
|
>({
|
|
31
|
-
|
|
31
|
+
moduleId: 'formie:place-kit',
|
|
32
32
|
load: async () => {
|
|
33
33
|
const module = await import('@placekit/autocomplete-js');
|
|
34
34
|
|
|
@@ -34,7 +34,7 @@ async function loadCaptchaEuGlobal(options: CaptchaEuProviderOptions): Promise<C
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
export const captchaEuModule = defineCaptchaModule<CaptchaEuProviderOptions, CaptchaEuGlobal, HTMLElement>({
|
|
37
|
-
|
|
37
|
+
moduleId: 'formie:captcha-eu',
|
|
38
38
|
defaultPlaceholderSelector: '[data-captcha-eu-placeholder]',
|
|
39
39
|
defaultTokenFieldNames: ['captcha-eu-token'],
|
|
40
40
|
load: ({ options }) => {
|
|
@@ -69,7 +69,7 @@ export const captchaEuModule = defineCaptchaModule<CaptchaEuProviderOptions, Cap
|
|
|
69
69
|
|
|
70
70
|
return container;
|
|
71
71
|
},
|
|
72
|
-
|
|
72
|
+
challenge: async ({ placeholder, services, stageCtx }) => {
|
|
73
73
|
// Captcha.eu solves through its own widget lifecycle and callback. By
|
|
74
74
|
// screen time we only need to wait for the shared transport layer to
|
|
75
75
|
// contain the provider payload.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
BrowserModuleDefinition,
|
|
3
|
+
BrowserModuleInstance,
|
|
4
4
|
ModuleSetupContext,
|
|
5
|
-
|
|
5
|
+
BeforeSubmitContext,
|
|
6
6
|
} from '#contracts/modules';
|
|
7
7
|
import type { FormSubmitResult } from '#contracts/schema';
|
|
8
8
|
import { DEFAULT_WAIT_FOR_VALUE_MS } from '#modules/captchas/constants';
|
|
@@ -21,11 +21,11 @@ type Cleanup = () => void;
|
|
|
21
21
|
const debug = createDebug('captchas');
|
|
22
22
|
|
|
23
23
|
type CaptchaModuleFactory<TProvider extends Record<string, unknown>> = {
|
|
24
|
-
|
|
24
|
+
moduleId: string;
|
|
25
25
|
defaultPlaceholderSelector: string;
|
|
26
26
|
defaultTokenFieldNames?: string[];
|
|
27
27
|
defaultWaitForValueMs?: number;
|
|
28
|
-
setup: (ctx: CaptchaModuleSetupContext<TProvider>) => Promise<
|
|
28
|
+
setup: (ctx: CaptchaModuleSetupContext<TProvider>) => Promise<BrowserModuleInstance | void>;
|
|
29
29
|
};
|
|
30
30
|
|
|
31
31
|
export type ManagedCaptchaModuleAdapter<
|
|
@@ -33,7 +33,7 @@ export type ManagedCaptchaModuleAdapter<
|
|
|
33
33
|
TApi,
|
|
34
34
|
TWidget,
|
|
35
35
|
> = {
|
|
36
|
-
|
|
36
|
+
moduleId: string;
|
|
37
37
|
defaultPlaceholderSelector: string;
|
|
38
38
|
defaultTokenFieldNames?: string[];
|
|
39
39
|
load: (ctx: CaptchaModuleSetupContext<TProvider>) => Promise<TApi>;
|
|
@@ -45,14 +45,14 @@ export type ManagedCaptchaModuleAdapter<
|
|
|
45
45
|
options: NormalizedCaptchaModuleOptions<TProvider>;
|
|
46
46
|
provider: TProvider;
|
|
47
47
|
}) => Promise<TWidget> | TWidget;
|
|
48
|
-
|
|
48
|
+
challenge: (args: {
|
|
49
49
|
api: TApi;
|
|
50
50
|
widget: TWidget;
|
|
51
51
|
placeholder: HTMLElement;
|
|
52
52
|
services: CaptchaHostServices;
|
|
53
53
|
options: NormalizedCaptchaModuleOptions<TProvider>;
|
|
54
54
|
provider: TProvider;
|
|
55
|
-
stageCtx:
|
|
55
|
+
stageCtx: BeforeSubmitContext;
|
|
56
56
|
}) => Promise<void> | void;
|
|
57
57
|
unmount?: (args: {
|
|
58
58
|
api: TApi;
|
|
@@ -79,14 +79,16 @@ export type CaptchaModuleSetupContext<TProvider extends Record<string, unknown>>
|
|
|
79
79
|
};
|
|
80
80
|
|
|
81
81
|
export function createCaptchaModule<TProvider extends Record<string, unknown> = Record<string, unknown>>({
|
|
82
|
-
|
|
82
|
+
moduleId,
|
|
83
83
|
defaultPlaceholderSelector,
|
|
84
84
|
defaultTokenFieldNames = [],
|
|
85
85
|
defaultWaitForValueMs = DEFAULT_WAIT_FOR_VALUE_MS,
|
|
86
86
|
setup,
|
|
87
|
-
}: CaptchaModuleFactory<TProvider>):
|
|
87
|
+
}: CaptchaModuleFactory<TProvider>): BrowserModuleDefinition {
|
|
88
88
|
return {
|
|
89
|
-
|
|
89
|
+
moduleId,
|
|
90
|
+
version: 2,
|
|
91
|
+
surfaces: ['server-rendered', 'client-rendered'],
|
|
90
92
|
kind: 'captcha',
|
|
91
93
|
match: () => true,
|
|
92
94
|
setup: async(ctx) => {
|
|
@@ -95,47 +97,58 @@ export function createCaptchaModule<TProvider extends Record<string, unknown> =
|
|
|
95
97
|
// 1. normalized options from the backend manifest
|
|
96
98
|
// 2. shared host services for placeholders, errors, tokens, and
|
|
97
99
|
// refresh-token events
|
|
98
|
-
const options = normalizeCaptchaModuleOptions<TProvider>(
|
|
100
|
+
const options = normalizeCaptchaModuleOptions<TProvider>(moduleId.split(':')[1], ctx.options || {}, {
|
|
99
101
|
defaultPlaceholderSelector,
|
|
100
102
|
defaultTokenFieldNames,
|
|
101
103
|
defaultWaitForValueMs,
|
|
102
104
|
});
|
|
103
105
|
debug.log('Setup module.', {
|
|
104
|
-
moduleId:
|
|
106
|
+
moduleId: moduleId,
|
|
105
107
|
placeholderSelector: options.ui.placeholderSelector,
|
|
106
108
|
tokenFieldNames: options.transport.tokenFieldNames,
|
|
107
109
|
});
|
|
110
|
+
let placeholder: HTMLElement | undefined;
|
|
111
|
+
if (ctx.surface === 'client-rendered' && !ctx.root.querySelector(options.ui.placeholderSelector)) {
|
|
112
|
+
const attribute = /^\[(data-[a-z0-9-]+)\]$/.exec(options.ui.placeholderSelector)?.[1];
|
|
113
|
+
if (!attribute) throw new Error('The CAPTCHA needs a supported placeholder in the client-rendered form.');
|
|
114
|
+
placeholder = document.createElement('div');
|
|
115
|
+
placeholder.setAttribute(attribute, '');
|
|
116
|
+
(ctx.form ?? ctx.root).append(placeholder);
|
|
117
|
+
}
|
|
108
118
|
const services = createCaptchaHostServices(ctx, options);
|
|
109
119
|
|
|
110
|
-
|
|
120
|
+
const instance = await setup({
|
|
111
121
|
...ctx,
|
|
112
122
|
options,
|
|
113
123
|
services,
|
|
114
124
|
});
|
|
125
|
+
if (!instance) { placeholder?.remove(); return; }
|
|
126
|
+
const destroy = instance.destroy;
|
|
127
|
+
return { ...instance, destroy: async() => { await destroy(); placeholder?.remove(); } };
|
|
115
128
|
},
|
|
116
129
|
};
|
|
117
130
|
}
|
|
118
131
|
|
|
119
132
|
export function createPassiveCaptchaModule({
|
|
120
|
-
|
|
133
|
+
moduleId,
|
|
121
134
|
defaultPlaceholderSelector,
|
|
122
135
|
defaultTokenFieldNames = [],
|
|
123
136
|
defaultWaitForValueMs = DEFAULT_WAIT_FOR_VALUE_MS,
|
|
124
137
|
}: {
|
|
125
|
-
|
|
138
|
+
moduleId: string;
|
|
126
139
|
defaultPlaceholderSelector: string;
|
|
127
140
|
defaultTokenFieldNames?: string[];
|
|
128
141
|
defaultWaitForValueMs?: number;
|
|
129
|
-
}):
|
|
142
|
+
}): BrowserModuleDefinition {
|
|
130
143
|
return createCaptchaModule<Record<string, never>>({
|
|
131
|
-
|
|
144
|
+
moduleId,
|
|
132
145
|
defaultPlaceholderSelector,
|
|
133
146
|
defaultTokenFieldNames,
|
|
134
147
|
defaultWaitForValueMs,
|
|
135
148
|
setup: async({ services, options, root }) => {
|
|
136
149
|
// Passive captchas do not have a browser SDK or visible widget.
|
|
137
150
|
// Their lifecycle is basically "keep the hidden transport input in
|
|
138
|
-
// sync, then verify it still exists at
|
|
151
|
+
// sync, then verify it still exists at challenge-stage submit time".
|
|
139
152
|
const cleanups: Cleanup[] = [];
|
|
140
153
|
let activePlaceholder = services.placeholder.getPrimary();
|
|
141
154
|
let sessionKey = options.transport.sessionKey;
|
|
@@ -159,7 +172,7 @@ export function createPassiveCaptchaModule({
|
|
|
159
172
|
(placeholder) => {
|
|
160
173
|
activePlaceholder = placeholder;
|
|
161
174
|
debug.log('Passive placeholder visible.', {
|
|
162
|
-
moduleId:
|
|
175
|
+
moduleId: moduleId,
|
|
163
176
|
});
|
|
164
177
|
renderPlaceholder(placeholder);
|
|
165
178
|
},
|
|
@@ -192,8 +205,8 @@ export function createPassiveCaptchaModule({
|
|
|
192
205
|
cleanup();
|
|
193
206
|
});
|
|
194
207
|
},
|
|
195
|
-
|
|
196
|
-
if (stageCtx.
|
|
208
|
+
beforeSubmit: async(stageCtx) => {
|
|
209
|
+
if (stageCtx.action !== 'submit') {
|
|
197
210
|
return;
|
|
198
211
|
}
|
|
199
212
|
|
|
@@ -209,7 +222,7 @@ export function createPassiveCaptchaModule({
|
|
|
209
222
|
const message = services.errors.getDefaultMessage();
|
|
210
223
|
services.errors.show(message, activePlaceholder);
|
|
211
224
|
debug.warn('Passive captcha missing token.', {
|
|
212
|
-
moduleId:
|
|
225
|
+
moduleId: moduleId,
|
|
213
226
|
tokenFieldNames,
|
|
214
227
|
});
|
|
215
228
|
stageCtx.abort(message);
|
|
@@ -224,9 +237,9 @@ export function createManagedCaptchaModule<
|
|
|
224
237
|
TProvider extends Record<string, unknown>,
|
|
225
238
|
TApi,
|
|
226
239
|
TWidget,
|
|
227
|
-
>(adapter: ManagedCaptchaModuleAdapter<TProvider, TApi, TWidget>):
|
|
240
|
+
>(adapter: ManagedCaptchaModuleAdapter<TProvider, TApi, TWidget>): BrowserModuleDefinition {
|
|
228
241
|
return createCaptchaModule<TProvider>({
|
|
229
|
-
|
|
242
|
+
moduleId: adapter.moduleId,
|
|
230
243
|
defaultPlaceholderSelector: adapter.defaultPlaceholderSelector,
|
|
231
244
|
defaultTokenFieldNames: adapter.defaultTokenFieldNames,
|
|
232
245
|
setup: async(ctx) => {
|
|
@@ -234,7 +247,7 @@ export function createManagedCaptchaModule<
|
|
|
234
247
|
// owns only the generic plumbing:
|
|
235
248
|
// - load the provider API once
|
|
236
249
|
// - mount/unmount when placeholders appear/disappear
|
|
237
|
-
// - call the provider's `
|
|
250
|
+
// - call the provider's `challenge()` at submit time
|
|
238
251
|
//
|
|
239
252
|
// It intentionally does not know provider policy such as "execute
|
|
240
253
|
// now" vs "must already be solved" - that stays in each module.
|
|
@@ -243,13 +256,14 @@ export function createManagedCaptchaModule<
|
|
|
243
256
|
const mountPromises = new Map<HTMLElement, Promise<void>>();
|
|
244
257
|
let activePlaceholder = ctx.services.placeholder.getPrimary();
|
|
245
258
|
let destroyed = false;
|
|
259
|
+
let initializationError: unknown;
|
|
246
260
|
|
|
247
261
|
let apiPromise: Promise<TApi> | null = null;
|
|
248
262
|
|
|
249
263
|
const getApi = async(): Promise<TApi> => {
|
|
250
264
|
if (!apiPromise) {
|
|
251
265
|
debug.log('Loading captcha provider API.', {
|
|
252
|
-
moduleId: adapter.
|
|
266
|
+
moduleId: adapter.moduleId,
|
|
253
267
|
});
|
|
254
268
|
apiPromise = adapter.load(ctx);
|
|
255
269
|
}
|
|
@@ -284,7 +298,7 @@ export function createManagedCaptchaModule<
|
|
|
284
298
|
placeholder.innerHTML = '';
|
|
285
299
|
ctx.services.tokens.clear();
|
|
286
300
|
debug.log('Unmounted captcha placeholder widget.', {
|
|
287
|
-
moduleId: adapter.
|
|
301
|
+
moduleId: adapter.moduleId,
|
|
288
302
|
});
|
|
289
303
|
|
|
290
304
|
if (activePlaceholder === placeholder) {
|
|
@@ -293,9 +307,8 @@ export function createManagedCaptchaModule<
|
|
|
293
307
|
};
|
|
294
308
|
|
|
295
309
|
const mountPlaceholder = async(placeholder: HTMLElement) => {
|
|
296
|
-
if (destroyed || mountedWidgets.has(placeholder)
|
|
297
|
-
|
|
298
|
-
}
|
|
310
|
+
if (destroyed || mountedWidgets.has(placeholder)) return;
|
|
311
|
+
if (mountPromises.has(placeholder)) return mountPromises.get(placeholder);
|
|
299
312
|
|
|
300
313
|
// Guard against repeated visibility events or rapid DOM churn
|
|
301
314
|
// by tracking an in-flight mount promise per placeholder.
|
|
@@ -322,7 +335,7 @@ export function createManagedCaptchaModule<
|
|
|
322
335
|
mountedWidgets.set(placeholder, widget);
|
|
323
336
|
activePlaceholder = placeholder;
|
|
324
337
|
debug.log('Mounted captcha placeholder widget.', {
|
|
325
|
-
moduleId: adapter.
|
|
338
|
+
moduleId: adapter.moduleId,
|
|
326
339
|
});
|
|
327
340
|
})().finally(() => {
|
|
328
341
|
mountPromises.delete(placeholder);
|
|
@@ -336,7 +349,7 @@ export function createManagedCaptchaModule<
|
|
|
336
349
|
const visibility = ctx.services.placeholder.observe(
|
|
337
350
|
(placeholder) => {
|
|
338
351
|
activePlaceholder = placeholder;
|
|
339
|
-
void mountPlaceholder(placeholder);
|
|
352
|
+
void mountPlaceholder(placeholder).catch((error) => { initializationError = error; });
|
|
340
353
|
},
|
|
341
354
|
(placeholder) => {
|
|
342
355
|
void unmountPlaceholder(placeholder);
|
|
@@ -399,7 +412,7 @@ export function createManagedCaptchaModule<
|
|
|
399
412
|
return;
|
|
400
413
|
}
|
|
401
414
|
|
|
402
|
-
if (detail?.ok === false && detail?.stage === '
|
|
415
|
+
if (detail?.ok === false && detail?.stage === 'challenge') {
|
|
403
416
|
return;
|
|
404
417
|
}
|
|
405
418
|
|
|
@@ -420,7 +433,18 @@ export function createManagedCaptchaModule<
|
|
|
420
433
|
}));
|
|
421
434
|
}
|
|
422
435
|
|
|
436
|
+
visibility.reconcileImmediate();
|
|
437
|
+
try {
|
|
438
|
+
await Promise.all([...mountPromises.values()]);
|
|
439
|
+
if (initializationError) throw initializationError;
|
|
440
|
+
} catch (error) {
|
|
441
|
+
destroyed = true;
|
|
442
|
+
cleanups.forEach((cleanup) => cleanup());
|
|
443
|
+
throw error;
|
|
444
|
+
}
|
|
445
|
+
|
|
423
446
|
return {
|
|
447
|
+
assertReady: () => { if (initializationError) throw initializationError; },
|
|
424
448
|
destroy: async() => {
|
|
425
449
|
destroyed = true;
|
|
426
450
|
cleanups.forEach((cleanup) => {
|
|
@@ -431,22 +455,22 @@ export function createManagedCaptchaModule<
|
|
|
431
455
|
await unmountPlaceholder(placeholder);
|
|
432
456
|
}
|
|
433
457
|
},
|
|
434
|
-
|
|
435
|
-
if (stageCtx.
|
|
458
|
+
beforeSubmit: async(stageCtx) => {
|
|
459
|
+
if (stageCtx.action !== 'submit') {
|
|
436
460
|
return;
|
|
437
461
|
}
|
|
438
462
|
|
|
439
463
|
// Reconcile immediately so captcha placeholders on the newly
|
|
440
|
-
// visible page are mounted before
|
|
464
|
+
// visible page are mounted before challenge-stage policy runs.
|
|
441
465
|
visibility.reconcileImmediate();
|
|
442
466
|
|
|
443
|
-
// By the time provider `
|
|
467
|
+
// By the time provider `challenge()` runs, the widget is
|
|
444
468
|
// guaranteed to be mounted and the active placeholder is
|
|
445
469
|
// resolved. That lets provider code focus on challenge
|
|
446
470
|
// policy rather than generic lifecycle setup.
|
|
447
471
|
const visiblePlaceholders = visibility.getVisible();
|
|
448
472
|
|
|
449
|
-
// Captcha fields on hidden pages should not run in
|
|
473
|
+
// Captcha fields on hidden pages should not run in challenge stage.
|
|
450
474
|
if (visiblePlaceholders.length === 0) {
|
|
451
475
|
return;
|
|
452
476
|
}
|
|
@@ -464,8 +488,8 @@ export function createManagedCaptchaModule<
|
|
|
464
488
|
if (!widget) {
|
|
465
489
|
const message = ctx.services.errors.getDefaultMessage();
|
|
466
490
|
ctx.services.errors.show(message, placeholder);
|
|
467
|
-
debug.warn('Captcha widget unavailable at
|
|
468
|
-
moduleId: adapter.
|
|
491
|
+
debug.warn('Captcha widget unavailable at challenge stage.', {
|
|
492
|
+
moduleId: adapter.moduleId,
|
|
469
493
|
});
|
|
470
494
|
stageCtx.abort(message);
|
|
471
495
|
return;
|
|
@@ -473,7 +497,7 @@ export function createManagedCaptchaModule<
|
|
|
473
497
|
|
|
474
498
|
const api = await getApi();
|
|
475
499
|
|
|
476
|
-
await adapter.
|
|
500
|
+
await adapter.challenge({
|
|
477
501
|
api,
|
|
478
502
|
widget,
|
|
479
503
|
placeholder,
|
|
@@ -8,6 +8,7 @@ type FriendlyCaptchaProviderOptions = {
|
|
|
8
8
|
siteKey?: string | null;
|
|
9
9
|
language?: string;
|
|
10
10
|
startMode?: string;
|
|
11
|
+
theme?: string;
|
|
11
12
|
};
|
|
12
13
|
|
|
13
14
|
export const friendlyCaptchaV1Module = defineCaptchaModule<
|
|
@@ -15,7 +16,7 @@ export const friendlyCaptchaV1Module = defineCaptchaModule<
|
|
|
15
16
|
FriendlyChallengeModule,
|
|
16
17
|
import('friendly-challenge').WidgetInstance
|
|
17
18
|
>({
|
|
18
|
-
|
|
19
|
+
moduleId: 'formie:friendly-captcha-v1',
|
|
19
20
|
defaultPlaceholderSelector: '[data-friendly-captcha-placeholder]',
|
|
20
21
|
defaultTokenFieldNames: ['frc-captcha-solution'],
|
|
21
22
|
load: async() => {
|
|
@@ -24,6 +25,15 @@ export const friendlyCaptchaV1Module = defineCaptchaModule<
|
|
|
24
25
|
return import('friendly-challenge');
|
|
25
26
|
},
|
|
26
27
|
mount: ({ api, container, provider, services }) => {
|
|
28
|
+
// V1 uses a `dark` class on the widget element (no `auto` theme option).
|
|
29
|
+
const theme = provider.theme || 'auto';
|
|
30
|
+
const prefersDark = window.matchMedia?.('(prefers-color-scheme: dark)').matches ?? false;
|
|
31
|
+
const useDark = theme === 'dark' || (theme === 'auto' && prefersDark);
|
|
32
|
+
|
|
33
|
+
if (useDark) {
|
|
34
|
+
container.classList.add('dark');
|
|
35
|
+
}
|
|
36
|
+
|
|
27
37
|
return new api.WidgetInstance(container, {
|
|
28
38
|
sitekey: provider.siteKey || '',
|
|
29
39
|
startMode: (provider.startMode as 'auto' | 'focus' | 'none' | undefined) || 'none',
|
|
@@ -43,7 +53,7 @@ export const friendlyCaptchaV1Module = defineCaptchaModule<
|
|
|
43
53
|
},
|
|
44
54
|
});
|
|
45
55
|
},
|
|
46
|
-
|
|
56
|
+
challenge: async({ widget, placeholder, services, stageCtx }) => {
|
|
47
57
|
// FriendlyCaptcha is started programmatically on submit when needed.
|
|
48
58
|
if (services.tokens.has()) {
|
|
49
59
|
return;
|
|
@@ -10,6 +10,7 @@ type FriendlyCaptchaProviderOptions = {
|
|
|
10
10
|
siteKey?: string | null;
|
|
11
11
|
language?: string;
|
|
12
12
|
startMode?: string;
|
|
13
|
+
theme?: string;
|
|
13
14
|
};
|
|
14
15
|
|
|
15
16
|
export const friendlyCaptchaV2Module = defineCaptchaModule<
|
|
@@ -17,7 +18,7 @@ export const friendlyCaptchaV2Module = defineCaptchaModule<
|
|
|
17
18
|
FriendlyCaptchaSdkModule,
|
|
18
19
|
FriendlyCaptchaWidget
|
|
19
20
|
>({
|
|
20
|
-
|
|
21
|
+
moduleId: 'formie:friendly-captcha-v2',
|
|
21
22
|
defaultPlaceholderSelector: '[data-friendly-captcha-placeholder]',
|
|
22
23
|
defaultTokenFieldNames: ['frc-captcha-response'],
|
|
23
24
|
load: async () => {
|
|
@@ -34,6 +35,7 @@ export const friendlyCaptchaV2Module = defineCaptchaModule<
|
|
|
34
35
|
formFieldName: 'frc-captcha-response',
|
|
35
36
|
language: provider.language,
|
|
36
37
|
startMode: (provider.startMode as 'auto' | 'focus' | 'none' | undefined) || 'none',
|
|
38
|
+
theme: (provider.theme as 'auto' | 'light' | 'dark' | undefined) || 'auto',
|
|
37
39
|
});
|
|
38
40
|
|
|
39
41
|
widget.addEventListener('frc:widget.complete', (event) => {
|
|
@@ -62,7 +64,7 @@ export const friendlyCaptchaV2Module = defineCaptchaModule<
|
|
|
62
64
|
|
|
63
65
|
return widget;
|
|
64
66
|
},
|
|
65
|
-
|
|
67
|
+
challenge: async ({ widget, placeholder, services, stageCtx }) => {
|
|
66
68
|
// As with v1, start the challenge only if no token is currently present.
|
|
67
69
|
if (services.tokens.has()) {
|
|
68
70
|
return;
|
|
@@ -66,7 +66,7 @@ async function loadHcaptchaGlobal(options: HcaptchaProviderOptions): Promise<Hca
|
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
export const hcaptchaModule = defineCaptchaModule<HcaptchaProviderOptions, HcaptchaGlobal, number | string>({
|
|
69
|
-
|
|
69
|
+
moduleId: 'formie:hcaptcha',
|
|
70
70
|
defaultPlaceholderSelector: '[data-hcaptcha-placeholder]',
|
|
71
71
|
defaultTokenFieldNames: ['h-captcha-response'],
|
|
72
72
|
load: ({ options }) => {
|
|
@@ -77,7 +77,7 @@ export const hcaptchaModule = defineCaptchaModule<HcaptchaProviderOptions, Hcapt
|
|
|
77
77
|
},
|
|
78
78
|
mount: ({ api, container, provider, services }) => {
|
|
79
79
|
// Mount only renders/configures the widget. It does not decide whether
|
|
80
|
-
// a submit should be blocked; that responsibility lives in `
|
|
80
|
+
// a submit should be blocked; that responsibility lives in `challenge()`.
|
|
81
81
|
return api.render(container, {
|
|
82
82
|
sitekey: provider.siteKey || '',
|
|
83
83
|
theme: provider.theme || 'light',
|
|
@@ -113,10 +113,10 @@ export const hcaptchaModule = defineCaptchaModule<HcaptchaProviderOptions, Hcapt
|
|
|
113
113
|
},
|
|
114
114
|
});
|
|
115
115
|
},
|
|
116
|
-
|
|
117
|
-
// `
|
|
116
|
+
challenge: ({ api, widget, placeholder, services, stageCtx }) => {
|
|
117
|
+
// `challenge()` runs at submit time. By the time we get here the widget is
|
|
118
118
|
// already mounted, so this method only answers "do we have a valid
|
|
119
|
-
// token yet, and if not, can we get one before the
|
|
119
|
+
// token yet, and if not, can we get one before the challenge stage ends?"
|
|
120
120
|
if (services.tokens.has()) {
|
|
121
121
|
// Users can complete hCaptcha before clicking submit. In that case
|
|
122
122
|
// there is nothing to do; we already have the token the backend
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { BrowserModuleDefinition } from '#contracts/modules';
|
|
2
2
|
|
|
3
|
-
export const builtinCaptchaModuleLoaders: Record<string, () => Promise<
|
|
3
|
+
export const builtinCaptchaModuleLoaders: Record<string, () => Promise<BrowserModuleDefinition>> = {
|
|
4
4
|
// Module ids map directly to importer functions so the loader can fetch only
|
|
5
5
|
// the captcha chunks required by the current form manifest.
|
|
6
6
|
'captcha-eu': () => import('#modules/captchas/captcha-eu').then((module) => module.captchaEuModule),
|
|
@@ -23,7 +23,7 @@ type RecaptchaEnterpriseProviderOptions = RecaptchaProviderOptions & {
|
|
|
23
23
|
// Shared captcha services should not know about any of those distinctions, so
|
|
24
24
|
// this module owns the branching itself.
|
|
25
25
|
export const recaptchaEnterpriseModule = defineCaptchaModule<RecaptchaEnterpriseProviderOptions, RecaptchaGlobal, number | string>({
|
|
26
|
-
|
|
26
|
+
moduleId: 'formie:recaptcha-enterprise',
|
|
27
27
|
defaultPlaceholderSelector: '[data-recaptcha-placeholder]',
|
|
28
28
|
defaultTokenFieldNames: ['g-recaptcha-response'],
|
|
29
29
|
load: ({ options }) => {
|
|
@@ -75,7 +75,7 @@ export const recaptchaEnterpriseModule = defineCaptchaModule<RecaptchaEnterprise
|
|
|
75
75
|
});
|
|
76
76
|
});
|
|
77
77
|
},
|
|
78
|
-
|
|
78
|
+
challenge: async({ api, widget, provider, placeholder, services, stageCtx }) => {
|
|
79
79
|
const enterpriseApi = api.enterprise || api;
|
|
80
80
|
|
|
81
81
|
if (provider.enterpriseType === 'checkbox') {
|