@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
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
// invisible/score flows is that we never trigger execution ourselves; the user
|
|
12
12
|
// must solve the already-rendered widget before submit succeeds.
|
|
13
13
|
export const recaptchaV2CheckboxModule = defineCaptchaModule<RecaptchaProviderOptions, RecaptchaGlobal, number | string>({
|
|
14
|
-
|
|
14
|
+
moduleId: 'formie:recaptcha-v2-checkbox',
|
|
15
15
|
defaultPlaceholderSelector: '[data-recaptcha-placeholder]',
|
|
16
16
|
defaultTokenFieldNames: ['g-recaptcha-response'],
|
|
17
17
|
load: ({ options }) => {
|
|
@@ -29,7 +29,7 @@ export const recaptchaV2CheckboxModule = defineCaptchaModule<RecaptchaProviderOp
|
|
|
29
29
|
callback: (token?: string) => {
|
|
30
30
|
// Checkbox mode solves interactively before submit, so
|
|
31
31
|
// the callback is the point where the transport layer
|
|
32
|
-
// finally becomes "
|
|
32
|
+
// finally becomes "challenge-stage ready".
|
|
33
33
|
if (typeof token === 'string' && token.trim() !== '') {
|
|
34
34
|
services.tokens.write(token.trim());
|
|
35
35
|
}
|
|
@@ -47,7 +47,7 @@ export const recaptchaV2CheckboxModule = defineCaptchaModule<RecaptchaProviderOp
|
|
|
47
47
|
});
|
|
48
48
|
});
|
|
49
49
|
},
|
|
50
|
-
|
|
50
|
+
challenge: ({ placeholder, services, stageCtx }) => {
|
|
51
51
|
// Checkbox mode does not execute at submit time. We simply check if the
|
|
52
52
|
// user already solved it; if not, abort immediately with a field-style
|
|
53
53
|
// error and let the user interact with the widget.
|
|
@@ -35,7 +35,7 @@ async function waitForRecaptchaResponse(api: RecaptchaGlobal, widgetId: number |
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
export const recaptchaV2InvisibleModule = defineCaptchaModule<RecaptchaProviderOptions, RecaptchaGlobal, RecaptchaWidgetState>({
|
|
38
|
-
|
|
38
|
+
moduleId: 'formie:recaptcha-v2-invisible',
|
|
39
39
|
defaultPlaceholderSelector: '[data-recaptcha-placeholder]',
|
|
40
40
|
defaultTokenFieldNames: ['g-recaptcha-response'],
|
|
41
41
|
load: ({ options }) => {
|
|
@@ -79,7 +79,7 @@ export const recaptchaV2InvisibleModule = defineCaptchaModule<RecaptchaProviderO
|
|
|
79
79
|
});
|
|
80
80
|
});
|
|
81
81
|
},
|
|
82
|
-
|
|
82
|
+
challenge: async({ api, widget, placeholder, services, stageCtx }) => {
|
|
83
83
|
// If we already have a token, do not re-execute the invisible widget.
|
|
84
84
|
if (services.tokens.has()) {
|
|
85
85
|
return;
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
// instance so it can participate in the same submit lifecycle as other
|
|
14
14
|
// providers, but most of the work happens at screen time.
|
|
15
15
|
export const recaptchaV3Module = defineCaptchaModule<RecaptchaProviderOptions, RecaptchaGlobal, number | string>({
|
|
16
|
-
|
|
16
|
+
moduleId: 'formie:recaptcha-v3',
|
|
17
17
|
defaultPlaceholderSelector: '[data-recaptcha-placeholder]',
|
|
18
18
|
defaultTokenFieldNames: ['g-recaptcha-response'],
|
|
19
19
|
load: ({ options }) => {
|
|
@@ -31,7 +31,7 @@ export const recaptchaV3Module = defineCaptchaModule<RecaptchaProviderOptions, R
|
|
|
31
31
|
});
|
|
32
32
|
});
|
|
33
33
|
},
|
|
34
|
-
|
|
34
|
+
challenge: async({ api, provider, placeholder, services, stageCtx }) => {
|
|
35
35
|
// If a token already exists we can skip execution, which matters for
|
|
36
36
|
// re-renders or multi-step flows where the same challenge was already
|
|
37
37
|
// completed very recently.
|
|
@@ -5,6 +5,6 @@ import { definePassiveCaptchaModule } from '#modules/captchas/api';
|
|
|
5
5
|
// good fit here because the provider is really just about keeping a hidden
|
|
6
6
|
// transport value in sync across renders and token refreshes.
|
|
7
7
|
export const snaptchaModule = definePassiveCaptchaModule({
|
|
8
|
-
|
|
8
|
+
moduleId: 'formie:snaptcha',
|
|
9
9
|
defaultPlaceholderSelector: '[data-snaptcha-captcha-placeholder]',
|
|
10
10
|
});
|
|
@@ -51,7 +51,7 @@ async function loadTurnstileGlobal(options: TurnstileProviderOptions): Promise<T
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
export const turnstileModule = defineCaptchaModule<TurnstileProviderOptions, TurnstileGlobal, string>({
|
|
54
|
-
|
|
54
|
+
moduleId: 'formie:turnstile',
|
|
55
55
|
defaultPlaceholderSelector: '[data-turnstile-placeholder]',
|
|
56
56
|
defaultTokenFieldNames: ['cf-turnstile-response'],
|
|
57
57
|
load: ({ options }) => {
|
|
@@ -102,7 +102,7 @@ export const turnstileModule = defineCaptchaModule<TurnstileProviderOptions, Tur
|
|
|
102
102
|
},
|
|
103
103
|
});
|
|
104
104
|
},
|
|
105
|
-
|
|
105
|
+
challenge: ({ api, widget, placeholder, services, provider, stageCtx }) => {
|
|
106
106
|
// Submit-time rule: if a valid token already exists, do nothing. This
|
|
107
107
|
// covers cases where Turnstile solved itself on load or before submit.
|
|
108
108
|
if (services.tokens.has()) {
|
|
@@ -115,7 +115,7 @@ export const turnstileModule = defineCaptchaModule<TurnstileProviderOptions, Tur
|
|
|
115
115
|
api.execute(widget);
|
|
116
116
|
return services.tokens.wait(getTurnstileWaitForValueMs(provider)).then((hasToken) => {
|
|
117
117
|
if (!hasToken) {
|
|
118
|
-
// No token arrived in time, so block the
|
|
118
|
+
// No token arrived in time, so block the challenge stage and show
|
|
119
119
|
// the shared themed inline error next to the active placeholder.
|
|
120
120
|
const message = services.errors.getDefaultMessage();
|
|
121
121
|
services.errors.show(message, placeholder);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { BrowserModuleDefinition } from '#contracts/modules';
|
|
2
2
|
import { ADDRESS_SELECTORS, findAddressFieldInput } from '#modules/address/constants';
|
|
3
3
|
import { getModuleFieldContainers } from '#modules/fields/shared';
|
|
4
4
|
import { fetchCountryFromIp } from '#utils/country-from-ip';
|
|
@@ -85,7 +85,7 @@ async function preselectCountry(
|
|
|
85
85
|
return;
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
const response = await fetchCountryFromIp(options.countryFromIpAction);
|
|
88
|
+
const response = await fetchCountryFromIp(options.countryFromIpAction, addressRoot.closest('form'));
|
|
89
89
|
|
|
90
90
|
if (!response?.countryCode) {
|
|
91
91
|
return;
|
|
@@ -116,8 +116,10 @@ async function preselectCountry(
|
|
|
116
116
|
debug.log('Preselected country from IP.', { selectValue });
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
-
export const addressCountryModule:
|
|
120
|
-
|
|
119
|
+
export const addressCountryModule: BrowserModuleDefinition = {
|
|
120
|
+
moduleId: `formie:${MODULE_ID}`,
|
|
121
|
+
version: 2,
|
|
122
|
+
surfaces: ['server-rendered', 'client-rendered', 'cp-edit'],
|
|
121
123
|
kind: 'field',
|
|
122
124
|
match: (ctx) => {
|
|
123
125
|
return !!ctx.target.querySelector(COUNTRY_SELECTOR);
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { browserRequest, type BrowserRequestOptions } from '@verbb/formie-core';
|
|
2
|
+
import { getFormBrowserRequestOptions } from '#utils/request-profile';
|
|
3
|
+
import type { BrowserModuleDefinition } from '#contracts/modules';
|
|
2
4
|
import { ADDRESS_SELECTORS } from '#modules/address/constants';
|
|
3
5
|
import { initFormieCombobox } from '#modules/fields/combobox';
|
|
4
6
|
import { dispatchFieldEvent, getModuleFieldContainers } from '#modules/fields/shared';
|
|
7
|
+
import { getThemeClasses, toggleThemeClasses } from '#theme/theme-classes';
|
|
5
8
|
import { createDebug } from '#utils/debug';
|
|
6
9
|
|
|
7
10
|
const STATE_DYNAMIC_SELECTOR = '[data-formie-address-state-dynamic]';
|
|
@@ -212,7 +215,7 @@ function reconcileAutofillValue(fieldState: FieldState): void {
|
|
|
212
215
|
}
|
|
213
216
|
|
|
214
217
|
function buildSubdivisionsUrl(action: string, country: string, optionLabel: string, optionValue: string): string {
|
|
215
|
-
const url = new URL(action.startsWith('/') ? action : `/actions/${action}`, window.location.origin);
|
|
218
|
+
const url = new URL(/^https?:\/\//.test(action) || action.startsWith('/') ? action : `/actions/${action}`, window.location.origin);
|
|
216
219
|
url.searchParams.set('country', country);
|
|
217
220
|
url.searchParams.set('optionLabel', optionLabel);
|
|
218
221
|
url.searchParams.set('optionValue', optionValue);
|
|
@@ -238,6 +241,7 @@ async function fetchSubdivisions(
|
|
|
238
241
|
optionLabel: string,
|
|
239
242
|
optionValue: string,
|
|
240
243
|
action: string,
|
|
244
|
+
requestOptions: BrowserRequestOptions,
|
|
241
245
|
): Promise<SubdivisionsResponse | null> {
|
|
242
246
|
const cacheKey = getSubdivisionsCacheKey(country, optionLabel, optionValue, action);
|
|
243
247
|
|
|
@@ -248,11 +252,11 @@ async function fetchSubdivisions(
|
|
|
248
252
|
if (!subdivisionInflight.has(cacheKey)) {
|
|
249
253
|
subdivisionInflight.set(cacheKey, (async() => {
|
|
250
254
|
try {
|
|
251
|
-
const response = await
|
|
255
|
+
const response = await browserRequest(buildSubdivisionsUrl(action, country, optionLabel, optionValue), {
|
|
252
256
|
headers: {
|
|
253
257
|
Accept: 'application/json',
|
|
254
258
|
},
|
|
255
|
-
});
|
|
259
|
+
}, requestOptions);
|
|
256
260
|
|
|
257
261
|
if (!response.ok) {
|
|
258
262
|
subdivisionDataCache.set(cacheKey, null);
|
|
@@ -342,9 +346,11 @@ function applyTextThemeClasses(template: AddressStateControl, input: HTMLInputEl
|
|
|
342
346
|
function applySelectThemeClasses(template: AddressStateControl, select: HTMLSelectElement): void {
|
|
343
347
|
const classes: string[] = [...SELECT_THEME_CLASSES];
|
|
344
348
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
349
|
+
getThemeClasses(template, 'fieldControlError').forEach((className) => {
|
|
350
|
+
if (template.classList.contains(className)) {
|
|
351
|
+
classes.push(className);
|
|
352
|
+
}
|
|
353
|
+
});
|
|
348
354
|
|
|
349
355
|
select.className = classes.join(' ');
|
|
350
356
|
}
|
|
@@ -454,7 +460,7 @@ function syncDatalist(
|
|
|
454
460
|
function setFieldVisibility(fieldState: FieldState, visible: boolean): void {
|
|
455
461
|
const { stateField, stateControl, required } = fieldState;
|
|
456
462
|
|
|
457
|
-
stateField
|
|
463
|
+
toggleThemeClasses(stateField, stateField, 'conditionalHidden', !visible);
|
|
458
464
|
stateField.toggleAttribute('data-formie-conditionally-hidden', !visible);
|
|
459
465
|
|
|
460
466
|
if (!visible) {
|
|
@@ -502,7 +508,7 @@ function showFetchingUI(fieldState: FieldState): void {
|
|
|
502
508
|
fieldState.stateControl.setAttribute('aria-hidden', 'true');
|
|
503
509
|
fieldState.stateControl.setAttribute('tabindex', '-1');
|
|
504
510
|
|
|
505
|
-
fieldState.stateField.
|
|
511
|
+
toggleThemeClasses(fieldState.stateField, fieldState.stateField, 'conditionalHidden', false);
|
|
506
512
|
fieldState.stateField.removeAttribute('data-formie-conditionally-hidden');
|
|
507
513
|
fieldState.stateField.setAttribute('data-formie-address-state-skeleton-active', 'true');
|
|
508
514
|
|
|
@@ -632,7 +638,7 @@ async function applyCountryState(
|
|
|
632
638
|
showFetchingUI(fieldState);
|
|
633
639
|
}
|
|
634
640
|
|
|
635
|
-
const response = await fetchSubdivisions(country, optionLabel, optionValue, subdivisionsAction);
|
|
641
|
+
const response = await fetchSubdivisions(country, optionLabel, optionValue, subdivisionsAction, getFormBrowserRequestOptions(fieldState.addressRoot.closest('form')));
|
|
636
642
|
|
|
637
643
|
if (fetchGeneration !== fieldState.fetchGeneration) {
|
|
638
644
|
return;
|
|
@@ -923,8 +929,10 @@ function initAddressStateField(field: HTMLElement, options: AddressStateOptions)
|
|
|
923
929
|
};
|
|
924
930
|
}
|
|
925
931
|
|
|
926
|
-
export const addressStateModule:
|
|
927
|
-
|
|
932
|
+
export const addressStateModule: BrowserModuleDefinition = {
|
|
933
|
+
moduleId: `formie:${MODULE_ID}`,
|
|
934
|
+
version: 2,
|
|
935
|
+
surfaces: ['server-rendered', 'client-rendered', 'cp-edit'],
|
|
928
936
|
kind: 'field',
|
|
929
937
|
match: (ctx) => {
|
|
930
938
|
return !!ctx.target.querySelector(STATE_DYNAMIC_SELECTOR);
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
type CalculationVariableEntry,
|
|
10
10
|
} from '@verbb/formie-core';
|
|
11
11
|
|
|
12
|
-
import type {
|
|
12
|
+
import type { BrowserModuleDefinition } from '#contracts/modules';
|
|
13
13
|
import { dispatchFieldEvent, getModuleFieldContainers } from '#modules/fields/shared';
|
|
14
14
|
import { buildFieldValueRegistry, fieldKeyToInputName, normalizeFieldKey, resolveFieldReferenceLive } from '#utils/field-references';
|
|
15
15
|
import { getRowScopedWatchNames, resolveRowScopedFieldReference, type RowScopeParams } from '#utils/field-references.row-scope';
|
|
@@ -263,8 +263,10 @@ function bindCalculationsField(root: Element, field: HTMLElement, input: HTMLInp
|
|
|
263
263
|
};
|
|
264
264
|
}
|
|
265
265
|
|
|
266
|
-
export const calculationsModule:
|
|
267
|
-
|
|
266
|
+
export const calculationsModule: BrowserModuleDefinition = {
|
|
267
|
+
moduleId: `formie:${MODULE_ID}`,
|
|
268
|
+
version: 2,
|
|
269
|
+
surfaces: ['server-rendered', 'client-rendered', 'cp-edit'],
|
|
268
270
|
kind: 'field',
|
|
269
271
|
match: (ctx) => {
|
|
270
272
|
return !!ctx.target.querySelector(INPUT_SELECTOR);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import { dispatchFieldEvent,
|
|
1
|
+
import type { BrowserModuleDefinition } from '#contracts/modules';
|
|
2
|
+
import { dispatchFieldEvent, releaseFormValidators, retainFormValidators } from '#modules/fields/shared';
|
|
3
3
|
import { createDebug } from '#utils/debug';
|
|
4
4
|
|
|
5
5
|
const FIELD_SELECTOR = '[data-formie-checkboxes-field-layout], [data-formie-radio-field-layout]';
|
|
@@ -213,19 +213,7 @@ function unregisterValidators(form: HTMLFormElement | null): void {
|
|
|
213
213
|
releaseFormValidators(form, VALIDATOR_SCOPE, [CHECKBOX_MINMAX_VALIDATOR, OTHER_OPTION_TEXT_VALIDATOR]);
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
-
function
|
|
217
|
-
if (input.checked) {
|
|
218
|
-
input.setAttribute('checked', '');
|
|
219
|
-
} else {
|
|
220
|
-
input.removeAttribute('checked');
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
function syncRequiredCheckboxes(field: HTMLElement): void {
|
|
225
|
-
const requiredCheckboxes = Array.from(field.querySelectorAll('input[type="checkbox"][required][data-formie-checkbox-input]')).filter((input): input is HTMLInputElement => {
|
|
226
|
-
return input instanceof HTMLInputElement;
|
|
227
|
-
});
|
|
228
|
-
|
|
216
|
+
function syncRequiredCheckboxes(requiredCheckboxes: HTMLInputElement[]): void {
|
|
229
217
|
if (!requiredCheckboxes.length) {
|
|
230
218
|
return;
|
|
231
219
|
}
|
|
@@ -299,27 +287,11 @@ function toggleCheckboxGroup(field: HTMLElement, toggle: HTMLInputElement): void
|
|
|
299
287
|
// Re-emit change/input so downstream modules (conditions, calculations,
|
|
300
288
|
// validation) react exactly as if the user toggled each box manually.
|
|
301
289
|
input.checked = toggle.checked;
|
|
302
|
-
syncCheckedAttribute(input);
|
|
303
290
|
input.dispatchEvent(new Event('change', { bubbles: true }));
|
|
304
291
|
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
305
292
|
});
|
|
306
293
|
}
|
|
307
294
|
|
|
308
|
-
function syncRadioGroup(input: HTMLInputElement, field: HTMLElement): void {
|
|
309
|
-
if (!input.checked || !input.name) {
|
|
310
|
-
syncCheckedAttribute(input);
|
|
311
|
-
return;
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
const group = Array.from(field.querySelectorAll(`input[type="radio"][name="${escapeSelectorValue(input.name)}"]`)).filter((radio): radio is HTMLInputElement => {
|
|
315
|
-
return radio instanceof HTMLInputElement;
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
group.forEach((radio) => {
|
|
319
|
-
syncCheckedAttribute(radio);
|
|
320
|
-
});
|
|
321
|
-
}
|
|
322
|
-
|
|
323
295
|
function bindField(field: HTMLElement): () => void {
|
|
324
296
|
const inputs = Array.from(field.querySelectorAll('input[type="checkbox"], input[type="radio"]')).filter((input): input is HTMLInputElement => {
|
|
325
297
|
return input instanceof HTMLInputElement;
|
|
@@ -330,20 +302,28 @@ function bindField(field: HTMLElement): () => void {
|
|
|
330
302
|
return () => {};
|
|
331
303
|
}
|
|
332
304
|
|
|
305
|
+
const requiredCheckboxes = inputs.filter((input) => input.type === 'checkbox' && input.required);
|
|
306
|
+
const form = field.closest('form');
|
|
307
|
+
const onReset = (event: Event) => {
|
|
308
|
+
// Native reset restores checked properties after the reset event returns.
|
|
309
|
+
queueMicrotask(() => {
|
|
310
|
+
if (!event.defaultPrevented) {
|
|
311
|
+
syncRequiredCheckboxes(requiredCheckboxes);
|
|
312
|
+
enforceMaxOptions(field);
|
|
313
|
+
syncOtherOptionField(field);
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
};
|
|
317
|
+
form?.addEventListener('reset', onReset);
|
|
318
|
+
|
|
333
319
|
const listeners = inputs.map((input) => {
|
|
334
320
|
const eventName = input.type === 'radio' ? 'change' : 'click';
|
|
335
321
|
const handler = () => {
|
|
336
|
-
syncCheckedAttribute(input);
|
|
337
|
-
|
|
338
322
|
if (input.type === 'checkbox' && isToggleCheckbox(input)) {
|
|
339
323
|
toggleCheckboxGroup(field, input);
|
|
340
324
|
}
|
|
341
325
|
|
|
342
|
-
|
|
343
|
-
syncRadioGroup(input, field);
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
syncRequiredCheckboxes(field);
|
|
326
|
+
syncRequiredCheckboxes(requiredCheckboxes);
|
|
347
327
|
enforceMaxOptions(field);
|
|
348
328
|
queueMicrotask(() => {
|
|
349
329
|
syncOtherOptionField(field);
|
|
@@ -356,7 +336,6 @@ function bindField(field: HTMLElement): () => void {
|
|
|
356
336
|
};
|
|
357
337
|
|
|
358
338
|
input.addEventListener(eventName, handler);
|
|
359
|
-
syncCheckedAttribute(input);
|
|
360
339
|
|
|
361
340
|
return () => {
|
|
362
341
|
input.removeEventListener(eventName, handler);
|
|
@@ -365,7 +344,7 @@ function bindField(field: HTMLElement): () => void {
|
|
|
365
344
|
|
|
366
345
|
const destroyOtherOptionBinding = bindOtherOptionField(field);
|
|
367
346
|
|
|
368
|
-
syncRequiredCheckboxes(
|
|
347
|
+
syncRequiredCheckboxes(requiredCheckboxes);
|
|
369
348
|
enforceMaxOptions(field);
|
|
370
349
|
syncOtherOptionField(field);
|
|
371
350
|
dispatchFieldEvent(field, MODULE_ID, 'init', {
|
|
@@ -376,12 +355,15 @@ function bindField(field: HTMLElement): () => void {
|
|
|
376
355
|
listeners.forEach((unbind) => {
|
|
377
356
|
unbind();
|
|
378
357
|
});
|
|
358
|
+
form?.removeEventListener('reset', onReset);
|
|
379
359
|
destroyOtherOptionBinding();
|
|
380
360
|
};
|
|
381
361
|
}
|
|
382
362
|
|
|
383
|
-
export const checkboxRadioModule:
|
|
384
|
-
|
|
363
|
+
export const checkboxRadioModule: BrowserModuleDefinition = {
|
|
364
|
+
moduleId: `formie:${MODULE_ID}`,
|
|
365
|
+
version: 2,
|
|
366
|
+
surfaces: ['server-rendered', 'client-rendered', 'cp-edit'],
|
|
385
367
|
kind: 'field',
|
|
386
368
|
match: (ctx) => {
|
|
387
369
|
return ctx.target instanceof HTMLElement && (
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import TomSelect from 'tom-select/dist/esm/tom-select.complete.js';
|
|
2
2
|
|
|
3
|
-
import type {
|
|
3
|
+
import type { BrowserModuleDefinition } from '#contracts/modules';
|
|
4
4
|
import comboboxThemeCss from '#theme-css/fields/_combobox.css?inline';
|
|
5
5
|
import { dispatchFieldEvent, getModuleFieldContainers } from '#modules/fields/shared';
|
|
6
6
|
import { ensureModuleStyles } from '#modules/styles';
|
|
7
|
+
import { getThemeClasses } from '#theme/theme-classes';
|
|
7
8
|
import { createDebug } from '#utils/debug';
|
|
8
9
|
|
|
9
10
|
const SELECT_SELECTOR = 'select[data-formie-combobox-input]';
|
|
@@ -15,7 +16,6 @@ ensureModuleStyles(MODULE_ID, [comboboxThemeCss]);
|
|
|
15
16
|
const NATIVE_THEME_CLASSES = [
|
|
16
17
|
'formie-select',
|
|
17
18
|
'formie-dropdown-input',
|
|
18
|
-
'formie-input-error',
|
|
19
19
|
] as const;
|
|
20
20
|
|
|
21
21
|
export type FormieComboboxOptions = {
|
|
@@ -35,7 +35,7 @@ type SelectElement = HTMLSelectElement & {
|
|
|
35
35
|
function stripNativeThemeClasses(select: HTMLSelectElement): string[] {
|
|
36
36
|
const removed: string[] = [];
|
|
37
37
|
|
|
38
|
-
NATIVE_THEME_CLASSES.forEach((className) => {
|
|
38
|
+
[...NATIVE_THEME_CLASSES, ...getThemeClasses(select, 'fieldControlError')].forEach((className) => {
|
|
39
39
|
if (select.classList.contains(className)) {
|
|
40
40
|
select.classList.remove(className);
|
|
41
41
|
removed.push(className);
|
|
@@ -51,8 +51,8 @@ function restoreNativeThemeClasses(select: HTMLSelectElement, classNames: string
|
|
|
51
51
|
});
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
function cleanLeakedThemeClasses(element: HTMLElement): void {
|
|
55
|
-
NATIVE_THEME_CLASSES.forEach((className) => {
|
|
54
|
+
function cleanLeakedThemeClasses(element: HTMLElement, source: HTMLSelectElement): void {
|
|
55
|
+
[...NATIVE_THEME_CLASSES, ...getThemeClasses(source, 'fieldControlError')].forEach((className) => {
|
|
56
56
|
element.classList.remove(className);
|
|
57
57
|
});
|
|
58
58
|
}
|
|
@@ -78,6 +78,8 @@ function removeEmptyOptionFromCombobox(instance: TomSelectInstance): void {
|
|
|
78
78
|
export function initFormieCombobox(select: SelectElement, options: FormieComboboxOptions = {}): () => void {
|
|
79
79
|
select._formieTomSelect?.destroy();
|
|
80
80
|
|
|
81
|
+
const initialValues = Array.from(select.selectedOptions, (option) => option.value).filter(Boolean);
|
|
82
|
+
const form = select.form;
|
|
81
83
|
const multiple = options.multiple === true;
|
|
82
84
|
const restoredClasses = stripNativeThemeClasses(select);
|
|
83
85
|
const placeholder = resolvePlaceholder(select, options.placeholder);
|
|
@@ -115,10 +117,10 @@ export function initFormieCombobox(select: SelectElement, options: FormieCombobo
|
|
|
115
117
|
|
|
116
118
|
const instance = new TomSelect(select, mergedOptions) as TomSelectInstance;
|
|
117
119
|
removeEmptyOptionFromCombobox(instance);
|
|
118
|
-
cleanLeakedThemeClasses(instance.wrapper);
|
|
120
|
+
cleanLeakedThemeClasses(instance.wrapper, select);
|
|
119
121
|
|
|
120
122
|
if (instance.dropdown) {
|
|
121
|
-
cleanLeakedThemeClasses(instance.dropdown);
|
|
123
|
+
cleanLeakedThemeClasses(instance.dropdown, select);
|
|
122
124
|
}
|
|
123
125
|
|
|
124
126
|
// Tom Select keeps the native select as a preceding sibling; ensure it never
|
|
@@ -127,6 +129,17 @@ export function initFormieCombobox(select: SelectElement, options: FormieCombobo
|
|
|
127
129
|
|
|
128
130
|
select._formieTomSelect = instance;
|
|
129
131
|
|
|
132
|
+
const onReset = (event: Event) => {
|
|
133
|
+
// Tom Select replaces native options, so retain the original selection
|
|
134
|
+
// and restore its display after the browser resets the backing select.
|
|
135
|
+
queueMicrotask(() => {
|
|
136
|
+
if (!event.defaultPrevented) {
|
|
137
|
+
instance.setValue(initialValues);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
};
|
|
141
|
+
form?.addEventListener('reset', onReset);
|
|
142
|
+
|
|
130
143
|
debug.log('Initialized.', {
|
|
131
144
|
inputName: select.name,
|
|
132
145
|
multiple,
|
|
@@ -138,6 +151,7 @@ export function initFormieCombobox(select: SelectElement, options: FormieCombobo
|
|
|
138
151
|
});
|
|
139
152
|
|
|
140
153
|
return () => {
|
|
154
|
+
form?.removeEventListener('reset', onReset);
|
|
141
155
|
instance.destroy();
|
|
142
156
|
select.style.removeProperty('display');
|
|
143
157
|
restoreNativeThemeClasses(select, restoredClasses);
|
|
@@ -148,8 +162,10 @@ export function initFormieCombobox(select: SelectElement, options: FormieCombobo
|
|
|
148
162
|
};
|
|
149
163
|
}
|
|
150
164
|
|
|
151
|
-
export const comboboxModule:
|
|
152
|
-
|
|
165
|
+
export const comboboxModule: BrowserModuleDefinition = {
|
|
166
|
+
moduleId: `formie:${MODULE_ID}`,
|
|
167
|
+
version: 2,
|
|
168
|
+
surfaces: ['server-rendered', 'client-rendered', 'cp-edit'],
|
|
153
169
|
kind: 'field',
|
|
154
170
|
match: (ctx) => {
|
|
155
171
|
return !!ctx.target.querySelector(SELECT_SELECTOR);
|
|
@@ -13,7 +13,7 @@ function parseConditionSource(value: unknown): ConditionSource | null {
|
|
|
13
13
|
return {
|
|
14
14
|
raw: typeof candidate.raw === 'string' ? candidate.raw : '',
|
|
15
15
|
target: typeof candidate.target === 'string' ? candidate.target : '',
|
|
16
|
-
handle: typeof candidate.handle === 'string' ? candidate.handle : '',
|
|
16
|
+
handle: typeof candidate.domHandle === 'string' ? candidate.domHandle : typeof candidate.handle === 'string' ? candidate.handle : '',
|
|
17
17
|
selector: typeof candidate.selector === 'string' ? candidate.selector : '',
|
|
18
18
|
defaultValue: typeof candidate.defaultValue === 'string' ? candidate.defaultValue : '',
|
|
19
19
|
transformerId: typeof candidate.transformerId === 'string' ? candidate.transformerId : '',
|
|
@@ -45,35 +45,32 @@ export function parseConditionSettings(node: Element): ParsedConditionSettings |
|
|
|
45
45
|
|
|
46
46
|
try {
|
|
47
47
|
const parsed = JSON.parse(raw) as Record<string, unknown>;
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
const candidate = condition as Record<string, unknown>;
|
|
55
|
-
return typeof candidate.field === 'string' && typeof candidate.condition === 'string';
|
|
56
|
-
}).map((condition) => {
|
|
57
|
-
const candidate = condition as Record<string, unknown>;
|
|
58
|
-
|
|
48
|
+
const effect = String(parsed.effect ?? parsed.showRule ?? 'show');
|
|
49
|
+
const valid = (parsed.version == null || parsed.version === 1) && ['all', 'any'].includes(String(parsed.mode ?? parsed.conditionRule ?? 'all')) && ['show', 'hide', 'enable', 'disable'].includes(effect);
|
|
50
|
+
const rawRules = valid ? parsed.rules ?? parsed.conditions : [null];
|
|
51
|
+
const conditions = Array.isArray(rawRules)
|
|
52
|
+
? rawRules.map((row) => {
|
|
53
|
+
const candidate = row && typeof row === 'object' ? row as Record<string, unknown> : {};
|
|
59
54
|
return {
|
|
60
|
-
field:
|
|
55
|
+
field: typeof candidate.field === 'string' ? candidate.field : '',
|
|
61
56
|
source: parseConditionSource(candidate.source),
|
|
62
|
-
condition:
|
|
63
|
-
|
|
57
|
+
condition: String(candidate.operator ?? candidate.condition ?? ''),
|
|
58
|
+
valueType: candidate.valueType as ConditionDefinition['valueType'],
|
|
59
|
+
browserSafe: candidate.browserSafe !== false,
|
|
60
|
+
value: candidate.value,
|
|
64
61
|
};
|
|
65
62
|
})
|
|
66
|
-
: [];
|
|
63
|
+
: [{ field: '', condition: '', value: null, browserSafe: false }];
|
|
67
64
|
|
|
68
65
|
return {
|
|
69
|
-
showRule:
|
|
70
|
-
conditionRule: parsed.conditionRule === 'any' ? 'any' : 'all',
|
|
66
|
+
showRule: ['hide', 'enable', 'disable'].includes(effect) ? effect as ParsedConditionSettings['showRule'] : 'show',
|
|
67
|
+
conditionRule: (parsed.mode ?? parsed.conditionRule) === 'any' ? 'any' : 'all',
|
|
71
68
|
clearOnHide: parsed.clearOnHide !== false,
|
|
72
69
|
isNested: Boolean(parsed.isNested),
|
|
73
70
|
conditions,
|
|
74
71
|
};
|
|
75
72
|
} catch (error) {
|
|
76
|
-
console.error('[formie] Invalid condition JSON.'
|
|
77
|
-
return
|
|
73
|
+
console.error('[formie] Invalid condition JSON.');
|
|
74
|
+
return { showRule: 'show', conditionRule: 'all', clearOnHide: true, isNested: false, conditions: [{ field: '', condition: '', browserSafe: false }] };
|
|
78
75
|
}
|
|
79
76
|
}
|