@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,7 +1,6 @@
|
|
|
1
1
|
import type { FormEventUnsubscribe } from '#contracts/client';
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
4
|
-
import type { FormModuleManifest } from '#contracts/schema';
|
|
2
|
+
import type { BrowserModuleDefinition, BrowserModuleHydrationReport, ModuleRegistrationOptions } from '#contracts/modules';
|
|
3
|
+
import type { BrowserModuleEntry } from '#contracts/schema';
|
|
5
4
|
import { EventBus } from '#events/event-bus';
|
|
6
5
|
import { loadModulesFromManifest } from '#modules/loader';
|
|
7
6
|
import { ModuleRegistry } from '#modules/registry';
|
|
@@ -10,34 +9,38 @@ import { createDebug } from '#utils/debug';
|
|
|
10
9
|
export type FormieModuleHydratorOptions = {
|
|
11
10
|
root: Element;
|
|
12
11
|
form?: HTMLFormElement | null;
|
|
13
|
-
modules?:
|
|
14
|
-
|
|
12
|
+
modules?: import('@verbb/formie-core').BrowserModuleManifest;
|
|
13
|
+
surface?: import('@verbb/formie-core').BrowserSurface;
|
|
15
14
|
registry?: ModuleRegistry;
|
|
16
15
|
};
|
|
17
16
|
|
|
18
|
-
export type FormieModuleHydrator = {
|
|
17
|
+
export type FormieModuleHydrator = BrowserModuleHydrationReport & {
|
|
18
|
+
assertReady: () => void;
|
|
19
|
+
prepare: (action: import('@verbb/formie-core').ClientSubmitAction) => Promise<Record<string, unknown>>;
|
|
20
|
+
result: (result: import('#contracts/schema').FormSubmitResult) => Promise<void>;
|
|
21
|
+
update: (manifest: import('@verbb/formie-core').BrowserModuleManifest) => Promise<void>;
|
|
19
22
|
destroy: () => Promise<void>;
|
|
20
23
|
on: (eventName: string, callback: (payload: unknown) => void | Promise<void>) => FormEventUnsubscribe;
|
|
21
24
|
emit: (eventName: string, payload?: unknown) => Promise<void>;
|
|
22
|
-
registerModule: (moduleDefinition:
|
|
25
|
+
registerModule: (moduleDefinition: BrowserModuleDefinition, options?: ModuleRegistrationOptions) => boolean;
|
|
23
26
|
unregisterModule: (moduleId: string) => void;
|
|
24
|
-
getRegisteredModules: () =>
|
|
27
|
+
getRegisteredModules: () => BrowserModuleDefinition[];
|
|
25
28
|
};
|
|
26
29
|
|
|
27
30
|
const debug = createDebug('general', 'module-hydrator');
|
|
28
31
|
|
|
29
32
|
export async function hydrateFormieModules(options: FormieModuleHydratorOptions): Promise<FormieModuleHydrator> {
|
|
30
33
|
const root = options.root;
|
|
31
|
-
const form = options.form ?? (root instanceof HTMLFormElement ? root : root.closest('form'));
|
|
32
|
-
const
|
|
33
|
-
const
|
|
34
|
+
const form = options.form ?? (root instanceof HTMLFormElement ? root : root.closest('form') ?? root.querySelector('form'));
|
|
35
|
+
const surface = options.surface ?? 'cp-edit';
|
|
36
|
+
const modules = options.modules ?? { contractVersion: 2, surface, entries: [] };
|
|
34
37
|
const registry = options.registry ?? new ModuleRegistry();
|
|
35
38
|
const bus = new EventBus();
|
|
36
39
|
|
|
37
40
|
// This helper reuses the canonical module manifest loader without mounting the
|
|
38
|
-
// full form client, which lets
|
|
41
|
+
// full form client, which lets CP edit hosts opt into shared
|
|
39
42
|
// field modules without inheriting submit or pagination ownership.
|
|
40
|
-
const
|
|
43
|
+
const runtime = await loadModulesFromManifest(modules, {
|
|
41
44
|
registry,
|
|
42
45
|
setupContext: {
|
|
43
46
|
formId: form?.id || (root as HTMLElement).id || 'formie-modules',
|
|
@@ -45,31 +48,64 @@ export async function hydrateFormieModules(options: FormieModuleHydratorOptions)
|
|
|
45
48
|
form,
|
|
46
49
|
target: root,
|
|
47
50
|
scope: 'form',
|
|
51
|
+
surface,
|
|
48
52
|
state: {},
|
|
49
53
|
options: {},
|
|
50
54
|
on: (eventName, callback) => {
|
|
51
55
|
return bus.on(eventName, callback);
|
|
52
56
|
},
|
|
53
57
|
emit: async(eventName, payload) => {
|
|
58
|
+
root.dispatchEvent(new CustomEvent(eventName, { detail: payload, bubbles: true }));
|
|
54
59
|
await bus.emit(eventName, payload);
|
|
55
60
|
},
|
|
56
61
|
},
|
|
57
62
|
matchContext: {
|
|
58
63
|
root,
|
|
59
64
|
form,
|
|
60
|
-
|
|
65
|
+
surface,
|
|
61
66
|
},
|
|
62
67
|
});
|
|
63
68
|
|
|
64
69
|
debug.log('Hydrated module manifest.', {
|
|
65
|
-
moduleCount: modules.length,
|
|
66
|
-
instanceCount: instances.length,
|
|
67
|
-
|
|
70
|
+
moduleCount: modules.entries.length,
|
|
71
|
+
instanceCount: runtime.instances.length,
|
|
72
|
+
surface,
|
|
68
73
|
});
|
|
69
74
|
|
|
70
75
|
return {
|
|
76
|
+
get instances() { return runtime.instances; },
|
|
77
|
+
get failures() { return runtime.failures; },
|
|
78
|
+
prepare: async(action) => {
|
|
79
|
+
if (!form) throw new Error('Browser modules require a mounted form element.');
|
|
80
|
+
runtime.assertReady();
|
|
81
|
+
runtime.instances.forEach((instance) => instance.assertReady?.());
|
|
82
|
+
let reason: string | undefined;
|
|
83
|
+
const context = {
|
|
84
|
+
form, action: action === 'back' || action === 'save' ? action : 'submit' as const,
|
|
85
|
+
formData: new FormData(form),
|
|
86
|
+
abort: (message?: string) => { reason = message || 'A form feature could not complete.'; },
|
|
87
|
+
isAborted: () => Boolean(reason), abortReason: () => reason,
|
|
88
|
+
};
|
|
89
|
+
const priority = { core: 0, field: 0, address: 0, captcha: 1, payment: 2 };
|
|
90
|
+
for (const instance of [...runtime.instances].sort((a, b) => priority[a.kind ?? 'core'] - priority[b.kind ?? 'core'])) {
|
|
91
|
+
await instance.beforeSubmit?.(context);
|
|
92
|
+
if (reason) throw new Error(reason);
|
|
93
|
+
}
|
|
94
|
+
// Only transient module inputs cross this seam. PHP reads CAPTCHA data
|
|
95
|
+
// and payment fields without allowing arbitrary request/authority overrides.
|
|
96
|
+
return Object.fromEntries(Array.from(form.querySelectorAll<HTMLInputElement>('input[type="hidden"][name]')).map((input) => [input.name, input.value]));
|
|
97
|
+
},
|
|
98
|
+
result: async(result) => {
|
|
99
|
+
if (!form) return;
|
|
100
|
+
const context = { form, action: result.action ?? 'submit' as const, formData: new FormData(form) };
|
|
101
|
+
await bus.emit('formie:submit:result', result);
|
|
102
|
+
for (const instance of runtime.instances) await instance.afterSubmit?.(context, result);
|
|
103
|
+
form.dispatchEvent(new CustomEvent('formie:submit:result', { detail: result, bubbles: true }));
|
|
104
|
+
},
|
|
105
|
+
update: (manifest) => runtime.updateManifest(manifest),
|
|
106
|
+
assertReady: () => { runtime.assertReady(); runtime.instances.forEach((instance) => instance.assertReady?.()); },
|
|
71
107
|
destroy: async() => {
|
|
72
|
-
await
|
|
108
|
+
await runtime.destroy();
|
|
73
109
|
bus.clear();
|
|
74
110
|
},
|
|
75
111
|
on: (eventName, callback) => {
|
|
@@ -89,14 +125,3 @@ export async function hydrateFormieModules(options: FormieModuleHydratorOptions)
|
|
|
89
125
|
},
|
|
90
126
|
};
|
|
91
127
|
}
|
|
92
|
-
|
|
93
|
-
async function destroyModuleInstances(instances: FormieModuleInstance[]): Promise<void> {
|
|
94
|
-
for (const instance of instances) {
|
|
95
|
-
try {
|
|
96
|
-
await instance.destroy();
|
|
97
|
-
} catch (error) {
|
|
98
|
-
console.error('[formie] Failed to destroy module instance.', error);
|
|
99
|
-
debug.warn('Failed destroying module instance.', { error });
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
@@ -99,22 +99,17 @@ function getProgressState(progress: number): 'start' | 'middle' | 'end' {
|
|
|
99
99
|
return 'middle';
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
function
|
|
103
|
-
return (form.dataset.formieSubmitAction || '').trim();
|
|
102
|
+
function getConfiguredCompletionBehavior(form: HTMLFormElement): string {
|
|
103
|
+
return (form.dataset.formieCompletionBehavior || form.dataset.formieSubmitAction || '').trim();
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
function
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if (typeof fromResponse === 'string' && fromResponse.trim() !== '') {
|
|
110
|
-
return fromResponse.trim();
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
return getConfiguredSubmitAction(form);
|
|
106
|
+
function getResolvedCompletionBehavior(form: HTMLFormElement, result: FormSubmitResult): string {
|
|
107
|
+
if (result.completion) return String(result.completion.behavior);
|
|
108
|
+
return getConfiguredCompletionBehavior(form);
|
|
114
109
|
}
|
|
115
110
|
|
|
116
111
|
function shouldHideFormOnSuccess(form: HTMLFormElement): boolean {
|
|
117
|
-
const rawValue = form.dataset.formieSubmitActionFormHide;
|
|
112
|
+
const rawValue = form.dataset.formieHideFormAfterSubmit ?? form.dataset.formieSubmitActionFormHide;
|
|
118
113
|
|
|
119
114
|
if (rawValue === undefined) {
|
|
120
115
|
return false;
|
|
@@ -199,7 +194,7 @@ function applyCompletedProgressState(form: HTMLFormElement): void {
|
|
|
199
194
|
|
|
200
195
|
function scheduleFinalSubmitReset(form: HTMLFormElement): void {
|
|
201
196
|
clearPendingFinalSubmitReset(form);
|
|
202
|
-
const preserveHiddenState =
|
|
197
|
+
const preserveHiddenState = getConfiguredCompletionBehavior(form) === 'message' && shouldHideFormOnSuccess(form);
|
|
203
198
|
|
|
204
199
|
if (DEFAULT_FINAL_SUBMIT_RESET_DELAY_MS < 1) {
|
|
205
200
|
resetSubmissionState(form, { preserveHiddenState });
|
|
@@ -300,12 +295,10 @@ export function clearSubmitLoading(form: HTMLFormElement): void {
|
|
|
300
295
|
button.removeAttribute('data-formie-loading-text');
|
|
301
296
|
});
|
|
302
297
|
|
|
303
|
-
|
|
304
|
-
const formWithValidation = form as FormWithValidationApi;
|
|
298
|
+
const formWithValidation = form as FormWithValidationApi;
|
|
305
299
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
}
|
|
300
|
+
if (formWithValidation.formieValidation) {
|
|
301
|
+
syncSubmitReadiness(form, formWithValidation.formieValidation);
|
|
309
302
|
}
|
|
310
303
|
}
|
|
311
304
|
|
|
@@ -370,27 +363,30 @@ export function applyPageState(form: HTMLFormElement, nextPageId: string): void
|
|
|
370
363
|
setHiddenInputValue(form, 'pageId', nextPageId);
|
|
371
364
|
syncPageTabErrors(form);
|
|
372
365
|
|
|
373
|
-
|
|
374
|
-
const formWithValidation = form as FormWithValidationApi;
|
|
366
|
+
const formWithValidation = form as FormWithValidationApi;
|
|
375
367
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
}
|
|
368
|
+
if (formWithValidation.formieValidation) {
|
|
369
|
+
syncSubmitReadiness(form, formWithValidation.formieValidation);
|
|
379
370
|
}
|
|
380
371
|
}
|
|
381
372
|
|
|
382
373
|
function syncSubmissionIdentity(form: HTMLFormElement, result: FormSubmitResult): void {
|
|
374
|
+
const session = result.meta?.session as { version?: number } | undefined;
|
|
375
|
+
const version = session?.version ?? result.meta?.version;
|
|
376
|
+
if (typeof version === 'number') {
|
|
377
|
+
setHiddenInputValue(form, 'expectedVersion', String(version));
|
|
378
|
+
}
|
|
383
379
|
const submissionUid = result.meta?.submissionUid;
|
|
384
380
|
if (typeof submissionUid === 'string' && submissionUid.trim() !== '') {
|
|
385
381
|
setHiddenInputValue(form, 'submissionUid', submissionUid);
|
|
386
382
|
}
|
|
387
383
|
|
|
388
|
-
const
|
|
389
|
-
?.continuation?.
|
|
390
|
-
if (typeof
|
|
391
|
-
setHiddenInputValue(form, '
|
|
384
|
+
const progressId = (result.meta?.session as { continuation?: { progressId?: unknown } } | undefined)
|
|
385
|
+
?.continuation?.progressId;
|
|
386
|
+
if (typeof progressId === 'string' && progressId.trim() !== '') {
|
|
387
|
+
setHiddenInputValue(form, 'progressId', progressId);
|
|
392
388
|
} else {
|
|
393
|
-
removeHiddenInput(form, '
|
|
389
|
+
removeHiddenInput(form, 'progressId');
|
|
394
390
|
}
|
|
395
391
|
}
|
|
396
392
|
|
|
@@ -457,8 +453,9 @@ function resetSubmissionState(form: HTMLFormElement, options: ResetSubmissionSta
|
|
|
457
453
|
setFormHiddenState(form, false);
|
|
458
454
|
}
|
|
459
455
|
removeHiddenInput(form, 'submissionId');
|
|
456
|
+
setHiddenInputValue(form, 'expectedVersion', '0');
|
|
460
457
|
removeHiddenInput(form, 'submissionUid');
|
|
461
|
-
removeHiddenInput(form, '
|
|
458
|
+
removeHiddenInput(form, 'progressId');
|
|
462
459
|
removeHiddenInput(form, 'pageId');
|
|
463
460
|
clearResumeTokenState(form);
|
|
464
461
|
validator?.resetLiveState();
|
|
@@ -508,15 +505,7 @@ function dispatchSubmitDataEvents(form: HTMLFormElement, result: FormSubmitResul
|
|
|
508
505
|
}
|
|
509
506
|
}
|
|
510
507
|
|
|
511
|
-
|
|
512
|
-
// as `paymentAction`/`paymentDecision` metadata without submitData entries.
|
|
513
|
-
const meta = (result.meta || {}) as Record<string, unknown>;
|
|
514
|
-
const paymentAction = (
|
|
515
|
-
(meta.paymentAction && typeof meta.paymentAction === 'object' ? meta.paymentAction : null)
|
|
516
|
-
|| (meta.paymentDecision && typeof meta.paymentDecision === 'object'
|
|
517
|
-
? ((meta.paymentDecision as Record<string, unknown>).action as Record<string, unknown> | null)
|
|
518
|
-
: null)
|
|
519
|
-
) as Record<string, unknown> | null;
|
|
508
|
+
const paymentAction = result.payment?.action;
|
|
520
509
|
|
|
521
510
|
const actionEvent = paymentAction ? String(paymentAction.event || '') : '';
|
|
522
511
|
const actionPayload = paymentAction ? paymentAction.payload : undefined;
|
|
@@ -564,7 +553,7 @@ export function applySubmitResultState(form: HTMLFormElement, result: FormSubmit
|
|
|
564
553
|
});
|
|
565
554
|
clearPendingFinalSubmitReset(form);
|
|
566
555
|
if (result.redirect.target === 'new-tab') {
|
|
567
|
-
window.open(result.redirect.url, '_blank');
|
|
556
|
+
window.open(result.redirect.url, '_blank', 'noopener,noreferrer');
|
|
568
557
|
} else {
|
|
569
558
|
markInternalNavigation(form, 'redirect');
|
|
570
559
|
window.location.href = result.redirect.url;
|
|
@@ -609,18 +598,18 @@ export function applySubmitResultState(form: HTMLFormElement, result: FormSubmit
|
|
|
609
598
|
return;
|
|
610
599
|
}
|
|
611
600
|
|
|
612
|
-
if (action === 'submit' && !result.redirect?.url) {
|
|
613
|
-
const
|
|
614
|
-
const preserveHiddenState =
|
|
601
|
+
if (result.completion && action === 'submit' && !result.redirect?.url) {
|
|
602
|
+
const completionBehavior = getResolvedCompletionBehavior(form, result);
|
|
603
|
+
const preserveHiddenState = completionBehavior === 'message' && shouldHideFormOnSuccess(form);
|
|
615
604
|
|
|
616
|
-
if (
|
|
605
|
+
if (completionBehavior === 'reload') {
|
|
617
606
|
clearPendingFinalSubmitReset(form);
|
|
618
607
|
markInternalNavigation(form, 'reload');
|
|
619
608
|
window.location.reload();
|
|
620
609
|
return;
|
|
621
610
|
}
|
|
622
611
|
|
|
623
|
-
if (
|
|
612
|
+
if (completionBehavior === 'reset') {
|
|
624
613
|
resetSubmissionState(form);
|
|
625
614
|
return;
|
|
626
615
|
}
|
|
@@ -633,8 +622,8 @@ export function applySubmitResultState(form: HTMLFormElement, result: FormSubmit
|
|
|
633
622
|
}
|
|
634
623
|
|
|
635
624
|
if (action === 'submit' && result.redirect?.url && result.redirect.target === 'new-tab') {
|
|
636
|
-
const
|
|
637
|
-
const preserveHiddenState =
|
|
625
|
+
const completionBehavior = getResolvedCompletionBehavior(form, result);
|
|
626
|
+
const preserveHiddenState = completionBehavior === 'message' && shouldHideFormOnSuccess(form);
|
|
638
627
|
clearPendingFinalSubmitReset(form);
|
|
639
628
|
resetSubmissionState(form, { preserveHiddenState });
|
|
640
629
|
return;
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import type { FormSubmitResult } from '#contracts/schema';
|
|
2
2
|
import { applyErrorAriaLive, getErrorAriaLivePreference, resolveSubmitErrorAriaLive } from '#core/error-aria-live';
|
|
3
|
+
import {
|
|
4
|
+
appendDescribedBy,
|
|
5
|
+
clearFieldErrorAria,
|
|
6
|
+
setErrorMessageReference,
|
|
7
|
+
} from '#core/field-error-aria';
|
|
3
8
|
import { ensureFieldErrorContainer as resolveFieldErrorContainer } from '#core/field-error-container';
|
|
4
9
|
import { syncPageTabErrors } from '#core/page-tab-errors';
|
|
5
10
|
import { focusFirstValidationError } from '#core/validation-focus';
|
|
@@ -8,8 +13,8 @@ import { addThemeClasses, removeThemeClasses } from '#theme/theme-classes';
|
|
|
8
13
|
|
|
9
14
|
const successHideTimers = new WeakMap<HTMLFormElement, number>();
|
|
10
15
|
|
|
11
|
-
function
|
|
12
|
-
return (form.dataset.formieSubmitAction || '').trim();
|
|
16
|
+
function getConfiguredCompletionBehavior(form: HTMLFormElement): string {
|
|
17
|
+
return (form.dataset.formieCompletionBehavior || form.dataset.formieSubmitAction || '').trim();
|
|
13
18
|
}
|
|
14
19
|
|
|
15
20
|
function getErrorMessagePosition(form: HTMLFormElement): string {
|
|
@@ -17,11 +22,11 @@ function getErrorMessagePosition(form: HTMLFormElement): string {
|
|
|
17
22
|
}
|
|
18
23
|
|
|
19
24
|
function getSuccessMessagePosition(form: HTMLFormElement): string {
|
|
20
|
-
return (form.dataset.formieSubmitActionMessagePosition || '').trim();
|
|
25
|
+
return (form.dataset.formieSuccessMessagePosition || form.dataset.formieSubmitActionMessagePosition || '').trim();
|
|
21
26
|
}
|
|
22
27
|
|
|
23
28
|
function getSuccessMessageTimeoutMs(form: HTMLFormElement): number | null {
|
|
24
|
-
const rawValue = (form.dataset.formieSubmitActionMessageTimeout || '').trim();
|
|
29
|
+
const rawValue = (form.dataset.formieSuccessMessageTimeout || form.dataset.formieSubmitActionMessageTimeout || '').trim();
|
|
25
30
|
|
|
26
31
|
if (!rawValue) {
|
|
27
32
|
return null;
|
|
@@ -37,7 +42,7 @@ function getSuccessMessageTimeoutMs(form: HTMLFormElement): number | null {
|
|
|
37
42
|
}
|
|
38
43
|
|
|
39
44
|
function shouldHideFormOnSuccess(form: HTMLFormElement): boolean {
|
|
40
|
-
const rawValue = form.dataset.formieSubmitActionFormHide;
|
|
45
|
+
const rawValue = form.dataset.formieHideFormAfterSubmit ?? form.dataset.formieSubmitActionFormHide;
|
|
41
46
|
|
|
42
47
|
if (rawValue === undefined) {
|
|
43
48
|
return false;
|
|
@@ -160,40 +165,10 @@ function ensureFieldErrorContainer(fieldNode: Element): HTMLElement {
|
|
|
160
165
|
});
|
|
161
166
|
}
|
|
162
167
|
|
|
163
|
-
function removeDescribedBy(input: HTMLElement, describedById: string): void {
|
|
164
|
-
const current = (input.getAttribute('aria-describedby') || '').trim();
|
|
165
|
-
|
|
166
|
-
if (!current) {
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
const nextValue = current.split(/\s+/).filter((item) => {
|
|
171
|
-
return item !== describedById;
|
|
172
|
-
}).join(' ').trim();
|
|
173
|
-
|
|
174
|
-
if (nextValue) {
|
|
175
|
-
input.setAttribute('aria-describedby', nextValue);
|
|
176
|
-
return;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
input.removeAttribute('aria-describedby');
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
function setErrorMessageReference(input: HTMLElement, errorMessageId: string): void {
|
|
183
|
-
input.setAttribute('aria-errormessage', errorMessageId);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
function clearErrorMessageReference(input: HTMLElement, errorMessageId: string): void {
|
|
187
|
-
if (input.getAttribute('aria-errormessage') === errorMessageId) {
|
|
188
|
-
input.removeAttribute('aria-errormessage');
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
168
|
export function clearFieldErrors(form: HTMLFormElement): void {
|
|
193
169
|
form.querySelectorAll('[data-formie-field-handle]').forEach((fieldNode) => {
|
|
194
170
|
const fieldElement = fieldNode as HTMLElement;
|
|
195
171
|
const container = fieldElement.querySelector('[data-formie-field-errors]') as HTMLElement | null;
|
|
196
|
-
const containerId = container?.id || '';
|
|
197
172
|
const errorMessageIds = Array.from(fieldElement.querySelectorAll('[data-formie-field-error]')).map((node) => {
|
|
198
173
|
return (node as HTMLElement).id;
|
|
199
174
|
}).filter(Boolean);
|
|
@@ -214,14 +189,7 @@ export function clearFieldErrors(form: HTMLFormElement): void {
|
|
|
214
189
|
element.removeAttribute('aria-invalid');
|
|
215
190
|
removeThemeClasses(element, form, 'fieldControlError');
|
|
216
191
|
element.removeAttribute('data-formie-input-has-error');
|
|
217
|
-
|
|
218
|
-
if (containerId) {
|
|
219
|
-
removeDescribedBy(element, containerId);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
errorMessageIds.forEach((errorMessageId) => {
|
|
223
|
-
clearErrorMessageReference(element, errorMessageId);
|
|
224
|
-
});
|
|
192
|
+
clearFieldErrorAria(element, errorMessageIds);
|
|
225
193
|
});
|
|
226
194
|
});
|
|
227
195
|
|
|
@@ -275,7 +243,7 @@ export function clearFormSuccess(form: HTMLFormElement): void {
|
|
|
275
243
|
}
|
|
276
244
|
});
|
|
277
245
|
|
|
278
|
-
if (!(
|
|
246
|
+
if (!(getConfiguredCompletionBehavior(form) === 'message' && shouldHideFormOnSuccess(form))) {
|
|
279
247
|
setFormHiddenState(form, false);
|
|
280
248
|
}
|
|
281
249
|
}
|
|
@@ -286,22 +254,13 @@ export function clearAriaInvalid(form: HTMLFormElement): void {
|
|
|
286
254
|
});
|
|
287
255
|
}
|
|
288
256
|
|
|
289
|
-
function appendDescribedBy(input: HTMLElement, describedById: string): void {
|
|
290
|
-
const current = (input.getAttribute('aria-describedby') || '').trim();
|
|
291
|
-
const items = current ? current.split(/\s+/) : [];
|
|
292
|
-
|
|
293
|
-
if (!items.includes(describedById)) {
|
|
294
|
-
items.push(describedById);
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
input.setAttribute('aria-describedby', items.join(' ').trim());
|
|
298
|
-
}
|
|
299
|
-
|
|
300
257
|
export function renderFieldErrors(form: HTMLFormElement, fieldErrors: Record<string, string[]>): void {
|
|
301
258
|
const errorAriaLive = resolveSubmitErrorAriaLive(getErrorAriaLivePreference(form));
|
|
302
259
|
|
|
303
260
|
Object.entries(fieldErrors).forEach(([handle, messages]) => {
|
|
304
|
-
const
|
|
261
|
+
const inputName = `fields[${handle.split('.').join('][')}]`;
|
|
262
|
+
const exactInput = form.querySelector(`[name="${CSS.escape(inputName)}"], [name="${CSS.escape(inputName + '[]')}"]`);
|
|
263
|
+
const fieldNode = exactInput?.closest('[data-formie-field-handle]') || form.querySelector(`[data-formie-field-handle="${CSS.escape(handle)}"]`);
|
|
305
264
|
|
|
306
265
|
if (!fieldNode) {
|
|
307
266
|
return;
|
|
@@ -319,7 +278,6 @@ export function renderFieldErrors(form: HTMLFormElement, fieldErrors: Record<str
|
|
|
319
278
|
messages.forEach((message, index) => {
|
|
320
279
|
const errorNode = document.createElement('div');
|
|
321
280
|
errorNode.setAttribute('data-formie-field-error', 'true');
|
|
322
|
-
errorNode.setAttribute('role', 'alert');
|
|
323
281
|
errorNode.id = `${containerId}-${index + 1}`;
|
|
324
282
|
addThemeClasses(errorNode, form, 'fieldError');
|
|
325
283
|
errorNode.textContent = message;
|
|
@@ -327,7 +285,8 @@ export function renderFieldErrors(form: HTMLFormElement, fieldErrors: Record<str
|
|
|
327
285
|
});
|
|
328
286
|
|
|
329
287
|
// Point every control in the field at the first rendered message while
|
|
330
|
-
// still rendering the full list for visual output.
|
|
288
|
+
// still rendering the full list for visual output. Pair aria-errormessage
|
|
289
|
+
// with aria-describedby on that message id (#2946).
|
|
331
290
|
const primaryErrorId = (container.querySelector('[data-formie-field-error]') as HTMLElement | null)?.id;
|
|
332
291
|
|
|
333
292
|
fieldNode.querySelectorAll('input, select, textarea').forEach((input) => {
|
|
@@ -335,7 +294,6 @@ export function renderFieldErrors(form: HTMLFormElement, fieldErrors: Record<str
|
|
|
335
294
|
element.setAttribute('aria-invalid', 'true');
|
|
336
295
|
addThemeClasses(element, form, 'fieldControlError');
|
|
337
296
|
element.setAttribute('data-formie-input-has-error', 'true');
|
|
338
|
-
appendDescribedBy(element, containerId);
|
|
339
297
|
|
|
340
298
|
if (primaryErrorId) {
|
|
341
299
|
setErrorMessageReference(element, primaryErrorId);
|
|
@@ -372,10 +330,9 @@ function isPaymentFollowUpResult(result: FormSubmitResult): boolean {
|
|
|
372
330
|
return false;
|
|
373
331
|
}
|
|
374
332
|
|
|
375
|
-
const
|
|
376
|
-
const paymentStatus = String(meta.paymentStatus || '');
|
|
333
|
+
const paymentStatus = result.payment?.status;
|
|
377
334
|
|
|
378
|
-
return paymentStatus === '
|
|
335
|
+
return paymentStatus === 'requiresAction' || paymentStatus === 'pending' || paymentStatus === 'unknown';
|
|
379
336
|
}
|
|
380
337
|
|
|
381
338
|
export function renderFormNotice(form: HTMLFormElement, message: string): void {
|
|
@@ -403,7 +360,7 @@ function shouldRenderSuccessMessage(form: HTMLFormElement, result: FormSubmitRes
|
|
|
403
360
|
return true;
|
|
404
361
|
}
|
|
405
362
|
|
|
406
|
-
return
|
|
363
|
+
return getConfiguredCompletionBehavior(form) === 'message' && getSuccessMessagePosition(form) !== '';
|
|
407
364
|
}
|
|
408
365
|
|
|
409
366
|
export function renderFormSuccess(form: HTMLFormElement, message: string): void {
|
|
@@ -459,8 +416,7 @@ export function applySubmitResultUi(form: HTMLFormElement, result: FormSubmitRes
|
|
|
459
416
|
|
|
460
417
|
if (!result.ok) {
|
|
461
418
|
if (isPaymentFollowUpResult(result)) {
|
|
462
|
-
const
|
|
463
|
-
const message = String(meta.paymentMessage || '').trim();
|
|
419
|
+
const message = String(result.payment?.message || '').trim();
|
|
464
420
|
|
|
465
421
|
if (message) {
|
|
466
422
|
renderFormNotice(form, message);
|
|
@@ -1,15 +1,6 @@
|
|
|
1
|
+
import { appendDescribedBy, setErrorMessageReference } from '#core/field-error-aria';
|
|
1
2
|
import { addThemeClasses } from '#theme/theme-classes';
|
|
2
|
-
|
|
3
|
-
function appendDescribedBy(input: HTMLElement, describedById: string): void {
|
|
4
|
-
const current = (input.getAttribute('aria-describedby') || '').trim();
|
|
5
|
-
const items = current ? current.split(/\s+/) : [];
|
|
6
|
-
|
|
7
|
-
if (!items.includes(describedById)) {
|
|
8
|
-
items.push(describedById);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
input.setAttribute('aria-describedby', items.join(' ').trim());
|
|
12
|
-
}
|
|
3
|
+
import { isValidationSkipped } from '#validation/skip';
|
|
13
4
|
|
|
14
5
|
function getFirstErroredField(form: HTMLFormElement): HTMLElement | null {
|
|
15
6
|
const fields = Array.from(form.querySelectorAll('[data-formie-field-handle]')) as HTMLElement[];
|
|
@@ -24,15 +15,19 @@ function getFirstErroredField(form: HTMLFormElement): HTMLElement | null {
|
|
|
24
15
|
}
|
|
25
16
|
|
|
26
17
|
function getFieldFocusTarget(field: HTMLElement): HTMLElement | null {
|
|
27
|
-
const invalidControl = field.
|
|
18
|
+
const invalidControl = Array.from(field.querySelectorAll('[aria-invalid="true"]')).find((node) => {
|
|
19
|
+
return !isValidationSkipped(node);
|
|
20
|
+
}) as HTMLElement | undefined;
|
|
28
21
|
|
|
29
22
|
if (invalidControl) {
|
|
30
23
|
return invalidControl;
|
|
31
24
|
}
|
|
32
25
|
|
|
33
|
-
return field.
|
|
26
|
+
return Array.from(field.querySelectorAll(
|
|
34
27
|
'input:not([type="hidden"]):not([disabled]), select:not([disabled]), textarea:not([disabled])',
|
|
35
|
-
)
|
|
28
|
+
)).find((node) => {
|
|
29
|
+
return !isValidationSkipped(node);
|
|
30
|
+
}) as HTMLElement | undefined ?? null;
|
|
36
31
|
}
|
|
37
32
|
|
|
38
33
|
function getFormLevelErrorTarget(form: HTMLFormElement): HTMLElement | null {
|
|
@@ -54,23 +49,28 @@ export function enhanceServerRenderedFieldErrors(form: HTMLFormElement): void {
|
|
|
54
49
|
field.setAttribute('data-formie-field-has-error', 'true');
|
|
55
50
|
addThemeClasses(field, form, 'fieldLayoutError');
|
|
56
51
|
|
|
57
|
-
const errorContainer = field.querySelector('[data-formie-field-errors]') as HTMLElement | null;
|
|
58
|
-
const errorContainerId = errorContainer?.id || '';
|
|
59
52
|
const primaryError = field.querySelector('[data-formie-field-error]') as HTMLElement | null;
|
|
60
53
|
const primaryErrorId = primaryError?.id || '';
|
|
61
54
|
|
|
62
55
|
field.querySelectorAll('input, select, textarea').forEach((input) => {
|
|
63
56
|
const element = input as HTMLElement;
|
|
57
|
+
|
|
58
|
+
if (isValidationSkipped(element)) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
64
62
|
element.setAttribute('aria-invalid', 'true');
|
|
65
63
|
addThemeClasses(element, form, 'fieldControlError');
|
|
66
64
|
element.setAttribute('data-formie-input-has-error', 'true');
|
|
67
65
|
|
|
68
|
-
if (
|
|
69
|
-
|
|
66
|
+
if (primaryErrorId) {
|
|
67
|
+
// Pair aria-errormessage + aria-describedby on the message id (#2946).
|
|
68
|
+
setErrorMessageReference(element, primaryErrorId);
|
|
70
69
|
}
|
|
71
70
|
|
|
72
|
-
|
|
73
|
-
|
|
71
|
+
const instructions = field.querySelector('[data-formie-instructions]') as HTMLElement | null;
|
|
72
|
+
if (instructions?.id) {
|
|
73
|
+
appendDescribedBy(element, instructions.id);
|
|
74
74
|
}
|
|
75
75
|
});
|
|
76
76
|
});
|
|
@@ -28,7 +28,7 @@ export const addressFinderModule = defineAddressModule<
|
|
|
28
28
|
AddressFinderGlobal,
|
|
29
29
|
AddressFinderWidget
|
|
30
30
|
>({
|
|
31
|
-
|
|
31
|
+
moduleId: 'formie:address-finder',
|
|
32
32
|
load: async () => {
|
|
33
33
|
return loadScriptAndEnsureGlobal<AddressFinderGlobal>('AddressFinder', {
|
|
34
34
|
id: SCRIPT_ID,
|