@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,14 +1,13 @@
|
|
|
1
|
+
import { getThemeClasses } from '#theme/theme-classes';
|
|
2
|
+
|
|
1
3
|
const CONDITION_DISABLED_ATTR = 'data-formie-conditions-disabled';
|
|
2
4
|
const PRESERVED_DISABLED_ATTR = 'data-formie-preserve-disabled';
|
|
3
5
|
const CONDITIONAL_HIDDEN_ATTR = 'data-formie-conditionally-hidden';
|
|
4
6
|
const PAGE_HIDDEN_ATTR = 'data-formie-page-hidden';
|
|
5
|
-
const CONDITIONAL_HIDDEN_CLASS = 'formie-conditionally-hidden';
|
|
6
7
|
const CP_MUTED_CLASS = 'fui-cp-muted-conditional-field';
|
|
7
8
|
const CP_MUTED_EXPANDED_CLASS = 'fui-cp-muted-conditional-field--expanded';
|
|
8
9
|
const CP_MUTED_ATTR = 'data-formie-cp-muted';
|
|
9
|
-
const PAGE_HIDDEN_CLASS = 'formie-page-hidden';
|
|
10
10
|
const ROW_HIDDEN_ATTR = 'data-formie-row-hidden';
|
|
11
|
-
const ROW_HIDDEN_CLASS = 'formie-row-hidden';
|
|
12
11
|
const FIELD_COUNT_ATTR = 'data-formie-field-count';
|
|
13
12
|
const ROW_SELECTOR = '[data-formie-row], [data-formie-subfield-row], [data-formie-nested-field-row]';
|
|
14
13
|
const FIELD_SELECTOR = ':scope > [data-formie-field]';
|
|
@@ -35,7 +34,7 @@ function clearConditionNodeValues(node: Element): void {
|
|
|
35
34
|
option.selected = false;
|
|
36
35
|
});
|
|
37
36
|
} else {
|
|
38
|
-
element.selectedIndex =
|
|
37
|
+
element.selectedIndex = -1;
|
|
39
38
|
}
|
|
40
39
|
}
|
|
41
40
|
|
|
@@ -43,12 +42,14 @@ function clearConditionNodeValues(node: Element): void {
|
|
|
43
42
|
element.value = '';
|
|
44
43
|
}
|
|
45
44
|
});
|
|
45
|
+
|
|
46
|
+
node.dispatchEvent(new CustomEvent('formie:field:clear', { bubbles: true }));
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
function setVisibilityState(node: Element, hidden: boolean): boolean {
|
|
49
50
|
const isPage = node.hasAttribute('data-formie-page');
|
|
50
51
|
const hiddenAttr = isPage ? PAGE_HIDDEN_ATTR : CONDITIONAL_HIDDEN_ATTR;
|
|
51
|
-
const
|
|
52
|
+
const hiddenClasses = getThemeClasses(node, isPage ? 'pageHidden' : 'conditionalHidden');
|
|
52
53
|
const wasHidden = node.hasAttribute(hiddenAttr);
|
|
53
54
|
|
|
54
55
|
if (hidden) {
|
|
@@ -56,17 +57,13 @@ function setVisibilityState(node: Element, hidden: boolean): boolean {
|
|
|
56
57
|
node.setAttribute(hiddenAttr, 'true');
|
|
57
58
|
}
|
|
58
59
|
|
|
59
|
-
|
|
60
|
-
node.classList.add(hiddenClass);
|
|
61
|
-
}
|
|
60
|
+
node.classList.add(...hiddenClasses);
|
|
62
61
|
} else {
|
|
63
62
|
if (wasHidden) {
|
|
64
63
|
node.removeAttribute(hiddenAttr);
|
|
65
64
|
}
|
|
66
65
|
|
|
67
|
-
|
|
68
|
-
node.classList.remove(hiddenClass);
|
|
69
|
-
}
|
|
66
|
+
node.classList.remove(...hiddenClasses);
|
|
70
67
|
}
|
|
71
68
|
|
|
72
69
|
return wasHidden !== hidden;
|
|
@@ -152,6 +149,7 @@ function isFieldVisible(field: Element): boolean {
|
|
|
152
149
|
}
|
|
153
150
|
|
|
154
151
|
function syncRowState(row: Element): void {
|
|
152
|
+
const hiddenClasses = getThemeClasses(row, 'rowHidden');
|
|
155
153
|
const directFields = Array.from(row.querySelectorAll(FIELD_SELECTOR));
|
|
156
154
|
const visibleFieldCount = directFields.filter((field) => {
|
|
157
155
|
return isFieldVisible(field);
|
|
@@ -168,9 +166,7 @@ function syncRowState(row: Element): void {
|
|
|
168
166
|
row.removeAttribute(ROW_HIDDEN_ATTR);
|
|
169
167
|
}
|
|
170
168
|
|
|
171
|
-
|
|
172
|
-
row.classList.remove(ROW_HIDDEN_CLASS);
|
|
173
|
-
}
|
|
169
|
+
row.classList.remove(...hiddenClasses);
|
|
174
170
|
|
|
175
171
|
return;
|
|
176
172
|
}
|
|
@@ -183,9 +179,7 @@ function syncRowState(row: Element): void {
|
|
|
183
179
|
row.setAttribute(ROW_HIDDEN_ATTR, 'true');
|
|
184
180
|
}
|
|
185
181
|
|
|
186
|
-
|
|
187
|
-
row.classList.add(ROW_HIDDEN_CLASS);
|
|
188
|
-
}
|
|
182
|
+
row.classList.add(...hiddenClasses);
|
|
189
183
|
}
|
|
190
184
|
|
|
191
185
|
function clearCpMutedState(node: Element): void {
|
|
@@ -197,8 +191,8 @@ function clearCpMutedState(node: Element): void {
|
|
|
197
191
|
function clearHideState(node: Element): void {
|
|
198
192
|
node.removeAttribute(CONDITIONAL_HIDDEN_ATTR);
|
|
199
193
|
node.removeAttribute(PAGE_HIDDEN_ATTR);
|
|
200
|
-
node.classList.remove(
|
|
201
|
-
node.classList.remove(
|
|
194
|
+
node.classList.remove(...getThemeClasses(node, 'conditionalHidden'));
|
|
195
|
+
node.classList.remove(...getThemeClasses(node, 'pageHidden'));
|
|
202
196
|
}
|
|
203
197
|
|
|
204
198
|
function syncAncestorRows(node: Element): void {
|
|
@@ -214,8 +208,15 @@ export function applyConditionVisibility(
|
|
|
214
208
|
node: Element,
|
|
215
209
|
hidden: boolean,
|
|
216
210
|
clearOnHide: boolean,
|
|
217
|
-
options: { displayMode?: 'hide' | 'muted' } = {},
|
|
211
|
+
options: { displayMode?: 'hide' | 'muted'; disabledOnly?: boolean } = {},
|
|
218
212
|
): boolean {
|
|
213
|
+
if (options.disabledOnly) {
|
|
214
|
+
const changed = node.hasAttribute('data-formie-conditionally-disabled') !== hidden;
|
|
215
|
+
node.toggleAttribute('data-formie-conditionally-disabled', hidden);
|
|
216
|
+
syncDisabledState(node, hidden);
|
|
217
|
+
if (hidden && clearOnHide && changed) clearConditionNodeValues(node);
|
|
218
|
+
return changed;
|
|
219
|
+
}
|
|
219
220
|
if (options.displayMode === 'muted') {
|
|
220
221
|
return applyMutedConditionVisibility(node, hidden);
|
|
221
222
|
}
|
|
@@ -246,9 +247,7 @@ function applyMutedConditionVisibility(node: Element, hidden: boolean): boolean
|
|
|
246
247
|
|
|
247
248
|
if (hidden) {
|
|
248
249
|
if (node.hasAttribute(CONDITIONAL_HIDDEN_ATTR)
|
|
249
|
-
|| node.hasAttribute(PAGE_HIDDEN_ATTR)
|
|
250
|
-
|| node.classList.contains(CONDITIONAL_HIDDEN_CLASS)
|
|
251
|
-
|| node.classList.contains(PAGE_HIDDEN_CLASS)) {
|
|
250
|
+
|| node.hasAttribute(PAGE_HIDDEN_ATTR)) {
|
|
252
251
|
clearHideState(node);
|
|
253
252
|
stateChanged = true;
|
|
254
253
|
}
|
|
@@ -271,9 +270,7 @@ function applyMutedConditionVisibility(node: Element, hidden: boolean): boolean
|
|
|
271
270
|
}
|
|
272
271
|
|
|
273
272
|
if (node.hasAttribute(CONDITIONAL_HIDDEN_ATTR)
|
|
274
|
-
|| node.hasAttribute(PAGE_HIDDEN_ATTR)
|
|
275
|
-
|| node.classList.contains(CONDITIONAL_HIDDEN_CLASS)
|
|
276
|
-
|| node.classList.contains(PAGE_HIDDEN_CLASS)) {
|
|
273
|
+
|| node.hasAttribute(PAGE_HIDDEN_ATTR)) {
|
|
277
274
|
clearHideState(node);
|
|
278
275
|
stateChanged = true;
|
|
279
276
|
}
|
|
@@ -1,43 +1,35 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { evaluateCondition, finalizeConditionEvaluation } from '@verbb/formie-core';
|
|
2
2
|
|
|
3
|
-
import type { ConditionDefinition, ParsedConditionSettings
|
|
3
|
+
import type { ConditionDefinition, ParsedConditionSettings } from '#modules/fields/conditions/types';
|
|
4
4
|
import { resolveConditionSource } from '#modules/fields/conditions/references';
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
function isInputVisible(input: ConditionInput): boolean {
|
|
8
|
-
if (
|
|
9
|
-
input.closest('[data-formie-conditionally-hidden]')
|
|
10
|
-
|| input.closest('[data-formie-page-hidden]')
|
|
11
|
-
|| input.closest('[hidden]')
|
|
12
|
-
|| input.closest('[aria-hidden="true"]')
|
|
13
|
-
) {
|
|
14
|
-
return false;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
return !!(input.offsetWidth || input.offsetHeight || input.getClientRects().length);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function getConditionVisibility(inputs: ConditionInput[]): boolean | null {
|
|
21
|
-
if (!inputs.length) {
|
|
22
|
-
return null;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
return inputs.some((input) => {
|
|
26
|
-
return isInputVisible(input);
|
|
27
|
-
});
|
|
28
|
-
}
|
|
5
|
+
import { readSubmissionConditionValues } from '#modules/fields/conditions/submission-context';
|
|
6
|
+
import { readConditionValues, readConditionProjection } from '#modules/fields/conditions/values';
|
|
29
7
|
|
|
30
8
|
export function evaluateConditionSettings(
|
|
31
9
|
settings: ParsedConditionSettings,
|
|
32
10
|
getConditionInputs: (condition: ConditionDefinition) => Array<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>,
|
|
11
|
+
options: {
|
|
12
|
+
root?: Element;
|
|
13
|
+
from?: Element;
|
|
14
|
+
} = {},
|
|
33
15
|
): { finalResult: boolean; shouldHide: boolean } {
|
|
16
|
+
const root = options.root;
|
|
17
|
+
const from = options.from || root;
|
|
18
|
+
|
|
34
19
|
const groupedResults = settings.conditions.map((condition) => {
|
|
35
20
|
const inputs = getConditionInputs(condition);
|
|
36
21
|
const source = resolveConditionSource(condition);
|
|
37
22
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
23
|
+
// `{submission:*}` is not a DOM field — read the snapshot emitted on the form.
|
|
24
|
+
const actualValues = source?.target === 'submission' && root && from
|
|
25
|
+
? readSubmissionConditionValues(root, source, from)
|
|
26
|
+
: readConditionValues(inputs, source);
|
|
27
|
+
|
|
28
|
+
if (condition.browserSafe === false || Boolean(source?.transformerId) || source?.isValid === false || (!inputs.length && source?.target !== 'submission')) return { value: null, diagnostics: [{ code: 'unresolvedReference' }] };
|
|
29
|
+
const type = condition.valueType ?? (actualValues.length > 1 ? 'collection' : 'text');
|
|
30
|
+
const value = source?.target === 'submission' ? (type === 'collection' ? actualValues : actualValues[0] ?? null) : readConditionProjection(inputs, source, type, Number(from?.querySelector('input,select,textarea')?.getAttribute('name')?.match(/\[([0-9]+)\]/)?.[1]));
|
|
31
|
+
if (value && typeof value === 'object' && 'conditionDiagnostic' in value) return { value: null, diagnostics: [{ code: String(value.conditionDiagnostic) }] };
|
|
32
|
+
return evaluateCondition(condition.condition, value, condition.value, type);
|
|
41
33
|
});
|
|
42
34
|
|
|
43
35
|
return finalizeConditionEvaluation(settings, groupedResults);
|
|
@@ -33,7 +33,8 @@ function getRowScope(node: Element): Element | null {
|
|
|
33
33
|
|
|
34
34
|
function getFieldInputs(fieldNode: Element): ConditionInput[] {
|
|
35
35
|
return Array.from(fieldNode.querySelectorAll(CONDITION_INPUT_SELECTOR)).filter((element): element is ConditionInput => {
|
|
36
|
-
|
|
36
|
+
// Enhanced controls add unnamed search/display inputs that are not field values.
|
|
37
|
+
return isConditionInput(element) && Boolean(element.name);
|
|
37
38
|
});
|
|
38
39
|
}
|
|
39
40
|
|
|
@@ -93,7 +94,12 @@ function preferSameRow<TElement extends Element>(targetNode: Element, candidates
|
|
|
93
94
|
}
|
|
94
95
|
|
|
95
96
|
export function resolveConditionSource(condition: ConditionDefinition): ConditionSource | null {
|
|
96
|
-
if (condition.source?.target
|
|
97
|
+
if (!condition.source?.target || !condition.source.handle) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Field inputs + submission snapshot keys both use `source.handle`.
|
|
102
|
+
if (condition.source.target === 'field' || condition.source.target === 'submission') {
|
|
97
103
|
return condition.source;
|
|
98
104
|
}
|
|
99
105
|
|
|
@@ -112,10 +118,11 @@ export function queryConditionInputs(
|
|
|
112
118
|
}
|
|
113
119
|
|
|
114
120
|
const escapedFieldHandle = escapeSelectorValue(source.handle);
|
|
121
|
+
const explicitScope = Boolean(source.transformerParams.scope);
|
|
115
122
|
const fieldMatches = Array.from(root.querySelectorAll(`[data-formie-field-handle="${escapedFieldHandle}"]`));
|
|
116
123
|
|
|
117
124
|
if (fieldMatches.length) {
|
|
118
|
-
return preferSameRow(targetNode, fieldMatches).flatMap((fieldNode) => {
|
|
125
|
+
return (explicitScope ? fieldMatches : preferSameRow(targetNode, fieldMatches)).flatMap((fieldNode) => {
|
|
119
126
|
return filterInputsBySelector(getFieldInputs(fieldNode), source.selector);
|
|
120
127
|
});
|
|
121
128
|
}
|
|
@@ -130,7 +137,7 @@ export function queryConditionInputs(
|
|
|
130
137
|
});
|
|
131
138
|
|
|
132
139
|
if (direct.length || multi.length) {
|
|
133
|
-
return preferSameRow(targetNode, [...direct, ...multi]);
|
|
140
|
+
return explicitScope ? [...direct, ...multi] : preferSameRow(targetNode, [...direct, ...multi]);
|
|
134
141
|
}
|
|
135
142
|
|
|
136
143
|
if (!source.handle.includes('__ROW__')) {
|
|
@@ -139,7 +146,7 @@ export function queryConditionInputs(
|
|
|
139
146
|
|
|
140
147
|
const rowToken = getNodeRowToken(targetNode);
|
|
141
148
|
|
|
142
|
-
if (rowToken) {
|
|
149
|
+
if (rowToken && !explicitScope) {
|
|
143
150
|
const rowFieldName = fieldKeyToInputName(source.handle.replace(/__ROW__/g, rowToken));
|
|
144
151
|
const escapedRowFieldName = escapeSelectorValue(rowFieldName);
|
|
145
152
|
const rowDirect = Array.from(root.querySelectorAll(`[name="${escapedRowFieldName}"]`)).filter((element): element is ConditionInput => {
|
|
@@ -154,6 +161,10 @@ export function queryConditionInputs(
|
|
|
154
161
|
}
|
|
155
162
|
}
|
|
156
163
|
|
|
164
|
+
if (!explicitScope) {
|
|
165
|
+
return [];
|
|
166
|
+
}
|
|
167
|
+
|
|
157
168
|
const regexString = fieldKeyToInputName(source.handle)
|
|
158
169
|
.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
159
170
|
.replace(/__ROW__/g, '\\d+');
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { ConditionSource } from '#modules/fields/conditions/types';
|
|
2
|
+
|
|
3
|
+
export const SUBMISSION_CONTEXT_ATTR = 'data-formie-submission';
|
|
4
|
+
export const SUBMISSION_CONTEXT_CHANGE_EVENT = 'formie:submission-context-change';
|
|
5
|
+
|
|
6
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
7
|
+
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Find the nearest form/host that carries the submission condition snapshot.
|
|
12
|
+
* Prefer ancestors of `from` (the conditioned node), then fall back to `root`.
|
|
13
|
+
*/
|
|
14
|
+
export function findSubmissionContextHost(root: Element, from: Element = root): Element | null {
|
|
15
|
+
const closest = from.closest(`[${SUBMISSION_CONTEXT_ATTR}]`);
|
|
16
|
+
|
|
17
|
+
if (closest) {
|
|
18
|
+
return closest;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (root instanceof Element && root.hasAttribute(SUBMISSION_CONTEXT_ATTR)) {
|
|
22
|
+
return root;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return root.querySelector(`[${SUBMISSION_CONTEXT_ATTR}]`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function readSubmissionContext(root: Element, from: Element = root): Record<string, string> {
|
|
29
|
+
const host = findSubmissionContextHost(root, from);
|
|
30
|
+
const raw = host?.getAttribute(SUBMISSION_CONTEXT_ATTR);
|
|
31
|
+
|
|
32
|
+
if (!raw) {
|
|
33
|
+
return {};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
const parsed = JSON.parse(raw) as unknown;
|
|
38
|
+
|
|
39
|
+
if (!isRecord(parsed)) {
|
|
40
|
+
return {};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return Object.fromEntries(Object.entries(parsed).map(([key, value]) => {
|
|
44
|
+
return [key, value == null ? '' : String(value)];
|
|
45
|
+
}));
|
|
46
|
+
} catch (error) {
|
|
47
|
+
console.error('[formie] Invalid submission context JSON.', error);
|
|
48
|
+
return {};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Resolve `{submission:status}` (etc.) from the emitted snapshot.
|
|
54
|
+
* Handle is the property key from PHP (`status`, `title`, `formName`, …).
|
|
55
|
+
*/
|
|
56
|
+
export function readSubmissionConditionValues(
|
|
57
|
+
root: Element,
|
|
58
|
+
source: ConditionSource,
|
|
59
|
+
from: Element = root,
|
|
60
|
+
): string[] {
|
|
61
|
+
const context = readSubmissionContext(root, from);
|
|
62
|
+
const key = String(source.handle || '').trim();
|
|
63
|
+
let value = '';
|
|
64
|
+
|
|
65
|
+
if (key !== '') {
|
|
66
|
+
if (Object.prototype.hasOwnProperty.call(context, key)) {
|
|
67
|
+
value = context[key] ?? '';
|
|
68
|
+
} else {
|
|
69
|
+
// Variables map uses camelCase (`submissionStatus`); tolerate that alias.
|
|
70
|
+
const aliased = `submission${key.charAt(0).toUpperCase()}${key.slice(1)}`;
|
|
71
|
+
value = context[aliased] ?? '';
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (value === '' && source.defaultValue) {
|
|
76
|
+
value = source.defaultValue;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return [value];
|
|
80
|
+
}
|
|
@@ -15,11 +15,13 @@ export type ConditionDefinition = {
|
|
|
15
15
|
field: string;
|
|
16
16
|
source?: ConditionSource | null;
|
|
17
17
|
condition: string;
|
|
18
|
+
valueType?: import('@verbb/formie-core').ConditionValueType;
|
|
19
|
+
browserSafe?: boolean;
|
|
18
20
|
value?: unknown;
|
|
19
21
|
};
|
|
20
22
|
|
|
21
23
|
export type ParsedConditionSettings = {
|
|
22
|
-
showRule: 'show' | 'hide';
|
|
24
|
+
showRule: 'show' | 'hide' | 'enable' | 'disable';
|
|
23
25
|
conditionRule: 'all' | 'any';
|
|
24
26
|
clearOnHide: boolean;
|
|
25
27
|
isNested: boolean;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { selectConditionRows } from '@verbb/formie-core';
|
|
2
2
|
import type { ConditionInput, ConditionSource } from '#modules/fields/conditions/types';
|
|
3
3
|
|
|
4
4
|
function getInputKey(input: ConditionInput, index: number): string {
|
|
@@ -105,11 +105,36 @@ export function readConditionValues(inputs: ConditionInput[], source: ConditionS
|
|
|
105
105
|
return readInputGroupValues(group, source?.selector || '');
|
|
106
106
|
});
|
|
107
107
|
|
|
108
|
-
return
|
|
108
|
+
return (rawValues.length === 0 || rawValues.every((value) => value === '')) && source?.defaultValue ? [source.defaultValue] : rawValues;
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
111
|
+
// DOM controls adapt to the same normalized condition projection as client-rendered values.
|
|
112
|
+
export function readConditionProjection(inputs: ConditionInput[], source: ConditionSource | null, type: import('@verbb/formie-core').ConditionValueType, currentRow?: number): unknown {
|
|
113
|
+
if (source?.transformerParams.scope) {
|
|
114
|
+
const grouped = new Map<string, ConditionInput[]>();
|
|
115
|
+
for (const input of inputs) {
|
|
116
|
+
const row = input.name.match(/\[([0-9]+)\]/)?.[1];
|
|
117
|
+
if (row != null) grouped.set(row, [...(grouped.get(row) ?? []), input]);
|
|
118
|
+
}
|
|
119
|
+
const rows = [...grouped.values()].map((group) => readConditionProjection(group, { ...source, transformerParams: {} }, type === 'collection' ? (group.length > 1 ? 'collection' : 'text') : type));
|
|
120
|
+
const selected = selectConditionRows(rows, source.transformerParams, currentRow);
|
|
121
|
+
if (selected.diagnostic) return { conditionDiagnostic: selected.diagnostic };
|
|
122
|
+
return source.transformerParams.scope === 'rows' && !Array.isArray(selected.value) ? [selected.value] : selected.value;
|
|
123
|
+
}
|
|
124
|
+
if (type === 'boolean') {
|
|
125
|
+
const checkbox = inputs.find((input) => input instanceof HTMLInputElement && input.type === 'checkbox') as HTMLInputElement | undefined;
|
|
126
|
+
if (checkbox) return checkbox.checked;
|
|
127
|
+
}
|
|
128
|
+
if (['date', 'time', 'datetime'].includes(type)) {
|
|
129
|
+
const parts: Record<string, string> = {};
|
|
130
|
+
for (const input of inputs) {
|
|
131
|
+
const key = input.name.match(/\[(year|month|day|hour|minute|second|ampm|timezone)\]$/)?.[1];
|
|
132
|
+
if (key && input.value !== '') parts[key] = input.value;
|
|
133
|
+
}
|
|
134
|
+
if (Object.keys(parts).length) return parts;
|
|
135
|
+
}
|
|
136
|
+
const values = readConditionValues(inputs, source);
|
|
137
|
+
// Empty hidden companions let unchecked groups post a value, but are not
|
|
138
|
+
// selected answers in the server's normalized collection.
|
|
139
|
+
return type === 'collection' ? values.filter((value) => value !== '') : values[0] ?? null;
|
|
115
140
|
}
|
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { BrowserModuleDefinition } from '#contracts/modules';
|
|
2
2
|
import { CONDITION_SELECTOR, getConditionNodes, parseConditionSettings } from '#modules/fields/conditions/config';
|
|
3
3
|
import { applyConditionVisibility } from '#modules/fields/conditions/effects';
|
|
4
4
|
import { evaluateConditionSettings } from '#modules/fields/conditions/evaluator';
|
|
5
5
|
import { queryConditionInputs } from '#modules/fields/conditions/references';
|
|
6
|
+
import {
|
|
7
|
+
SUBMISSION_CONTEXT_ATTR,
|
|
8
|
+
SUBMISSION_CONTEXT_CHANGE_EVENT,
|
|
9
|
+
} from '#modules/fields/conditions/submission-context';
|
|
6
10
|
import type { ConditionEntry, ConditionInput } from '#modules/fields/conditions/types';
|
|
7
11
|
import { getConditionInputEventNames } from '#modules/fields/conditions/values';
|
|
8
12
|
import { createDebug } from '#utils/debug';
|
|
9
13
|
|
|
10
|
-
const MAX_EVALUATION_PASSES = 4;
|
|
11
14
|
const debug = createDebug('conditions');
|
|
12
15
|
|
|
13
16
|
function uniqueConditionInputs(inputs: ConditionInput[]): ConditionInput[] {
|
|
@@ -23,9 +26,11 @@ function uniqueConditionInputs(inputs: ConditionInput[]): ConditionInput[] {
|
|
|
23
26
|
});
|
|
24
27
|
}
|
|
25
28
|
|
|
26
|
-
export const conditionsModule:
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
export const conditionsModule: BrowserModuleDefinition = {
|
|
30
|
+
moduleId: 'formie:conditions',
|
|
31
|
+
version: 2,
|
|
32
|
+
surfaces: ['server-rendered', 'client-rendered', 'cp-edit'],
|
|
33
|
+
kind: 'core',
|
|
29
34
|
match: (ctx) => {
|
|
30
35
|
return ctx.target instanceof HTMLElement && (
|
|
31
36
|
ctx.target.matches(CONDITION_SELECTOR) ||
|
|
@@ -42,6 +47,7 @@ export const conditionsModule: FormieModuleDefinition = {
|
|
|
42
47
|
|
|
43
48
|
const sourceUnbinds: Array<() => void> = [];
|
|
44
49
|
let entries: ConditionEntry[] = [];
|
|
50
|
+
let cycles = new Set<Element>();
|
|
45
51
|
let evaluationQueued = false;
|
|
46
52
|
let rebuildQueued = false;
|
|
47
53
|
|
|
@@ -56,7 +62,7 @@ export const conditionsModule: FormieModuleDefinition = {
|
|
|
56
62
|
return getConditionNodes(scopeRoot).flatMap((node) => {
|
|
57
63
|
const settings = parseConditionSettings(node);
|
|
58
64
|
|
|
59
|
-
if (!settings
|
|
65
|
+
if (!settings) {
|
|
60
66
|
return [];
|
|
61
67
|
}
|
|
62
68
|
|
|
@@ -72,6 +78,34 @@ export const conditionsModule: FormieModuleDefinition = {
|
|
|
72
78
|
});
|
|
73
79
|
};
|
|
74
80
|
|
|
81
|
+
const orderEntries = (items: ConditionEntry[]): ConditionEntry[] => {
|
|
82
|
+
const byNode = new Map(items.map((entry) => [entry.node, entry]));
|
|
83
|
+
const visited = new Set<Element>();
|
|
84
|
+
const visiting: Element[] = [];
|
|
85
|
+
const ordered: ConditionEntry[] = [];
|
|
86
|
+
cycles = new Set();
|
|
87
|
+
const visit = (entry: ConditionEntry): void => {
|
|
88
|
+
if (visited.has(entry.node)) return;
|
|
89
|
+
const index = visiting.indexOf(entry.node);
|
|
90
|
+
if (index >= 0) { visiting.slice(index).forEach((node) => cycles.add(node)); return; }
|
|
91
|
+
visiting.push(entry.node);
|
|
92
|
+
const ancestors = (node: Element | null) => {
|
|
93
|
+
for (let current = node?.closest(CONDITION_SELECTOR); current; current = current.parentElement?.closest(CONDITION_SELECTOR)) {
|
|
94
|
+
const dependency = byNode.get(current);
|
|
95
|
+
if (dependency) visit(dependency);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
ancestors(entry.node.parentElement);
|
|
99
|
+
entry.sourceInputs.forEach((input) => ancestors(input));
|
|
100
|
+
visiting.pop();
|
|
101
|
+
visited.add(entry.node);
|
|
102
|
+
ordered.push(entry);
|
|
103
|
+
};
|
|
104
|
+
items.forEach(visit);
|
|
105
|
+
if (cycles.size) debug.warn('Condition dependency cycle.', { count: cycles.size });
|
|
106
|
+
return ordered;
|
|
107
|
+
};
|
|
108
|
+
|
|
75
109
|
const cpDisplayMode = ctx.options?.cpDisplayMode === 'muted' ? 'muted' : 'hide';
|
|
76
110
|
let isApplyingConditions = false;
|
|
77
111
|
|
|
@@ -79,8 +113,11 @@ export const conditionsModule: FormieModuleDefinition = {
|
|
|
79
113
|
let hasStateChanges = false;
|
|
80
114
|
|
|
81
115
|
entries.forEach((entry) => {
|
|
82
|
-
const result = evaluateConditionSettings(entry.settings, (condition) => {
|
|
116
|
+
const result = cycles.has(entry.node) ? { finalResult: false, shouldHide: ['show', 'enable'].includes(entry.settings.showRule), diagnostics: [{ code: 'dependencyCycle' }] } : evaluateConditionSettings(entry.settings, (condition) => {
|
|
83
117
|
return queryConditionInputs(scopeRoot, entry.node, condition);
|
|
118
|
+
}, {
|
|
119
|
+
root: scopeRoot,
|
|
120
|
+
from: entry.node,
|
|
84
121
|
});
|
|
85
122
|
|
|
86
123
|
const displayMode = entry.node.hasAttribute('data-formie-page')
|
|
@@ -91,7 +128,7 @@ export const conditionsModule: FormieModuleDefinition = {
|
|
|
91
128
|
entry.node,
|
|
92
129
|
result.shouldHide,
|
|
93
130
|
entry.settings.clearOnHide,
|
|
94
|
-
{ displayMode },
|
|
131
|
+
{ displayMode, disabledOnly: ['enable', 'disable'].includes(entry.settings.showRule) },
|
|
95
132
|
);
|
|
96
133
|
hasStateChanges = hasStateChanges || stateChanged;
|
|
97
134
|
debug.log('Condition evaluated.', {
|
|
@@ -105,6 +142,7 @@ export const conditionsModule: FormieModuleDefinition = {
|
|
|
105
142
|
shouldHide: result.shouldHide,
|
|
106
143
|
finalResult: result.finalResult,
|
|
107
144
|
clearOnHide: entry.settings.clearOnHide,
|
|
145
|
+
diagnostics: cycles.has(entry.node) ? [{ code: 'dependencyCycle' }] : [],
|
|
108
146
|
});
|
|
109
147
|
});
|
|
110
148
|
|
|
@@ -119,15 +157,7 @@ export const conditionsModule: FormieModuleDefinition = {
|
|
|
119
157
|
isApplyingConditions = true;
|
|
120
158
|
|
|
121
159
|
try {
|
|
122
|
-
|
|
123
|
-
if (!runEvaluationPass()) {
|
|
124
|
-
break;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if (pass === MAX_EVALUATION_PASSES - 1) {
|
|
128
|
-
debug.warn('Reached max evaluation passes.', { maxPasses: MAX_EVALUATION_PASSES });
|
|
129
|
-
}
|
|
130
|
-
}
|
|
160
|
+
runEvaluationPass();
|
|
131
161
|
} finally {
|
|
132
162
|
isApplyingConditions = false;
|
|
133
163
|
}
|
|
@@ -185,12 +215,22 @@ export const conditionsModule: FormieModuleDefinition = {
|
|
|
185
215
|
sourceUnbinds.push(() => {
|
|
186
216
|
ctx.form?.removeEventListener('reset', resetHandler);
|
|
187
217
|
});
|
|
218
|
+
|
|
219
|
+
// CP status menu (etc.) updates `data-formie-submission` and fires this event.
|
|
220
|
+
const submissionContextHandler = () => {
|
|
221
|
+
scheduleEvaluateAll();
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
ctx.form.addEventListener(SUBMISSION_CONTEXT_CHANGE_EVENT, submissionContextHandler);
|
|
225
|
+
sourceUnbinds.push(() => {
|
|
226
|
+
ctx.form?.removeEventListener(SUBMISSION_CONTEXT_CHANGE_EVENT, submissionContextHandler);
|
|
227
|
+
});
|
|
188
228
|
}
|
|
189
229
|
};
|
|
190
230
|
|
|
191
231
|
const rebuild = (): void => {
|
|
192
232
|
cleanupSourceBindings();
|
|
193
|
-
entries = buildEntries();
|
|
233
|
+
entries = orderEntries(buildEntries());
|
|
194
234
|
bindSourceInputs();
|
|
195
235
|
debug.log('Rebuilt condition graph.', {
|
|
196
236
|
entryCount: entries.length,
|
|
@@ -249,6 +289,7 @@ export const conditionsModule: FormieModuleDefinition = {
|
|
|
249
289
|
'data-formie-conditionally-hidden',
|
|
250
290
|
'data-formie-page-hidden',
|
|
251
291
|
'data-formie-row-hidden',
|
|
292
|
+
SUBMISSION_CONTEXT_ATTR,
|
|
252
293
|
],
|
|
253
294
|
});
|
|
254
295
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { BrowserModuleDefinition } from '#contracts/modules';
|
|
2
2
|
import { getModuleFieldTarget, observeMatchingElements } from '#modules/fields/shared';
|
|
3
3
|
|
|
4
4
|
const MODULE_ID = 'custom-google-maps';
|
|
@@ -390,8 +390,10 @@ function initCustomGoogleMaps(root: HTMLElement): () => void {
|
|
|
390
390
|
};
|
|
391
391
|
}
|
|
392
392
|
|
|
393
|
-
export const customGoogleMapsModule:
|
|
394
|
-
|
|
393
|
+
export const customGoogleMapsModule: BrowserModuleDefinition = {
|
|
394
|
+
moduleId: `formie:${MODULE_ID}`,
|
|
395
|
+
version: 2,
|
|
396
|
+
surfaces: ['server-rendered', 'client-rendered', 'cp-edit'],
|
|
395
397
|
kind: 'field',
|
|
396
398
|
match: ({ target }) => {
|
|
397
399
|
return target instanceof Element && (
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { BrowserModuleDefinition } from '#contracts/modules';
|
|
2
2
|
import { getModuleFieldTarget, observeMatchingElements } from '#modules/fields/shared';
|
|
3
3
|
|
|
4
4
|
const MODULE_ID = 'custom-link';
|
|
@@ -69,8 +69,10 @@ function initCustomLink(link: HTMLElement): () => void {
|
|
|
69
69
|
};
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
export const customLinkModule:
|
|
73
|
-
|
|
72
|
+
export const customLinkModule: BrowserModuleDefinition = {
|
|
73
|
+
moduleId: `formie:${MODULE_ID}`,
|
|
74
|
+
version: 2,
|
|
75
|
+
surfaces: ['server-rendered', 'client-rendered', 'cp-edit'],
|
|
74
76
|
kind: 'field',
|
|
75
77
|
match: ({ target }) => {
|
|
76
78
|
return target instanceof Element && (
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { BrowserModuleDefinition } from '#contracts/modules';
|
|
2
2
|
import type * as Leaflet from 'leaflet';
|
|
3
3
|
import leafletCss from 'leaflet/dist/leaflet.css?inline';
|
|
4
4
|
import { getModuleFieldTarget, observeMatchingElements } from '#modules/fields/shared';
|
|
@@ -313,8 +313,10 @@ function initCustomMaps(root: HTMLElement): () => void {
|
|
|
313
313
|
};
|
|
314
314
|
}
|
|
315
315
|
|
|
316
|
-
export const customMapsModule:
|
|
317
|
-
|
|
316
|
+
export const customMapsModule: BrowserModuleDefinition = {
|
|
317
|
+
moduleId: `formie:${MODULE_ID}`,
|
|
318
|
+
version: 2,
|
|
319
|
+
surfaces: ['server-rendered', 'client-rendered', 'cp-edit'],
|
|
318
320
|
kind: 'field',
|
|
319
321
|
match: ({ target }) => {
|
|
320
322
|
return target instanceof Element && (
|