@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
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
export type FormCsrfToken = {
|
|
2
|
+
name: string;
|
|
3
|
+
value: string;
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
type CraftGlobal = {
|
|
7
|
+
csrfTokenName?: string;
|
|
8
|
+
csrfTokenValue?: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const DEFAULT_CRAFT_CSRF_TOKEN_NAME = 'CRAFT_CSRF_TOKEN';
|
|
12
|
+
const FORMIE_CSRF_PARAM_ATTR = 'data-formie-csrf-param';
|
|
13
|
+
const FORMIE_CSRF_INPUT_ATTR = 'data-formie-csrf';
|
|
14
|
+
|
|
15
|
+
function getCraftCsrfTokenName(): string | null {
|
|
16
|
+
const craft = (globalThis as { Craft?: CraftGlobal }).Craft;
|
|
17
|
+
const name = craft?.csrfTokenName;
|
|
18
|
+
|
|
19
|
+
return typeof name === 'string' && name.trim() ? name.trim() : null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function escapeAttributeSelectorValue(value: string): string {
|
|
23
|
+
if (typeof CSS !== 'undefined' && typeof CSS.escape === 'function') {
|
|
24
|
+
return CSS.escape(value);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Attribute-selector fallback for environments without CSS.escape.
|
|
28
|
+
return value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function queryNamedInput(root: ParentNode, name: string): HTMLInputElement | null {
|
|
32
|
+
const input = root.querySelector(`input[name="${escapeAttributeSelectorValue(name)}"]`);
|
|
33
|
+
|
|
34
|
+
return input instanceof HTMLInputElement ? input : null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Resolve the Craft CSRF hidden input for a Formie form.
|
|
39
|
+
*
|
|
40
|
+
* Prefer Formie markers / declared param names so custom `csrfTokenName`
|
|
41
|
+
* values in `config/general.php` keep working. Fall back to Craft's CP
|
|
42
|
+
* global and the default token name for older or custom templates.
|
|
43
|
+
*/
|
|
44
|
+
export function getFormCsrfInput(form: ParentNode | null | undefined): HTMLInputElement | null {
|
|
45
|
+
if (!form) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const marked = form.querySelector(`input[${FORMIE_CSRF_INPUT_ATTR}]`);
|
|
50
|
+
|
|
51
|
+
if (marked instanceof HTMLInputElement && marked.name.trim()) {
|
|
52
|
+
return marked;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (form instanceof Element) {
|
|
56
|
+
const declaredParam = form.getAttribute(FORMIE_CSRF_PARAM_ATTR)?.trim();
|
|
57
|
+
|
|
58
|
+
if (declaredParam) {
|
|
59
|
+
const declaredInput = queryNamedInput(form, declaredParam);
|
|
60
|
+
|
|
61
|
+
if (declaredInput) {
|
|
62
|
+
return declaredInput;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const craftName = getCraftCsrfTokenName();
|
|
68
|
+
|
|
69
|
+
if (craftName) {
|
|
70
|
+
const craftInput = queryNamedInput(form, craftName);
|
|
71
|
+
|
|
72
|
+
if (craftInput) {
|
|
73
|
+
return craftInput;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return queryNamedInput(form, DEFAULT_CRAFT_CSRF_TOKEN_NAME);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function getFormCsrfToken(form: ParentNode | null | undefined): FormCsrfToken | null {
|
|
81
|
+
const input = getFormCsrfInput(form);
|
|
82
|
+
const name = input?.name?.trim() || '';
|
|
83
|
+
const value = input?.value?.trim() || '';
|
|
84
|
+
|
|
85
|
+
if (!name || !value) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return { name, value };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function appendFormCsrfToFormData(body: FormData, form: ParentNode | null | undefined): void {
|
|
93
|
+
const csrf = getFormCsrfToken(form);
|
|
94
|
+
|
|
95
|
+
if (csrf) {
|
|
96
|
+
body.append(csrf.name, csrf.value);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function applyFormCsrfToRecord(target: Record<string, string>, form: ParentNode | null | undefined): void {
|
|
101
|
+
const csrf = getFormCsrfToken(form);
|
|
102
|
+
|
|
103
|
+
if (csrf) {
|
|
104
|
+
target[csrf.name] = csrf.value;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function isFormCsrfFieldName(name: string, form?: ParentNode | null): boolean {
|
|
109
|
+
const normalizedName = name.endsWith('[]') ? name.slice(0, -2) : name;
|
|
110
|
+
|
|
111
|
+
if (!normalizedName) {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (normalizedName === DEFAULT_CRAFT_CSRF_TOKEN_NAME) {
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const craftName = getCraftCsrfTokenName();
|
|
120
|
+
|
|
121
|
+
if (craftName && normalizedName === craftName) {
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (form instanceof Element) {
|
|
126
|
+
const declaredParam = form.getAttribute(FORMIE_CSRF_PARAM_ATTR)?.trim();
|
|
127
|
+
|
|
128
|
+
if (declaredParam && normalizedName === declaredParam) {
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const csrf = getFormCsrfToken(form);
|
|
134
|
+
|
|
135
|
+
return !!csrf && normalizedName === csrf.name;
|
|
136
|
+
}
|
|
@@ -1,121 +1,21 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { parseReference } from '@verbb/formie-core';
|
|
2
|
+
import type { ParsedFieldReference } from '#utils/field-references.types';
|
|
2
3
|
import { normalizeFieldKey } from '#utils/field-references.keys';
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
const parts = body.split(';').map((part) => {
|
|
6
|
-
return part.trim();
|
|
7
|
-
}).filter(Boolean);
|
|
8
|
-
|
|
9
|
-
if (!parts.length) {
|
|
10
|
-
return {
|
|
11
|
-
source: '',
|
|
12
|
-
transforms: [],
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const [source, ...metadata] = parts;
|
|
17
|
-
const transforms: FieldReferenceTransform[] = [];
|
|
18
|
-
let current: FieldReferenceTransform | null = null;
|
|
19
|
-
|
|
20
|
-
metadata.forEach((entry) => {
|
|
21
|
-
if (entry.startsWith('transform=')) {
|
|
22
|
-
if (current) {
|
|
23
|
-
transforms.push(current);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
current = {
|
|
27
|
-
id: decodeURIComponent(entry.slice('transform='.length) || '').trim(),
|
|
28
|
-
params: {},
|
|
29
|
-
};
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
if (!current || !entry.includes('=')) {
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const [rawKey, rawValue] = entry.split('=', 2);
|
|
38
|
-
const key = (rawKey || '').trim();
|
|
39
|
-
|
|
40
|
-
if (!key || key === 'transform') {
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
current.params[key] = decodeURIComponent(rawValue || '').trim();
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
if (current) {
|
|
48
|
-
transforms.push(current);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return {
|
|
52
|
-
source: source || '',
|
|
53
|
-
transforms,
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
|
|
5
|
+
/** Browser field slots adapt the shared grammar; plain keys are legacy field operands. */
|
|
57
6
|
export function parseFieldReference(rawValue: string): ParsedFieldReference {
|
|
58
7
|
const raw = String(rawValue || '').trim();
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
raw,
|
|
63
|
-
target: '',
|
|
64
|
-
key: '',
|
|
65
|
-
selector: '',
|
|
66
|
-
defaultValue: '',
|
|
67
|
-
transforms: [],
|
|
68
|
-
isToken: false,
|
|
69
|
-
isValid: false,
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const tokenMatch = raw.match(/^\{([a-zA-Z]+)(?::(.*))?\}$/);
|
|
74
|
-
|
|
75
|
-
if (!tokenMatch) {
|
|
76
|
-
return {
|
|
77
|
-
raw,
|
|
78
|
-
target: '',
|
|
79
|
-
key: normalizeFieldKey(raw),
|
|
80
|
-
selector: '',
|
|
81
|
-
defaultValue: '',
|
|
82
|
-
transforms: [],
|
|
83
|
-
isToken: false,
|
|
84
|
-
isValid: true,
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const targetRaw = (tokenMatch[1] || '').trim().toLowerCase();
|
|
89
|
-
const bodyRaw = (tokenMatch[2] || '').trim();
|
|
90
|
-
const [beforeDefault, defaultRaw = ''] = bodyRaw.split('|', 2);
|
|
91
|
-
const { source, transforms } = parseTransforms(beforeDefault || '');
|
|
92
|
-
|
|
93
|
-
if (targetRaw !== 'field') {
|
|
94
|
-
return {
|
|
95
|
-
raw,
|
|
96
|
-
target: '',
|
|
97
|
-
key: '',
|
|
98
|
-
selector: '',
|
|
99
|
-
defaultValue: defaultRaw.trim(),
|
|
100
|
-
transforms,
|
|
101
|
-
isToken: true,
|
|
102
|
-
isValid: false,
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
const separatorIndex = source.indexOf(':');
|
|
107
|
-
const keyRaw = separatorIndex === -1 ? source : source.slice(0, separatorIndex);
|
|
108
|
-
const selectorRaw = separatorIndex === -1 ? '' : source.slice(separatorIndex + 1);
|
|
109
|
-
const key = normalizeFieldKey(keyRaw);
|
|
110
|
-
|
|
8
|
+
const expression = parseReference(raw);
|
|
9
|
+
const isToken = raw.startsWith('{');
|
|
10
|
+
const field = expression.isValid && expression.target === 'field';
|
|
111
11
|
return {
|
|
112
12
|
raw,
|
|
113
|
-
target: 'field',
|
|
114
|
-
key,
|
|
115
|
-
selector:
|
|
116
|
-
defaultValue:
|
|
117
|
-
transforms,
|
|
118
|
-
isToken
|
|
119
|
-
isValid:
|
|
13
|
+
target: field ? 'field' : '',
|
|
14
|
+
key: field ? normalizeFieldKey(expression.identifier) : (isToken ? '' : normalizeFieldKey(raw)),
|
|
15
|
+
selector: expression.selector,
|
|
16
|
+
defaultValue: expression.default,
|
|
17
|
+
transforms: expression.transformerId ? [{ id: expression.transformerId, params: expression.transformerParams }] : [],
|
|
18
|
+
isToken,
|
|
19
|
+
isValid: isToken ? field : raw !== '',
|
|
120
20
|
};
|
|
121
21
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { parseReference, resolveReference } from '@verbb/formie-core';
|
|
1
2
|
import { fieldKeyToInputName, normalizeFieldKey } from '#utils/field-references.keys';
|
|
2
3
|
import { parseFieldReference } from '#utils/field-references.parser';
|
|
3
4
|
import type {
|
|
@@ -42,74 +43,36 @@ function getEntry(registry: FieldValueRegistry, key: string) {
|
|
|
42
43
|
return registry.get(normalizeFieldKey(key)) || null;
|
|
43
44
|
}
|
|
44
45
|
|
|
45
|
-
|
|
46
|
-
reference:
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
function resolvedProjection(reference: string, key: string, value: string | string[]): ResolveFieldValueResult {
|
|
47
|
+
const token = reference.trim().startsWith('{') ? reference : `{field:${encodeURIComponent(key)}}`;
|
|
48
|
+
const expression = parseReference(token);
|
|
49
|
+
const id = `field:${expression.identifier}`;
|
|
50
|
+
const valueId = expression.selector ? `${id}:${expression.selector}` : id;
|
|
51
|
+
const resolved = resolveReference(token, {
|
|
52
|
+
definitions: { [id]: { id, selectors: expression.selector ? [expression.selector] : [], availability: { server: true, browser: true } } },
|
|
53
|
+
values: { [valueId]: value },
|
|
54
|
+
});
|
|
55
|
+
return { key, value: resolved.diagnostic ? '' : resolved.value as string | string[], found: !resolved.diagnostic, diagnostic: resolved.diagnostic };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function resolveFieldReferenceLive(reference: string, registry: FieldValueRegistry): ResolveFieldValueResult {
|
|
49
59
|
const parsed = parseFieldReference(reference);
|
|
50
60
|
const key = parsed.key;
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
if (!entry) {
|
|
54
|
-
|
|
55
|
-
key,
|
|
56
|
-
value: parsed.defaultValue,
|
|
57
|
-
found: false,
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const value = readInputsValue(entry.inputs);
|
|
62
|
-
|
|
63
|
-
return {
|
|
64
|
-
key,
|
|
65
|
-
value: value === '' && parsed.defaultValue !== '' ? parsed.defaultValue : value,
|
|
66
|
-
found: true,
|
|
67
|
-
};
|
|
61
|
+
const lookup = parsed.selector ? `${key}.${parsed.selector.replace(/:/g, '.')}` : key;
|
|
62
|
+
const entry = parsed.isValid ? getEntry(registry, lookup) : null;
|
|
63
|
+
if (!entry) return { key, value: '', found: false, diagnostic: !parsed.isValid ? 'invalidExpression' : parsed.selector ? 'invalidSelector' : 'missingField' };
|
|
64
|
+
return resolvedProjection(reference, key, readInputsValue(entry.inputs));
|
|
68
65
|
}
|
|
69
66
|
|
|
70
|
-
export function resolveFieldReferenceFromFormData(
|
|
71
|
-
reference: string,
|
|
72
|
-
formData: FormData,
|
|
73
|
-
registry?: FieldValueRegistry,
|
|
74
|
-
): ResolveFieldValueResult {
|
|
67
|
+
export function resolveFieldReferenceFromFormData(reference: string, formData: FormData, registry?: FieldValueRegistry): ResolveFieldValueResult {
|
|
75
68
|
const parsed = parseFieldReference(reference);
|
|
76
69
|
const key = parsed.key;
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
const entry = registry ? getEntry(registry, key) : null;
|
|
87
|
-
const names = entry?.names?.length ? entry.names : [fieldKeyToInputName(key)];
|
|
88
|
-
const values = names.flatMap((name) => {
|
|
89
|
-
const collected = formData.getAll(name).map((value) => {
|
|
90
|
-
return String(value ?? '');
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
if (collected.length) {
|
|
94
|
-
return collected;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return formData.getAll(`${name}[]`).map((value) => {
|
|
98
|
-
return String(value ?? '');
|
|
99
|
-
});
|
|
100
|
-
}).filter((value) => value !== '');
|
|
101
|
-
|
|
102
|
-
if (!values.length) {
|
|
103
|
-
return {
|
|
104
|
-
key,
|
|
105
|
-
value: parsed.defaultValue,
|
|
106
|
-
found: false,
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
return {
|
|
111
|
-
key,
|
|
112
|
-
value: values.length > 1 ? values : values[0],
|
|
113
|
-
found: true,
|
|
114
|
-
};
|
|
70
|
+
const lookup = parsed.selector ? `${key}.${parsed.selector.replace(/:/g, '.')}` : key;
|
|
71
|
+
const entry = registry ? getEntry(registry, lookup) : null;
|
|
72
|
+
if (!parsed.isValid || (registry && !entry)) return { key, value: '', found: false, diagnostic: parsed.isValid ? 'missingField' : 'invalidExpression' };
|
|
73
|
+
const names = entry?.names?.length ? entry.names : [fieldKeyToInputName(lookup)];
|
|
74
|
+
const present = !!entry || names.some((name) => formData.has(name) || formData.has(`${name}[]`));
|
|
75
|
+
if (!present) return { key, value: '', found: false, diagnostic: 'missingField' };
|
|
76
|
+
const values = names.flatMap((name) => [...formData.getAll(name), ...formData.getAll(`${name}[]`)]).map((value) => String(value ?? ''));
|
|
77
|
+
return resolvedProjection(reference, key, values.length > 1 ? values : values[0] ?? '');
|
|
115
78
|
}
|
|
@@ -78,7 +78,7 @@ export function parseRowsExpression(expression: string, rowCount: number): numbe
|
|
|
78
78
|
[start, end] = [end, start];
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
for (let row = start; row <= end; row++) {
|
|
81
|
+
for (let row = Math.max(1, start); row <= Math.min(rowCount, end); row++) {
|
|
82
82
|
if (row >= 1 && row <= rowCount) {
|
|
83
83
|
indices.push(row - 1);
|
|
84
84
|
}
|
package/src/js/utils/http.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
import { browserRequest, type BrowserRequestOptions } from '@verbb/formie-core';
|
|
2
|
+
export type RequestJsonOptions = BrowserRequestOptions & {
|
|
2
3
|
method?: string;
|
|
3
4
|
body?: BodyInit | null;
|
|
4
5
|
headers?: Record<string, string>;
|
|
5
6
|
signal?: AbortSignal;
|
|
6
7
|
};
|
|
7
8
|
|
|
8
|
-
async function request(url: string | URL, options: RequestJsonOptions = {}): Promise<Response> {
|
|
9
|
+
export async function request(url: string | URL, options: RequestJsonOptions = {}): Promise<Response> {
|
|
9
10
|
// Do not send `X-Requested-With` here: it is not CORS-safelisted, and Craft GraphQL CORS
|
|
10
11
|
// often omits it from `Access-Control-Allow-Headers` (breaks localhost → ddev, starters, etc.).
|
|
11
12
|
// `Accept` + JSON `Content-Type` are enough for Formie/Craft JSON endpoints.
|
|
@@ -16,7 +17,7 @@ async function request(url: string | URL, options: RequestJsonOptions = {}): Pro
|
|
|
16
17
|
delete headers['X-Requested-With'];
|
|
17
18
|
delete headers['x-requested-with'];
|
|
18
19
|
|
|
19
|
-
return
|
|
20
|
+
return browserRequest(String(url), {
|
|
20
21
|
method: options.method || 'GET',
|
|
21
22
|
body: options.body ?? null,
|
|
22
23
|
signal: options.signal,
|
|
@@ -26,8 +27,7 @@ async function request(url: string | URL, options: RequestJsonOptions = {}): Pro
|
|
|
26
27
|
// `include` + `Access-Control-Allow-Origin: *` is invalid; many Craft GraphQL setups use `*`.
|
|
27
28
|
// `same-origin` keeps cookies for same-host deployments and avoids credentialed cross-origin
|
|
28
29
|
// fetches (e.g. Vite on localhost → ddev HTTPS) so wildcard CORS can succeed.
|
|
29
|
-
|
|
30
|
-
});
|
|
30
|
+
}, options);
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
export async function requestJson<T>(url: string | URL, options: RequestJsonOptions = {}): Promise<T> {
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { BrowserRequestOptions } from '@verbb/formie-core';
|
|
2
|
+
|
|
3
|
+
const formRequests = new WeakMap<HTMLFormElement, BrowserRequestOptions>();
|
|
4
|
+
export function setFormBrowserRequestOptions(form: HTMLFormElement, options: BrowserRequestOptions): void {
|
|
5
|
+
formRequests.set(form, { ...options });
|
|
6
|
+
form.dataset.formieRequestProfile = options.profile ?? 'same-origin-browser';
|
|
7
|
+
}
|
|
8
|
+
export function getFormBrowserRequestOptions(form: HTMLFormElement | null | undefined): BrowserRequestOptions {
|
|
9
|
+
return form && formRequests.get(form) || { profile: form?.dataset.formieRequestProfile as BrowserRequestOptions['profile'] };
|
|
10
|
+
}
|
|
@@ -1,15 +1,17 @@
|
|
|
1
|
+
import { isFormCsrfFieldName } from '#utils/csrf';
|
|
2
|
+
|
|
1
3
|
const DIRTY_TRACKING_IGNORED_FIELD_NAMES = new Set([
|
|
2
|
-
'CRAFT_CSRF_TOKEN',
|
|
3
4
|
'action',
|
|
4
5
|
'redirect',
|
|
5
6
|
'requestToken',
|
|
7
|
+
'uploadCreateToken',
|
|
6
8
|
'renderId',
|
|
7
9
|
'formStartedAt',
|
|
8
10
|
'submitAction',
|
|
9
11
|
'pageId',
|
|
10
12
|
'draftContextToken',
|
|
11
13
|
'draftContext',
|
|
12
|
-
'
|
|
14
|
+
'progressId',
|
|
13
15
|
]);
|
|
14
16
|
|
|
15
17
|
function serializeStableValue(value: unknown, seen: WeakSet<object>): string {
|
|
@@ -64,19 +66,25 @@ function stableSerialize(value: unknown): string {
|
|
|
64
66
|
return serializeStableValue(value, new WeakSet<object>());
|
|
65
67
|
}
|
|
66
68
|
|
|
67
|
-
function shouldTrackFieldName(name: string): boolean {
|
|
69
|
+
function shouldTrackFieldName(name: string, form: HTMLFormElement): boolean {
|
|
68
70
|
if (!name) {
|
|
69
71
|
return false;
|
|
70
72
|
}
|
|
71
73
|
|
|
72
74
|
const normalizedName = name.endsWith('[]') ? name.slice(0, -2) : name;
|
|
73
75
|
|
|
76
|
+
// Ignore CSRF regardless of custom csrfTokenName so token refresh
|
|
77
|
+
// does not mark the form dirty.
|
|
78
|
+
if (isFormCsrfFieldName(normalizedName, form)) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
|
|
74
82
|
return !DIRTY_TRACKING_IGNORED_FIELD_NAMES.has(normalizedName);
|
|
75
83
|
}
|
|
76
84
|
|
|
77
85
|
function buildTrackedSnapshot(form: HTMLFormElement): string {
|
|
78
86
|
const entries = Array.from(new FormData(form).entries()).filter(([name]) => {
|
|
79
|
-
return shouldTrackFieldName(String(name || ''));
|
|
87
|
+
return shouldTrackFieldName(String(name || ''), form);
|
|
80
88
|
});
|
|
81
89
|
|
|
82
90
|
return stableSerialize(entries);
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
+
import { validateBrowserValue } from '@verbb/formie-core';
|
|
1
2
|
import type { ValidationRuleDefinition } from '#validation/types';
|
|
2
3
|
|
|
3
4
|
const email: ValidationRuleDefinition = {
|
|
4
5
|
rule: ({ input, getRule }) => {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(input.value);
|
|
6
|
+
const rule = getRule('email');
|
|
7
|
+
return !rule || validateBrowserValue(input.value, { ...(typeof rule === 'object' ? rule : {}), type: 'email' }) === null;
|
|
10
8
|
},
|
|
11
9
|
message: ({ input, label, t }) => {
|
|
12
10
|
return input.getAttribute('data-formie-validation-email-message')
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { validateBrowserValue } from '@verbb/formie-core';
|
|
1
2
|
import type { ValidationRuleDefinition } from '#validation/types';
|
|
2
3
|
import { getComparableInput, getLabelText } from '#validation/rules/shared';
|
|
3
4
|
|
|
@@ -9,7 +10,7 @@ const match: ValidationRuleDefinition = {
|
|
|
9
10
|
return true;
|
|
10
11
|
}
|
|
11
12
|
|
|
12
|
-
return sourceInput.value ===
|
|
13
|
+
return validateBrowserValue(ctx.input.value, { type: 'match' }, { comparison: sourceInput.value }) === null;
|
|
13
14
|
},
|
|
14
15
|
message: (ctx) => {
|
|
15
16
|
const sourceInput = getComparableInput(ctx);
|
|
@@ -1,47 +1,8 @@
|
|
|
1
|
+
import { validateBrowserValue } from '@verbb/formie-core';
|
|
1
2
|
import type { ValidationRuleDefinition } from '#validation/types';
|
|
2
|
-
|
|
3
|
+
const bounds = (input: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement) => ({ type: 'number', min: input.hasAttribute('min') ? Number(input.getAttribute('min')) : null, max: input.hasAttribute('max') ? Number(input.getAttribute('max')) : null });
|
|
3
4
|
const minmax: ValidationRuleDefinition = {
|
|
4
|
-
rule: ({ input }) =>
|
|
5
|
-
|
|
6
|
-
return true;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const value = parseFloat(input.value);
|
|
10
|
-
const min = input.hasAttribute('min') ? parseFloat(input.getAttribute('min') || '') : null;
|
|
11
|
-
const max = input.hasAttribute('max') ? parseFloat(input.getAttribute('max') || '') : null;
|
|
12
|
-
|
|
13
|
-
if (Number.isNaN(value)) {
|
|
14
|
-
return false;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
if (min !== null && value < min) {
|
|
18
|
-
return false;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
if (max !== null && value > max) {
|
|
22
|
-
return false;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
return true;
|
|
26
|
-
},
|
|
27
|
-
message: ({ input, label, t }) => {
|
|
28
|
-
const min = input.hasAttribute('min') ? parseFloat(input.getAttribute('min') || '') : null;
|
|
29
|
-
const max = input.hasAttribute('max') ? parseFloat(input.getAttribute('max') || '') : null;
|
|
30
|
-
|
|
31
|
-
if (min !== null && max !== null) {
|
|
32
|
-
return t('{label} must be no less than {min}.', { label, min });
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
if (min !== null) {
|
|
36
|
-
return t('{label} must be no less than {min}.', { label, min });
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if (max !== null) {
|
|
40
|
-
return t('{label} must be no greater than {max}.', { label, max });
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
return t('{label} is not a valid number.', { label });
|
|
44
|
-
},
|
|
5
|
+
rule: ({ input }) => input.type !== 'number' || validateBrowserValue(input.value, bounds(input)) === null,
|
|
6
|
+
message: ({ input, label, t }) => validateBrowserValue(input.value, bounds(input), { label }) ?? t('{label} is not a valid number.', { label }),
|
|
45
7
|
};
|
|
46
|
-
|
|
47
8
|
export default minmax;
|
|
@@ -1,58 +1,14 @@
|
|
|
1
|
+
import { validateBrowserValue } from '@verbb/formie-core';
|
|
1
2
|
import type { ValidationRuleDefinition } from '#validation/types';
|
|
2
3
|
|
|
3
4
|
const number: ValidationRuleDefinition = {
|
|
4
5
|
rule: ({ input, getRule }) => {
|
|
5
6
|
const rule = getRule('number');
|
|
6
|
-
|
|
7
|
-
if (!rule || !input.value || input.value.trim() === '') {
|
|
8
|
-
return true;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const value = parseFloat(input.value);
|
|
12
|
-
|
|
13
|
-
if (Number.isNaN(value)) {
|
|
14
|
-
return false;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
if (rule !== true && typeof rule === 'object') {
|
|
18
|
-
const min = typeof rule.min === 'number' ? rule.min : null;
|
|
19
|
-
const max = typeof rule.max === 'number' ? rule.max : null;
|
|
20
|
-
|
|
21
|
-
if (min !== null && value < min) {
|
|
22
|
-
return false;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
if (max !== null && value > max) {
|
|
26
|
-
return false;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
return true;
|
|
7
|
+
return !rule || validateBrowserValue(input.value, { ...(typeof rule === 'object' ? rule : {}), type: 'number' }) === null;
|
|
31
8
|
},
|
|
32
9
|
message: ({ input, label, getRule, t }) => {
|
|
33
10
|
const rule = getRule('number');
|
|
34
|
-
|
|
35
|
-
const max = rule !== true && rule && typeof rule === 'object' && typeof rule.max === 'number' ? rule.max : null;
|
|
36
|
-
|
|
37
|
-
if (min !== null && max !== null) {
|
|
38
|
-
return input.getAttribute('data-formie-validation-number-min-message')
|
|
39
|
-
?? t('{label} must be no less than {min}.', { label, min });
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (min !== null) {
|
|
43
|
-
return input.getAttribute('data-formie-validation-number-min-message')
|
|
44
|
-
?? t('{label} must be no less than {min}.', { label, min });
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
if (max !== null) {
|
|
48
|
-
return input.getAttribute('data-formie-validation-number-max-message')
|
|
49
|
-
?? t('{label} must be no greater than {max}.', { label, max });
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return input.getAttribute('data-formie-validation-number-message')
|
|
53
|
-
?? input.getAttribute('data-formie-pattern-number-message')
|
|
54
|
-
?? input.getAttribute('data-pattern-number-message')
|
|
55
|
-
?? t('{label} is not a valid number.', { label });
|
|
11
|
+
return validateBrowserValue(input.value, { ...(typeof rule === 'object' ? rule : {}), type: 'number' }, { label }) ?? t('{label} is not a valid number.', { label });
|
|
56
12
|
},
|
|
57
13
|
};
|
|
58
14
|
|
|
@@ -1,15 +1,10 @@
|
|
|
1
|
+
import { validateBrowserValue } from '@verbb/formie-core';
|
|
1
2
|
import type { ValidationRuleDefinition } from '#validation/types';
|
|
2
3
|
|
|
3
4
|
const pattern: ValidationRuleDefinition = {
|
|
4
5
|
rule: ({ input, config }) => {
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
if (!patternToMatch || !input.value || input.value.length < 1) {
|
|
9
|
-
return true;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
return patternToMatch.test(input.value);
|
|
6
|
+
const pattern = input.getAttribute('pattern') || config.patterns[input.type];
|
|
7
|
+
return validateBrowserValue(input.value, { type: 'pattern', pattern }) === null;
|
|
13
8
|
},
|
|
14
9
|
message: ({ input, label, t }) => {
|
|
15
10
|
const messages = {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { validateBrowserValue } from '@verbb/formie-core';
|
|
1
2
|
import type { ValidationRuleDefinition } from '#validation/types';
|
|
2
3
|
|
|
3
4
|
const required: ValidationRuleDefinition = {
|
|
@@ -18,7 +19,7 @@ const required: ValidationRuleDefinition = {
|
|
|
18
19
|
return input instanceof HTMLInputElement ? input.checked : true;
|
|
19
20
|
}
|
|
20
21
|
|
|
21
|
-
return input.value
|
|
22
|
+
return validateBrowserValue(input.value, { type: 'required' }) === null;
|
|
22
23
|
},
|
|
23
24
|
message: ({ input, label, t }) => {
|
|
24
25
|
return input.getAttribute('data-formie-required-message')
|