@verbb/formie-browser 1.0.13 → 1.0.15
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 +80 -0
- package/dist/chunks/{address-country-Rx6GQTND.js → address-country-BcEQKw0T.js} +11 -5
- package/dist/chunks/{address-finder-k7_BXaRe.js → address-finder-BWGINCSA.js} +3 -3
- package/dist/chunks/address-state-DI3ndhMU.js +365 -0
- package/dist/chunks/{api-BUb6P-xu.js → api-BK9b340y.js} +93 -63
- package/dist/chunks/{api-DqpfkZWL.js → api-Dxl_CKw-.js} +202 -193
- package/dist/chunks/{api-sPqGbOww.js → api-ghNr2uxX.js} +15 -9
- package/dist/chunks/{async-nPFRNQ06.js → async-2GdXNFCE.js} +18 -1
- package/dist/chunks/{bpoint-Dlq34XH1.js → bpoint-BwtuyN_O.js} +3 -3
- package/dist/chunks/calculations-YEoVCG2q.js +310 -0
- package/dist/chunks/{captcha-eu-CGm8Lbrj.js → captcha-eu-DWLoQFKB.js} +6 -5
- package/dist/chunks/{checkbox-radio-BY2aTCOG.js → checkbox-radio-gsm8QPJg.js} +74 -75
- package/dist/chunks/{combobox-C0EuExSI.js → combobox-Ba08_cHL.js} +340 -328
- package/dist/chunks/conditions-Ceeg6ReZ.js +467 -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-DaPvMrop.js} +467 -443
- package/dist/chunks/{dist-D6i-VNgM.js → dist-ZLeW0zZ3.js} +1281 -453
- package/dist/chunks/{eway-D9_m8ooj.js → eway-uw0DzU-L.js} +5 -5
- package/dist/chunks/field-references.resolver-Ca8MguFv.js +104 -0
- package/dist/chunks/{file-upload-rqfZNqlH.js → file-upload-B8_mH012.js} +119 -99
- package/dist/chunks/friendly-captcha-v1-CVXaXgDO.js +34 -0
- package/dist/chunks/{friendly-captcha-v2-CLSAbkqx.js → friendly-captcha-v2-DkeIVTKI.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-c4wLJdOt.js} +2 -2
- package/dist/chunks/google-address-JHYvjwgN.js +168 -0
- package/dist/chunks/{hcaptcha-CGLAmgjO.js → hcaptcha-Dt3ELLlP.js} +4 -4
- 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-m51iPyO1.js} +3 -3
- package/dist/chunks/{mollie-Bibhl67p.js → mollie-Bn0PX173.js} +2 -2
- package/dist/chunks/{moneris-H2wSqk9h.js → moneris-BRbUvI4t.js} +3 -3
- package/dist/chunks/opayo-BwWdInEP.js +188 -0
- package/dist/chunks/{paddle-DkvIxQdG.js → paddle-CympHVvd.js} +4 -4
- package/dist/chunks/{password-validation-D06uH9va.js → password-validation-C8_uO_c_.js} +18 -12
- package/dist/chunks/{paypal-CQpAF7Ua.js → paypal-h75h6wae.js} +8 -6
- package/dist/chunks/{payway-CwDkC7YZ.js → payway-C9rHTCC_.js} +4 -4
- package/dist/chunks/{phone-country-D3ayr60L.js → phone-country-B8fv-L5_.js} +80 -63
- package/dist/chunks/{place-kit-BGHklIZ-.js → place-kit-BnZGQ-L1.js} +11 -11
- 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-CUs8BO6V.js} +4 -4
- package/dist/chunks/{recaptcha-shared-CLYJvojk.js → recaptcha-shared-DTbTw-MF.js} +2 -2
- package/dist/chunks/{recaptcha-v2-checkbox-Cy-0PEPc.js → recaptcha-v2-checkbox-P1McW4Pv.js} +4 -4
- package/dist/chunks/{recaptcha-v2-invisible-BwRH540O.js → recaptcha-v2-invisible-FGDqozSP.js} +4 -4
- package/dist/chunks/{recaptcha-v3-No4Ykrhk.js → recaptcha-v3-CflUHeZD.js} +4 -4
- package/dist/chunks/{repeater-BVnPUqTj.js → repeater-CyhDbozO.js} +60 -40
- 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/{scripts-CbQ7agX3.js → scripts-DrccjrFv.js} +1 -1
- 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/skip-CEW89ExY.js +7 -0
- package/dist/chunks/{snaptcha-DKx98oon.js → snaptcha-C3QLYxFT.js} +2 -2
- package/dist/chunks/{square-DwdcOI1G.js → square-C1z5DPVw.js} +9 -7
- package/dist/chunks/{stripe-DaoG2FT1.js → stripe-Dmkdkq1y.js} +11 -12
- package/dist/chunks/{summary-Dks0gXS3.js → summary-Bn-g5SDx.js} +48 -46
- 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-j7MlLLCc.js} +22 -16
- 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-ptihQfLl.js} +4 -4
- package/dist/chunks/{upload-manager-W-QDgxKD.js → upload-manager-BW7l-BhF.js} +459 -387
- 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 +1779 -1415
- 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 +3 -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 +12 -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/async.d.ts +1 -0
- package/dist/js/utils/async.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 +132 -86
- 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 +51 -45
- package/src/js/core/submit-result-ui.ts +25 -68
- 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 +102 -40
- 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 +14 -8
- 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 +11 -9
- package/src/js/modules/fields/address-state.ts +94 -35
- 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 +28 -9
- package/src/js/modules/fields/conditions/config.ts +17 -20
- package/src/js/modules/fields/conditions/effects.ts +25 -29
- 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 +65 -18
- package/src/js/modules/fields/custom-google-maps.ts +5 -3
- package/src/js/modules/fields/custom-link.ts +5 -3
- package/src/js/modules/fields/custom-maps.ts +5 -3
- package/src/js/modules/fields/date-picker.ts +40 -7
- package/src/js/modules/fields/file-upload.ts +62 -23
- 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 +35 -8
- package/src/js/modules/fields/repeater.ts +60 -7
- 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 +244 -67
- 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/async.ts +34 -0
- 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 +14 -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 +49 -61
- package/dist/chunks/address-state-BwE01m2_.js +0 -344
- package/dist/chunks/calculations-Dv3hYb8_.js +0 -299
- package/dist/chunks/conditions-CPH1snCx.js +0 -424
- package/dist/chunks/country-from-ip-BwxKaBuJ.js +0 -26
- package/dist/chunks/field-references.resolver-CHwn0G0L.js +0 -145
- package/dist/chunks/friendly-captcha-v1-C_2reOXr.js +0 -31
- package/dist/chunks/google-address-BH3Zhi06.js +0 -161
- package/dist/chunks/http-D-JExro7.js +0 -27
- package/dist/chunks/opayo-CR0DtsLa.js +0 -179
- package/dist/chunks/rich-text-Bg_--4TG.js +0 -349
- package/dist/js/modules/fields/conditions/transforms.d.ts +0 -3
- package/dist/js/modules/fields/conditions/transforms.d.ts.map +0 -1
- package/src/js/modules/fields/conditions/transforms.ts +0 -206
- package/src/js/modules/payments/stub-payment-module.ts +0 -87
|
@@ -1,7 +1,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]';
|
|
@@ -55,6 +58,9 @@ type ComboboxSelect = HTMLSelectElement & {
|
|
|
55
58
|
|
|
56
59
|
type FieldState = {
|
|
57
60
|
addressRoot: HTMLElement;
|
|
61
|
+
isCpEdit: boolean;
|
|
62
|
+
initialCountry: string;
|
|
63
|
+
initialValue: string;
|
|
58
64
|
stateField: HTMLElement;
|
|
59
65
|
stateControl: AddressStateControl;
|
|
60
66
|
countryControl: HTMLInputElement | HTMLSelectElement | null;
|
|
@@ -102,7 +108,8 @@ function getStateControl(field: HTMLElement): AddressStateControl | null {
|
|
|
102
108
|
}
|
|
103
109
|
|
|
104
110
|
function getFieldLabel(field: HTMLElement): HTMLElement | null {
|
|
105
|
-
return field.querySelector('[data-formie-field-label]')
|
|
111
|
+
return field.querySelector('[data-formie-field-label]')
|
|
112
|
+
|| (field.querySelector('[data-formie-address-state-cp]') ? field.querySelector(':scope > .heading > label') : null);
|
|
106
113
|
}
|
|
107
114
|
|
|
108
115
|
function dispatchControlEvents(control: AddressStateControl): void {
|
|
@@ -127,13 +134,15 @@ function syncComboboxValue(control: AddressStateControl, value: string): void {
|
|
|
127
134
|
}
|
|
128
135
|
|
|
129
136
|
function setControlValue(control: AddressStateControl, value: string): void {
|
|
130
|
-
|
|
131
|
-
|
|
137
|
+
const previousValue = control.value;
|
|
138
|
+
control.value = value;
|
|
139
|
+
syncComboboxValue(control, control.value);
|
|
140
|
+
|
|
141
|
+
// A select rejects values outside its options. Dispatch only actual changes
|
|
142
|
+
// so an unmatched autofill value cannot recursively trigger reconciliation.
|
|
143
|
+
if (control.value !== previousValue) {
|
|
132
144
|
dispatchControlEvents(control);
|
|
133
|
-
return;
|
|
134
145
|
}
|
|
135
|
-
|
|
136
|
-
syncComboboxValue(control, value);
|
|
137
146
|
}
|
|
138
147
|
|
|
139
148
|
function syncAutofillAnchor(fieldState: FieldState, value: string): void {
|
|
@@ -178,6 +187,7 @@ function ensureAutofillAnchor(fieldState: FieldState): HTMLInputElement {
|
|
|
178
187
|
anchor.setAttribute('tabindex', '-1');
|
|
179
188
|
anchor.setAttribute('aria-hidden', 'true');
|
|
180
189
|
anchor.className = 'formie-sr-only';
|
|
190
|
+
anchor.hidden = fieldState.isCpEdit;
|
|
181
191
|
fieldState.addressRoot.appendChild(anchor);
|
|
182
192
|
fieldState.autofillAnchor = anchor;
|
|
183
193
|
}
|
|
@@ -201,18 +211,17 @@ function reconcileAutofillValue(fieldState: FieldState): void {
|
|
|
201
211
|
}
|
|
202
212
|
|
|
203
213
|
const subdivisions = fieldState.lastSubdivisions;
|
|
204
|
-
const resolved =
|
|
205
|
-
? (resolveOptionMatch(pending, subdivisions) ||
|
|
214
|
+
const resolved = fieldState.stateControl instanceof HTMLSelectElement
|
|
215
|
+
? (resolveOptionMatch(pending, subdivisions) || '')
|
|
206
216
|
: pending;
|
|
207
217
|
|
|
208
|
-
setControlValue(fieldState.stateControl, resolved);
|
|
209
|
-
syncComboboxValue(fieldState.stateControl, resolved);
|
|
210
218
|
syncAutofillAnchor(fieldState, resolved);
|
|
211
219
|
fieldState.pendingStateValue = resolved;
|
|
220
|
+
setControlValue(fieldState.stateControl, resolved);
|
|
212
221
|
}
|
|
213
222
|
|
|
214
223
|
function buildSubdivisionsUrl(action: string, country: string, optionLabel: string, optionValue: string): string {
|
|
215
|
-
const url = new URL(action.startsWith('/') ? action : `/actions/${action}`, window.location.origin);
|
|
224
|
+
const url = new URL(/^https?:\/\//.test(action) || action.startsWith('/') ? action : `/actions/${action}`, window.location.origin);
|
|
216
225
|
url.searchParams.set('country', country);
|
|
217
226
|
url.searchParams.set('optionLabel', optionLabel);
|
|
218
227
|
url.searchParams.set('optionValue', optionValue);
|
|
@@ -238,6 +247,7 @@ async function fetchSubdivisions(
|
|
|
238
247
|
optionLabel: string,
|
|
239
248
|
optionValue: string,
|
|
240
249
|
action: string,
|
|
250
|
+
requestOptions: BrowserRequestOptions,
|
|
241
251
|
): Promise<SubdivisionsResponse | null> {
|
|
242
252
|
const cacheKey = getSubdivisionsCacheKey(country, optionLabel, optionValue, action);
|
|
243
253
|
|
|
@@ -248,11 +258,11 @@ async function fetchSubdivisions(
|
|
|
248
258
|
if (!subdivisionInflight.has(cacheKey)) {
|
|
249
259
|
subdivisionInflight.set(cacheKey, (async() => {
|
|
250
260
|
try {
|
|
251
|
-
const response = await
|
|
261
|
+
const response = await browserRequest(buildSubdivisionsUrl(action, country, optionLabel, optionValue), {
|
|
252
262
|
headers: {
|
|
253
263
|
Accept: 'application/json',
|
|
254
264
|
},
|
|
255
|
-
});
|
|
265
|
+
}, requestOptions);
|
|
256
266
|
|
|
257
267
|
if (!response.ok) {
|
|
258
268
|
subdivisionDataCache.set(cacheKey, null);
|
|
@@ -316,6 +326,7 @@ function copyControlAttributes(source: AddressStateControl, target: AddressState
|
|
|
316
326
|
'data-formie-input-type',
|
|
317
327
|
'data-formie-input-error-state',
|
|
318
328
|
'data-formie-address-state-dynamic',
|
|
329
|
+
'data-formie-address-state-cp',
|
|
319
330
|
'data-formie-address-state-hide-when-unused',
|
|
320
331
|
'data-formie-address-state-use-searchable',
|
|
321
332
|
'data-formie-address-state-use-datalist',
|
|
@@ -336,15 +347,17 @@ function copyControlAttributes(source: AddressStateControl, target: AddressState
|
|
|
336
347
|
}
|
|
337
348
|
|
|
338
349
|
function applyTextThemeClasses(template: AddressStateControl, input: HTMLInputElement): void {
|
|
339
|
-
input.className = template.className;
|
|
350
|
+
input.className = template.hasAttribute('data-formie-address-state-cp') ? 'text fullwidth' : template.className;
|
|
340
351
|
}
|
|
341
352
|
|
|
342
353
|
function applySelectThemeClasses(template: AddressStateControl, select: HTMLSelectElement): void {
|
|
343
354
|
const classes: string[] = [...SELECT_THEME_CLASSES];
|
|
344
355
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
356
|
+
getThemeClasses(template, 'fieldControlError').forEach((className) => {
|
|
357
|
+
if (template.classList.contains(className)) {
|
|
358
|
+
classes.push(className);
|
|
359
|
+
}
|
|
360
|
+
});
|
|
348
361
|
|
|
349
362
|
select.className = classes.join(' ');
|
|
350
363
|
}
|
|
@@ -454,12 +467,17 @@ function syncDatalist(
|
|
|
454
467
|
function setFieldVisibility(fieldState: FieldState, visible: boolean): void {
|
|
455
468
|
const { stateField, stateControl, required } = fieldState;
|
|
456
469
|
|
|
457
|
-
stateField
|
|
458
|
-
|
|
470
|
+
toggleThemeClasses(stateField, stateField, 'conditionalHidden', !visible);
|
|
471
|
+
// Use module-owned visibility: the generic hidden attribute unmounts modules,
|
|
472
|
+
// which would remove the country listener needed to show this field again.
|
|
473
|
+
stateField.toggleAttribute('data-formie-address-state-hidden', !visible);
|
|
474
|
+
|
|
459
475
|
|
|
460
476
|
if (!visible) {
|
|
461
477
|
stateControl.required = false;
|
|
462
|
-
|
|
478
|
+
// Keep the empty value in Craft's serialized form data so hiding the
|
|
479
|
+
// field during initialization does not count as an unsaved edit.
|
|
480
|
+
stateControl.disabled = !fieldState.isCpEdit;
|
|
463
481
|
return;
|
|
464
482
|
}
|
|
465
483
|
|
|
@@ -473,7 +491,7 @@ function ensureFetchingAnnouncement(fieldState: FieldState): HTMLElement {
|
|
|
473
491
|
}
|
|
474
492
|
|
|
475
493
|
const announcement = document.createElement('div');
|
|
476
|
-
announcement.className = 'formie-sr-only';
|
|
494
|
+
announcement.className = fieldState.isCpEdit ? 'visually-hidden' : 'formie-sr-only';
|
|
477
495
|
announcement.setAttribute('data-formie-address-state-fetching-announce', 'true');
|
|
478
496
|
announcement.setAttribute('aria-live', 'polite');
|
|
479
497
|
announcement.setAttribute('aria-atomic', 'true');
|
|
@@ -502,8 +520,8 @@ function showFetchingUI(fieldState: FieldState): void {
|
|
|
502
520
|
fieldState.stateControl.setAttribute('aria-hidden', 'true');
|
|
503
521
|
fieldState.stateControl.setAttribute('tabindex', '-1');
|
|
504
522
|
|
|
505
|
-
fieldState.stateField.
|
|
506
|
-
fieldState.stateField.removeAttribute('data-formie-
|
|
523
|
+
toggleThemeClasses(fieldState.stateField, fieldState.stateField, 'conditionalHidden', false);
|
|
524
|
+
fieldState.stateField.removeAttribute('data-formie-address-state-hidden');
|
|
507
525
|
fieldState.stateField.setAttribute('data-formie-address-state-skeleton-active', 'true');
|
|
508
526
|
|
|
509
527
|
const controlWrapper = fieldState.stateField.querySelector('[data-formie-field-control]');
|
|
@@ -540,7 +558,7 @@ function updateFieldLabel(stateField: HTMLElement, label: string): void {
|
|
|
540
558
|
return;
|
|
541
559
|
}
|
|
542
560
|
|
|
543
|
-
const required = labelEl.querySelector('[data-formie-field-required]');
|
|
561
|
+
const required = labelEl.querySelector('[data-formie-field-required], .required');
|
|
544
562
|
labelEl.textContent = label;
|
|
545
563
|
|
|
546
564
|
if (required) {
|
|
@@ -589,6 +607,10 @@ async function applyCountryState(
|
|
|
589
607
|
const country = fieldState.countryControl?.value?.trim() || '';
|
|
590
608
|
stashPendingStateValue(fieldState);
|
|
591
609
|
const currentValue = getEffectiveStateValue(fieldState);
|
|
610
|
+
// Opening an existing submission must not discard a historical state value
|
|
611
|
+
// merely because current country metadata no longer includes it.
|
|
612
|
+
const preserveStoredValue = fieldState.isCpEdit && !!currentValue
|
|
613
|
+
&& country === fieldState.initialCountry && currentValue === fieldState.initialValue;
|
|
592
614
|
const fetchGeneration = ++fieldState.fetchGeneration;
|
|
593
615
|
|
|
594
616
|
fieldState.comboboxCleanup?.();
|
|
@@ -602,7 +624,7 @@ async function applyCountryState(
|
|
|
602
624
|
|
|
603
625
|
hideFetchingUI(fieldState);
|
|
604
626
|
|
|
605
|
-
if (hideWhenUnused) {
|
|
627
|
+
if (hideWhenUnused && !preserveStoredValue) {
|
|
606
628
|
setFieldVisibility(fieldState, false);
|
|
607
629
|
setControlValue(fieldState.stateControl, '');
|
|
608
630
|
syncAutofillAnchor(fieldState, '');
|
|
@@ -617,7 +639,7 @@ async function applyCountryState(
|
|
|
617
639
|
const textControl = createTextControl(fieldState.stateControl, currentValue);
|
|
618
640
|
fieldState.stateControl = replaceControl(fieldState.stateControl, textControl);
|
|
619
641
|
} else {
|
|
620
|
-
fieldState.stateControl.disabled =
|
|
642
|
+
fieldState.stateControl.disabled = !fieldState.isCpEdit && !preserveStoredValue;
|
|
621
643
|
fieldState.stateControl.placeholder = placeholder || fieldState.stateControl.placeholder;
|
|
622
644
|
}
|
|
623
645
|
|
|
@@ -632,20 +654,23 @@ async function applyCountryState(
|
|
|
632
654
|
showFetchingUI(fieldState);
|
|
633
655
|
}
|
|
634
656
|
|
|
635
|
-
const response = await fetchSubdivisions(country, optionLabel, optionValue, subdivisionsAction);
|
|
657
|
+
const response = await fetchSubdivisions(country, optionLabel, optionValue, subdivisionsAction, getFormBrowserRequestOptions(fieldState.addressRoot.closest('form')));
|
|
636
658
|
|
|
637
659
|
if (fetchGeneration !== fieldState.fetchGeneration) {
|
|
638
660
|
return;
|
|
639
661
|
}
|
|
640
662
|
|
|
641
|
-
const subdivisions = response?.subdivisions || [];
|
|
663
|
+
const subdivisions = [...(response?.subdivisions || [])];
|
|
664
|
+
if (preserveStoredValue && subdivisions.length && !resolveOptionMatch(currentValue, subdivisions)) {
|
|
665
|
+
subdivisions.push({ label: currentValue, value: currentValue });
|
|
666
|
+
}
|
|
642
667
|
const administrativeAreaUsed = response?.administrativeAreaUsed ?? true;
|
|
643
668
|
const administrativeAreaLabel = response?.administrativeAreaLabel || 'State / Province';
|
|
644
669
|
fieldState.lastSubdivisions = subdivisions;
|
|
645
670
|
|
|
646
671
|
hideFetchingUI(fieldState);
|
|
647
672
|
|
|
648
|
-
if (hideWhenUnused && !administrativeAreaUsed) {
|
|
673
|
+
if (hideWhenUnused && !administrativeAreaUsed && !preserveStoredValue) {
|
|
649
674
|
setFieldVisibility(fieldState, false);
|
|
650
675
|
setControlValue(fieldState.stateControl, '');
|
|
651
676
|
syncAutofillAnchor(fieldState, '');
|
|
@@ -749,6 +774,9 @@ function initAddressStateField(field: HTMLElement, options: AddressStateOptions)
|
|
|
749
774
|
|
|
750
775
|
const fieldState: FieldState = {
|
|
751
776
|
addressRoot,
|
|
777
|
+
isCpEdit: stateControl.hasAttribute('data-formie-address-state-cp'),
|
|
778
|
+
initialCountry: getCountryControl(addressRoot)?.value?.trim() || '',
|
|
779
|
+
initialValue: stateControl.value?.trim() || '',
|
|
752
780
|
stateField: field,
|
|
753
781
|
stateControl,
|
|
754
782
|
countryControl: getCountryControl(addressRoot),
|
|
@@ -766,6 +794,10 @@ function initAddressStateField(field: HTMLElement, options: AddressStateOptions)
|
|
|
766
794
|
lastSubdivisions: [],
|
|
767
795
|
};
|
|
768
796
|
|
|
797
|
+
const initialStateValue = stateControl.value;
|
|
798
|
+
const form = field.closest('form');
|
|
799
|
+
let disposed = false;
|
|
800
|
+
let resetTimer: number | null = null;
|
|
769
801
|
ensureAutofillAnchor(fieldState);
|
|
770
802
|
|
|
771
803
|
const refresh = (force = false) => {
|
|
@@ -824,6 +856,7 @@ function initAddressStateField(field: HTMLElement, options: AddressStateOptions)
|
|
|
824
856
|
|
|
825
857
|
if (isStateControl && !isAnchor) {
|
|
826
858
|
syncAutofillAnchor(fieldState, target.value);
|
|
859
|
+
fieldState.pendingStateValue = target.value;
|
|
827
860
|
}
|
|
828
861
|
|
|
829
862
|
stashPendingStateValue(fieldState);
|
|
@@ -885,12 +918,31 @@ function initAddressStateField(field: HTMLElement, options: AddressStateOptions)
|
|
|
885
918
|
syncAutofillAnchor(fieldState, stateValue);
|
|
886
919
|
|
|
887
920
|
void applyCountryState(fieldState, options).then(() => {
|
|
888
|
-
|
|
889
|
-
|
|
921
|
+
// Keep the normalized option value, which may differ from a provider's
|
|
922
|
+
// abbreviation (for example "CA" when options store "California").
|
|
923
|
+
reconcileAutofillValue(fieldState);
|
|
890
924
|
fieldState.lastCountry = fieldState.countryControl?.value?.trim() || '';
|
|
891
925
|
});
|
|
892
926
|
};
|
|
893
927
|
|
|
928
|
+
const onReset = (event: Event) => {
|
|
929
|
+
if (resetTimer !== null) window.clearTimeout(resetTimer);
|
|
930
|
+
// Enhanced selects finish their own reset in microtasks. Rebuild the
|
|
931
|
+
// dependent options after those controls have restored the country.
|
|
932
|
+
resetTimer = window.setTimeout(() => {
|
|
933
|
+
resetTimer = null;
|
|
934
|
+
if (event.defaultPrevented || disposed) return;
|
|
935
|
+
clearScheduledAutofillTimers(fieldState);
|
|
936
|
+
// The current select may contain another country's options. Keep the
|
|
937
|
+
// original value pending until the reset country's options are ready.
|
|
938
|
+
fieldState.stateControl.value = '';
|
|
939
|
+
fieldState.pendingStateValue = initialStateValue;
|
|
940
|
+
syncAutofillAnchor(fieldState, initialStateValue);
|
|
941
|
+
refresh(true);
|
|
942
|
+
}, 0);
|
|
943
|
+
};
|
|
944
|
+
form?.addEventListener('reset', onReset);
|
|
945
|
+
|
|
894
946
|
fieldState.countryControl?.addEventListener('change', onCountryChange);
|
|
895
947
|
fieldState.countryControl?.addEventListener('input', onCountryChange);
|
|
896
948
|
addressRoot.addEventListener('input', onAddressInput);
|
|
@@ -901,10 +953,15 @@ function initAddressStateField(field: HTMLElement, options: AddressStateOptions)
|
|
|
901
953
|
addressRoot.addEventListener('formie:address:loqate:populate', onProviderPopulate);
|
|
902
954
|
addressRoot.addEventListener('formie:address:place-kit:populate', onProviderPopulate);
|
|
903
955
|
|
|
904
|
-
|
|
956
|
+
// Apply the empty-country visibility state on first mount as well.
|
|
957
|
+
refresh(true);
|
|
905
958
|
scheduleAutofillSweep(fieldState, options);
|
|
906
959
|
|
|
907
960
|
return () => {
|
|
961
|
+
disposed = true;
|
|
962
|
+
if (resetTimer !== null) window.clearTimeout(resetTimer);
|
|
963
|
+
fieldState.fetchGeneration++;
|
|
964
|
+
form?.removeEventListener('reset', onReset);
|
|
908
965
|
clearScheduledAutofillTimers(fieldState);
|
|
909
966
|
hideFetchingUI(fieldState);
|
|
910
967
|
fieldState.skeletonEl?.remove();
|
|
@@ -923,8 +980,10 @@ function initAddressStateField(field: HTMLElement, options: AddressStateOptions)
|
|
|
923
980
|
};
|
|
924
981
|
}
|
|
925
982
|
|
|
926
|
-
export const addressStateModule:
|
|
927
|
-
|
|
983
|
+
export const addressStateModule: BrowserModuleDefinition = {
|
|
984
|
+
moduleId: `formie:${MODULE_ID}`,
|
|
985
|
+
version: 2,
|
|
986
|
+
surfaces: ['server-rendered', 'client-rendered', 'cp-edit'],
|
|
928
987
|
kind: 'field',
|
|
929
988
|
match: (ctx) => {
|
|
930
989
|
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,10 +1,12 @@
|
|
|
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';
|
|
9
|
+
import { VALIDATION_SKIP_ATTR } from '#validation/skip';
|
|
8
10
|
|
|
9
11
|
const SELECT_SELECTOR = 'select[data-formie-combobox-input]';
|
|
10
12
|
const MODULE_ID = 'combobox';
|
|
@@ -15,7 +17,6 @@ ensureModuleStyles(MODULE_ID, [comboboxThemeCss]);
|
|
|
15
17
|
const NATIVE_THEME_CLASSES = [
|
|
16
18
|
'formie-select',
|
|
17
19
|
'formie-dropdown-input',
|
|
18
|
-
'formie-input-error',
|
|
19
20
|
] as const;
|
|
20
21
|
|
|
21
22
|
export type FormieComboboxOptions = {
|
|
@@ -35,7 +36,7 @@ type SelectElement = HTMLSelectElement & {
|
|
|
35
36
|
function stripNativeThemeClasses(select: HTMLSelectElement): string[] {
|
|
36
37
|
const removed: string[] = [];
|
|
37
38
|
|
|
38
|
-
NATIVE_THEME_CLASSES.forEach((className) => {
|
|
39
|
+
[...NATIVE_THEME_CLASSES, ...getThemeClasses(select, 'fieldControlError')].forEach((className) => {
|
|
39
40
|
if (select.classList.contains(className)) {
|
|
40
41
|
select.classList.remove(className);
|
|
41
42
|
removed.push(className);
|
|
@@ -51,8 +52,8 @@ function restoreNativeThemeClasses(select: HTMLSelectElement, classNames: string
|
|
|
51
52
|
});
|
|
52
53
|
}
|
|
53
54
|
|
|
54
|
-
function cleanLeakedThemeClasses(element: HTMLElement): void {
|
|
55
|
-
NATIVE_THEME_CLASSES.forEach((className) => {
|
|
55
|
+
function cleanLeakedThemeClasses(element: HTMLElement, source: HTMLSelectElement): void {
|
|
56
|
+
[...NATIVE_THEME_CLASSES, ...getThemeClasses(source, 'fieldControlError')].forEach((className) => {
|
|
56
57
|
element.classList.remove(className);
|
|
57
58
|
});
|
|
58
59
|
}
|
|
@@ -78,6 +79,8 @@ function removeEmptyOptionFromCombobox(instance: TomSelectInstance): void {
|
|
|
78
79
|
export function initFormieCombobox(select: SelectElement, options: FormieComboboxOptions = {}): () => void {
|
|
79
80
|
select._formieTomSelect?.destroy();
|
|
80
81
|
|
|
82
|
+
const initialValues = Array.from(select.selectedOptions, (option) => option.value).filter(Boolean);
|
|
83
|
+
const form = select.form;
|
|
81
84
|
const multiple = options.multiple === true;
|
|
82
85
|
const restoredClasses = stripNativeThemeClasses(select);
|
|
83
86
|
const placeholder = resolvePlaceholder(select, options.placeholder);
|
|
@@ -114,11 +117,13 @@ export function initFormieCombobox(select: SelectElement, options: FormieCombobo
|
|
|
114
117
|
});
|
|
115
118
|
|
|
116
119
|
const instance = new TomSelect(select, mergedOptions) as TomSelectInstance;
|
|
120
|
+
// The search query is temporary; the native select carries the field value.
|
|
121
|
+
instance.control_input.setAttribute(VALIDATION_SKIP_ATTR, '');
|
|
117
122
|
removeEmptyOptionFromCombobox(instance);
|
|
118
|
-
cleanLeakedThemeClasses(instance.wrapper);
|
|
123
|
+
cleanLeakedThemeClasses(instance.wrapper, select);
|
|
119
124
|
|
|
120
125
|
if (instance.dropdown) {
|
|
121
|
-
cleanLeakedThemeClasses(instance.dropdown);
|
|
126
|
+
cleanLeakedThemeClasses(instance.dropdown, select);
|
|
122
127
|
}
|
|
123
128
|
|
|
124
129
|
// Tom Select keeps the native select as a preceding sibling; ensure it never
|
|
@@ -127,6 +132,17 @@ export function initFormieCombobox(select: SelectElement, options: FormieCombobo
|
|
|
127
132
|
|
|
128
133
|
select._formieTomSelect = instance;
|
|
129
134
|
|
|
135
|
+
const onReset = (event: Event) => {
|
|
136
|
+
// Tom Select replaces native options, so retain the original selection
|
|
137
|
+
// and restore its display after the browser resets the backing select.
|
|
138
|
+
queueMicrotask(() => {
|
|
139
|
+
if (!event.defaultPrevented) {
|
|
140
|
+
instance.setValue(initialValues);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
};
|
|
144
|
+
form?.addEventListener('reset', onReset);
|
|
145
|
+
|
|
130
146
|
debug.log('Initialized.', {
|
|
131
147
|
inputName: select.name,
|
|
132
148
|
multiple,
|
|
@@ -138,6 +154,7 @@ export function initFormieCombobox(select: SelectElement, options: FormieCombobo
|
|
|
138
154
|
});
|
|
139
155
|
|
|
140
156
|
return () => {
|
|
157
|
+
form?.removeEventListener('reset', onReset);
|
|
141
158
|
instance.destroy();
|
|
142
159
|
select.style.removeProperty('display');
|
|
143
160
|
restoreNativeThemeClasses(select, restoredClasses);
|
|
@@ -148,8 +165,10 @@ export function initFormieCombobox(select: SelectElement, options: FormieCombobo
|
|
|
148
165
|
};
|
|
149
166
|
}
|
|
150
167
|
|
|
151
|
-
export const comboboxModule:
|
|
152
|
-
|
|
168
|
+
export const comboboxModule: BrowserModuleDefinition = {
|
|
169
|
+
moduleId: `formie:${MODULE_ID}`,
|
|
170
|
+
version: 2,
|
|
171
|
+
surfaces: ['server-rendered', 'client-rendered', 'cp-edit'],
|
|
153
172
|
kind: 'field',
|
|
154
173
|
match: (ctx) => {
|
|
155
174
|
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
|
}
|