@verbb/formie-browser 1.0.0
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 +5 -0
- package/LICENSE.md +40 -0
- package/README.md +34 -0
- package/dist/chunks/address-finder-DfMCiW89.js +47 -0
- package/dist/chunks/api-CbqEMQT5.js +181 -0
- package/dist/chunks/api-DE7LfK-R.js +960 -0
- package/dist/chunks/api-DOfDzYC_.js +538 -0
- package/dist/chunks/async-B3DUf1GZ.js +26 -0
- package/dist/chunks/bpoint-Ciy3yY9Q.js +34 -0
- package/dist/chunks/calculations-CkYAqO_-.js +197 -0
- package/dist/chunks/captcha-eu-DnOWhMwr.js +43 -0
- package/dist/chunks/checkbox-radio-0x7Tc0br.js +197 -0
- package/dist/chunks/chunk-K6L4z4UQ.js +24 -0
- package/dist/chunks/conditions-4fXKhEJS.js +609 -0
- package/dist/chunks/date-picker-B6iZkjHS.js +6204 -0
- package/dist/chunks/debug-KnZeKYBI.js +39 -0
- package/dist/chunks/dist-D09GnXMW.js +2663 -0
- package/dist/chunks/event-names-DamGPtXR.js +51 -0
- package/dist/chunks/eway-DEAYcwT0.js +86 -0
- package/dist/chunks/field-references.keys-BpBZ_quS.js +24 -0
- package/dist/chunks/field-references.resolver-Ba6xhiJC.js +183 -0
- package/dist/chunks/file-upload-Bh63PQSE.js +430 -0
- package/dist/chunks/friendly-captcha-v1-CqO4WVre.js +40 -0
- package/dist/chunks/friendly-captcha-v2-CyykcJcM.js +47 -0
- package/dist/chunks/friendly-challenge-Dg8XkStd.js +1101 -0
- package/dist/chunks/go-cardless-CuND59rR.js +26 -0
- package/dist/chunks/google-address--uR8WDSm.js +208 -0
- package/dist/chunks/hcaptcha-CmaFUesv.js +72 -0
- package/dist/chunks/hidden-CYnZYple.js +36 -0
- package/dist/chunks/http-18nn97DZ.js +29 -0
- package/dist/chunks/i18n-vUh-KGiH.js +55 -0
- package/dist/chunks/loqate-BICNJlVK.js +97 -0
- package/dist/chunks/mollie-DwlsgHZ1.js +26 -0
- package/dist/chunks/moneris-B_IFZFTx.js +159 -0
- package/dist/chunks/opayo-U2x_TOII.js +192 -0
- package/dist/chunks/paddle-BqXFrc79.js +75 -0
- package/dist/chunks/paypal-Cn_DYGDb.js +121 -0
- package/dist/chunks/payway-Rnq796eC.js +75 -0
- package/dist/chunks/phone-country-B6Me4lK0.js +3317 -0
- package/dist/chunks/place-kit-ldUl-u9w.js +56 -0
- package/dist/chunks/placekit-autocomplete.esm-D-lGeaZl.js +1771 -0
- package/dist/chunks/recaptcha-enterprise-DPJNyv1X.js +72 -0
- package/dist/chunks/recaptcha-shared-DTI4qWVR.js +22 -0
- package/dist/chunks/recaptcha-v2-checkbox-zFjpvJ5c.js +49 -0
- package/dist/chunks/recaptcha-v2-invisible-CnYtkNvz.js +62 -0
- package/dist/chunks/recaptcha-v3-EAlWhnkX.js +33 -0
- package/dist/chunks/repeater-CXD1eLSn.js +151 -0
- package/dist/chunks/rich-text-DkmZRhGj.js +442 -0
- package/dist/chunks/scripts-BGD_iU_6.js +41 -0
- package/dist/chunks/sdk-B7u9fTlP.js +2103 -0
- package/dist/chunks/shared-DC6_1u8X.js +85 -0
- package/dist/chunks/signature-E9KyYXS1.js +765 -0
- package/dist/chunks/snaptcha-CCDunGeb.js +8 -0
- package/dist/chunks/square-BLqK51rS.js +61 -0
- package/dist/chunks/stripe-B8gHpZNC.js +273 -0
- package/dist/chunks/styles-BIh6g7V_.js +22 -0
- package/dist/chunks/summary-EcNE0cvg.js +191 -0
- package/dist/chunks/table-yxEDL6kA.js +124 -0
- package/dist/chunks/text-limit-D0H_Ca2c.js +179 -0
- package/dist/chunks/theme-classes-vSHpdCUO.js +59 -0
- package/dist/chunks/turnstile-DP0bdR7T.js +68 -0
- package/dist/chunks/utils-ByrEVYrJ.js +49584 -0
- package/dist/css/formie-base.css +78 -0
- package/dist/css/formie-theme.css +19 -0
- package/dist/css/formie.css +2 -0
- package/dist/css/theme/_buttons.css +249 -0
- package/dist/css/theme/_loading.css +37 -0
- package/dist/css/theme/_messages.css +39 -0
- package/dist/css/theme/_progress.css +62 -0
- package/dist/css/theme/_tokens.css +361 -0
- package/dist/css/theme/_typography.css +70 -0
- package/dist/css/theme/fields/_address.css +17 -0
- package/dist/css/theme/fields/_check-radio.css +108 -0
- package/dist/css/theme/fields/_file.css +58 -0
- package/dist/css/theme/fields/_group.css +13 -0
- package/dist/css/theme/fields/_input.css +48 -0
- package/dist/css/theme/fields/_nested.css +19 -0
- package/dist/css/theme/fields/_repeater.css +69 -0
- package/dist/css/theme/fields/_rich-text.css +201 -0
- package/dist/css/theme/fields/_select.css +37 -0
- package/dist/css/theme/fields/_signature.css +39 -0
- package/dist/css/theme/fields/_summary.css +53 -0
- package/dist/css/theme/fields/_table.css +121 -0
- package/dist/css/theme/fields/_text-limit.css +10 -0
- package/dist/css/theme/forms/_field.css +62 -0
- package/dist/css/theme/forms/_form.css +166 -0
- package/dist/css/theme/integrations/_payment-modal.css +32 -0
- package/dist/css/theme/integrations/_paypal.css +10 -0
- package/dist/css/theme/integrations/_payway.css +10 -0
- package/dist/css/theme/integrations/_stripe.css +24 -0
- package/dist/css/theme/utilities/_accessibility.css +13 -0
- package/dist/css/theme-base/_controls.css +41 -0
- package/dist/css/theme-base/_primitives.css +34 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3206 -0
- package/dist/js/compatibility/dom-adapter.d.ts +12 -0
- package/dist/js/compatibility/dom-adapter.d.ts.map +1 -0
- package/dist/js/compatibility/event-map.d.ts +25 -0
- package/dist/js/compatibility/event-map.d.ts.map +1 -0
- package/dist/js/compatibility/validator-adapter.d.ts +17 -0
- package/dist/js/compatibility/validator-adapter.d.ts.map +1 -0
- package/dist/js/contracts/client.d.ts +40 -0
- package/dist/js/contracts/client.d.ts.map +1 -0
- package/dist/js/contracts/common.d.ts +5 -0
- package/dist/js/contracts/common.d.ts.map +1 -0
- package/dist/js/contracts/modules.d.ts +47 -0
- package/dist/js/contracts/modules.d.ts.map +1 -0
- package/dist/js/contracts/schema.d.ts +79 -0
- package/dist/js/contracts/schema.d.ts.map +1 -0
- package/dist/js/contracts/theme.d.ts +2 -0
- package/dist/js/contracts/theme.d.ts.map +1 -0
- package/dist/js/core/create-formie-client.d.ts +3 -0
- package/dist/js/core/create-formie-client.d.ts.map +1 -0
- package/dist/js/core/dom-events.d.ts +2 -0
- package/dist/js/core/dom-events.d.ts.map +1 -0
- package/dist/js/core/formie.d.ts +27 -0
- package/dist/js/core/formie.d.ts.map +1 -0
- package/dist/js/core/hydrate-modules.d.ts +22 -0
- package/dist/js/core/hydrate-modules.d.ts.map +1 -0
- package/dist/js/core/page-client-event.d.ts +9 -0
- package/dist/js/core/page-client-event.d.ts.map +1 -0
- package/dist/js/core/page-tab-errors.d.ts +2 -0
- package/dist/js/core/page-tab-errors.d.ts.map +1 -0
- package/dist/js/core/submit-flow.d.ts +21 -0
- package/dist/js/core/submit-flow.d.ts.map +1 -0
- package/dist/js/core/submit-result-state.d.ts +8 -0
- package/dist/js/core/submit-result-state.d.ts.map +1 -0
- package/dist/js/core/submit-result-ui.d.ts +10 -0
- package/dist/js/core/submit-result-ui.d.ts.map +1 -0
- package/dist/js/events/event-bus.d.ts +21 -0
- package/dist/js/events/event-bus.d.ts.map +1 -0
- package/dist/js/modules/address/address-finder.d.ts +2 -0
- package/dist/js/modules/address/address-finder.d.ts.map +1 -0
- package/dist/js/modules/address/api.d.ts +8 -0
- package/dist/js/modules/address/api.d.ts.map +1 -0
- package/dist/js/modules/address/constants.d.ts +15 -0
- package/dist/js/modules/address/constants.d.ts.map +1 -0
- package/dist/js/modules/address/factories.d.ts +35 -0
- package/dist/js/modules/address/factories.d.ts.map +1 -0
- package/dist/js/modules/address/google-address.d.ts +2 -0
- package/dist/js/modules/address/google-address.d.ts.map +1 -0
- package/dist/js/modules/address/host.d.ts +30 -0
- package/dist/js/modules/address/host.d.ts.map +1 -0
- package/dist/js/modules/address/index.d.ts +3 -0
- package/dist/js/modules/address/index.d.ts.map +1 -0
- package/dist/js/modules/address/loqate.d.ts +2 -0
- package/dist/js/modules/address/loqate.d.ts.map +1 -0
- package/dist/js/modules/address/place-kit.d.ts +2 -0
- package/dist/js/modules/address/place-kit.d.ts.map +1 -0
- package/dist/js/modules/captchas/api.d.ts +9 -0
- package/dist/js/modules/captchas/api.d.ts.map +1 -0
- package/dist/js/modules/captchas/captcha-eu.d.ts +2 -0
- package/dist/js/modules/captchas/captcha-eu.d.ts.map +1 -0
- package/dist/js/modules/captchas/constants.d.ts +5 -0
- package/dist/js/modules/captchas/constants.d.ts.map +1 -0
- package/dist/js/modules/captchas/factories.d.ts +63 -0
- package/dist/js/modules/captchas/factories.d.ts.map +1 -0
- package/dist/js/modules/captchas/friendly-captcha-v1.d.ts +2 -0
- package/dist/js/modules/captchas/friendly-captcha-v1.d.ts.map +1 -0
- package/dist/js/modules/captchas/friendly-captcha-v2.d.ts +2 -0
- package/dist/js/modules/captchas/friendly-captcha-v2.d.ts.map +1 -0
- package/dist/js/modules/captchas/hcaptcha.d.ts +2 -0
- package/dist/js/modules/captchas/hcaptcha.d.ts.map +1 -0
- package/dist/js/modules/captchas/host.d.ts +78 -0
- package/dist/js/modules/captchas/host.d.ts.map +1 -0
- package/dist/js/modules/captchas/index.d.ts +3 -0
- package/dist/js/modules/captchas/index.d.ts.map +1 -0
- package/dist/js/modules/captchas/recaptcha-enterprise.d.ts +2 -0
- package/dist/js/modules/captchas/recaptcha-enterprise.d.ts.map +1 -0
- package/dist/js/modules/captchas/recaptcha-shared.d.ts +26 -0
- package/dist/js/modules/captchas/recaptcha-shared.d.ts.map +1 -0
- package/dist/js/modules/captchas/recaptcha-v2-checkbox.d.ts +2 -0
- package/dist/js/modules/captchas/recaptcha-v2-checkbox.d.ts.map +1 -0
- package/dist/js/modules/captchas/recaptcha-v2-invisible.d.ts +2 -0
- package/dist/js/modules/captchas/recaptcha-v2-invisible.d.ts.map +1 -0
- package/dist/js/modules/captchas/recaptcha-v3.d.ts +2 -0
- package/dist/js/modules/captchas/recaptcha-v3.d.ts.map +1 -0
- package/dist/js/modules/captchas/snaptcha.d.ts +2 -0
- package/dist/js/modules/captchas/snaptcha.d.ts.map +1 -0
- package/dist/js/modules/captchas/turnstile.d.ts +2 -0
- package/dist/js/modules/captchas/turnstile.d.ts.map +1 -0
- package/dist/js/modules/captchas/utils.d.ts +13 -0
- package/dist/js/modules/captchas/utils.d.ts.map +1 -0
- package/dist/js/modules/fields/calculations.d.ts +3 -0
- package/dist/js/modules/fields/calculations.d.ts.map +1 -0
- package/dist/js/modules/fields/checkbox-radio.d.ts +3 -0
- package/dist/js/modules/fields/checkbox-radio.d.ts.map +1 -0
- package/dist/js/modules/fields/conditions/config.d.ts +5 -0
- package/dist/js/modules/fields/conditions/config.d.ts.map +1 -0
- package/dist/js/modules/fields/conditions/effects.d.ts +2 -0
- package/dist/js/modules/fields/conditions/effects.d.ts.map +1 -0
- package/dist/js/modules/fields/conditions/evaluator.d.ts +6 -0
- package/dist/js/modules/fields/conditions/evaluator.d.ts.map +1 -0
- package/dist/js/modules/fields/conditions/references.d.ts +5 -0
- package/dist/js/modules/fields/conditions/references.d.ts.map +1 -0
- package/dist/js/modules/fields/conditions/transforms.d.ts +3 -0
- package/dist/js/modules/fields/conditions/transforms.d.ts.map +1 -0
- package/dist/js/modules/fields/conditions/types.d.ts +30 -0
- package/dist/js/modules/fields/conditions/types.d.ts.map +1 -0
- package/dist/js/modules/fields/conditions/values.d.ts +5 -0
- package/dist/js/modules/fields/conditions/values.d.ts.map +1 -0
- package/dist/js/modules/fields/conditions.d.ts +3 -0
- package/dist/js/modules/fields/conditions.d.ts.map +1 -0
- package/dist/js/modules/fields/date-picker.d.ts +3 -0
- package/dist/js/modules/fields/date-picker.d.ts.map +1 -0
- package/dist/js/modules/fields/file-upload.d.ts +3 -0
- package/dist/js/modules/fields/file-upload.d.ts.map +1 -0
- package/dist/js/modules/fields/hidden.d.ts +3 -0
- package/dist/js/modules/fields/hidden.d.ts.map +1 -0
- package/dist/js/modules/fields/index.d.ts +3 -0
- package/dist/js/modules/fields/index.d.ts.map +1 -0
- package/dist/js/modules/fields/phone-country.d.ts +3 -0
- package/dist/js/modules/fields/phone-country.d.ts.map +1 -0
- package/dist/js/modules/fields/repeater.d.ts +3 -0
- package/dist/js/modules/fields/repeater.d.ts.map +1 -0
- package/dist/js/modules/fields/rich-text.d.ts +3 -0
- package/dist/js/modules/fields/rich-text.d.ts.map +1 -0
- package/dist/js/modules/fields/shared.d.ts +20 -0
- package/dist/js/modules/fields/shared.d.ts.map +1 -0
- package/dist/js/modules/fields/signature.d.ts +3 -0
- package/dist/js/modules/fields/signature.d.ts.map +1 -0
- package/dist/js/modules/fields/summary.d.ts +3 -0
- package/dist/js/modules/fields/summary.d.ts.map +1 -0
- package/dist/js/modules/fields/table.d.ts +3 -0
- package/dist/js/modules/fields/table.d.ts.map +1 -0
- package/dist/js/modules/fields/text-limit.d.ts +3 -0
- package/dist/js/modules/fields/text-limit.d.ts.map +1 -0
- package/dist/js/modules/loader.d.ts +11 -0
- package/dist/js/modules/loader.d.ts.map +1 -0
- package/dist/js/modules/payments/api.d.ts +8 -0
- package/dist/js/modules/payments/api.d.ts.map +1 -0
- package/dist/js/modules/payments/bpoint.d.ts +2 -0
- package/dist/js/modules/payments/bpoint.d.ts.map +1 -0
- package/dist/js/modules/payments/constants.d.ts +5 -0
- package/dist/js/modules/payments/constants.d.ts.map +1 -0
- package/dist/js/modules/payments/eway.d.ts +9 -0
- package/dist/js/modules/payments/eway.d.ts.map +1 -0
- package/dist/js/modules/payments/factories.d.ts +54 -0
- package/dist/js/modules/payments/factories.d.ts.map +1 -0
- package/dist/js/modules/payments/go-cardless.d.ts +2 -0
- package/dist/js/modules/payments/go-cardless.d.ts.map +1 -0
- package/dist/js/modules/payments/host.d.ts +70 -0
- package/dist/js/modules/payments/host.d.ts.map +1 -0
- package/dist/js/modules/payments/index.d.ts +3 -0
- package/dist/js/modules/payments/index.d.ts.map +1 -0
- package/dist/js/modules/payments/mollie.d.ts +2 -0
- package/dist/js/modules/payments/mollie.d.ts.map +1 -0
- package/dist/js/modules/payments/moneris.d.ts +2 -0
- package/dist/js/modules/payments/moneris.d.ts.map +1 -0
- package/dist/js/modules/payments/opayo.d.ts +25 -0
- package/dist/js/modules/payments/opayo.d.ts.map +1 -0
- package/dist/js/modules/payments/paddle.d.ts +2 -0
- package/dist/js/modules/payments/paddle.d.ts.map +1 -0
- package/dist/js/modules/payments/paypal.d.ts +2 -0
- package/dist/js/modules/payments/paypal.d.ts.map +1 -0
- package/dist/js/modules/payments/payway.d.ts +2 -0
- package/dist/js/modules/payments/payway.d.ts.map +1 -0
- package/dist/js/modules/payments/square.d.ts +2 -0
- package/dist/js/modules/payments/square.d.ts.map +1 -0
- package/dist/js/modules/payments/stripe.d.ts +2 -0
- package/dist/js/modules/payments/stripe.d.ts.map +1 -0
- package/dist/js/modules/payments/utils.d.ts +17 -0
- package/dist/js/modules/payments/utils.d.ts.map +1 -0
- package/dist/js/modules/registry.d.ts +9 -0
- package/dist/js/modules/registry.d.ts.map +1 -0
- package/dist/js/modules/styles.d.ts +2 -0
- package/dist/js/modules/styles.d.ts.map +1 -0
- package/dist/js/submit/pipeline.d.ts +18 -0
- package/dist/js/submit/pipeline.d.ts.map +1 -0
- package/dist/js/theme/theme-classes.d.ts +10 -0
- package/dist/js/theme/theme-classes.d.ts.map +1 -0
- package/dist/js/transport/forms-api.d.ts +11 -0
- package/dist/js/transport/forms-api.d.ts.map +1 -0
- package/dist/js/utils/async.d.ts +8 -0
- package/dist/js/utils/async.d.ts.map +1 -0
- package/dist/js/utils/debug.d.ts +10 -0
- package/dist/js/utils/debug.d.ts.map +1 -0
- package/dist/js/utils/event-names.d.ts +13 -0
- package/dist/js/utils/event-names.d.ts.map +1 -0
- package/dist/js/utils/field-references.d.ts +6 -0
- package/dist/js/utils/field-references.d.ts.map +1 -0
- package/dist/js/utils/field-references.keys.d.ts +4 -0
- package/dist/js/utils/field-references.keys.d.ts.map +1 -0
- package/dist/js/utils/field-references.parser.d.ts +3 -0
- package/dist/js/utils/field-references.parser.d.ts.map +1 -0
- package/dist/js/utils/field-references.registry.d.ts +3 -0
- package/dist/js/utils/field-references.registry.d.ts.map +1 -0
- package/dist/js/utils/field-references.resolver.d.ts +4 -0
- package/dist/js/utils/field-references.resolver.d.ts.map +1 -0
- package/dist/js/utils/field-references.types.d.ts +27 -0
- package/dist/js/utils/field-references.types.d.ts.map +1 -0
- package/dist/js/utils/fields.d.ts +5 -0
- package/dist/js/utils/fields.d.ts.map +1 -0
- package/dist/js/utils/http.d.ts +9 -0
- package/dist/js/utils/http.d.ts.map +1 -0
- package/dist/js/utils/i18n.d.ts +7 -0
- package/dist/js/utils/i18n.d.ts.map +1 -0
- package/dist/js/utils/scripts.d.ts +13 -0
- package/dist/js/utils/scripts.d.ts.map +1 -0
- package/dist/js/utils/unload-warning.d.ts +10 -0
- package/dist/js/utils/unload-warning.d.ts.map +1 -0
- package/dist/js/validation/rules/email.d.ts +4 -0
- package/dist/js/validation/rules/email.d.ts.map +1 -0
- package/dist/js/validation/rules/match.d.ts +4 -0
- package/dist/js/validation/rules/match.d.ts.map +1 -0
- package/dist/js/validation/rules/number.d.ts +4 -0
- package/dist/js/validation/rules/number.d.ts.map +1 -0
- package/dist/js/validation/rules/required.d.ts +4 -0
- package/dist/js/validation/rules/required.d.ts.map +1 -0
- package/dist/js/validation/rules/shared.d.ts +7 -0
- package/dist/js/validation/rules/shared.d.ts.map +1 -0
- package/dist/js/validation/rules/url.d.ts +4 -0
- package/dist/js/validation/rules/url.d.ts.map +1 -0
- package/dist/js/validation/rules.d.ts +10 -0
- package/dist/js/validation/rules.d.ts.map +1 -0
- package/dist/js/validation/types.d.ts +44 -0
- package/dist/js/validation/types.d.ts.map +1 -0
- package/dist/js/validation/validator.d.ts +53 -0
- package/dist/js/validation/validator.d.ts.map +1 -0
- package/package.json +78 -0
- package/src/css/formie-base.css +78 -0
- package/src/css/formie-theme.css +19 -0
- package/src/css/formie.css +2 -0
- package/src/css/theme/_buttons.css +249 -0
- package/src/css/theme/_loading.css +37 -0
- package/src/css/theme/_messages.css +39 -0
- package/src/css/theme/_progress.css +62 -0
- package/src/css/theme/_tokens.css +361 -0
- package/src/css/theme/_typography.css +70 -0
- package/src/css/theme/fields/_address.css +17 -0
- package/src/css/theme/fields/_check-radio.css +108 -0
- package/src/css/theme/fields/_file.css +58 -0
- package/src/css/theme/fields/_group.css +13 -0
- package/src/css/theme/fields/_input.css +48 -0
- package/src/css/theme/fields/_nested.css +19 -0
- package/src/css/theme/fields/_repeater.css +69 -0
- package/src/css/theme/fields/_rich-text.css +201 -0
- package/src/css/theme/fields/_select.css +37 -0
- package/src/css/theme/fields/_signature.css +39 -0
- package/src/css/theme/fields/_summary.css +53 -0
- package/src/css/theme/fields/_table.css +121 -0
- package/src/css/theme/fields/_text-limit.css +10 -0
- package/src/css/theme/forms/_field.css +62 -0
- package/src/css/theme/forms/_form.css +166 -0
- package/src/css/theme/integrations/_payment-modal.css +32 -0
- package/src/css/theme/integrations/_paypal.css +10 -0
- package/src/css/theme/integrations/_payway.css +10 -0
- package/src/css/theme/integrations/_stripe.css +24 -0
- package/src/css/theme/utilities/_accessibility.css +13 -0
- package/src/css/theme-base/_controls.css +41 -0
- package/src/css/theme-base/_primitives.css +34 -0
- package/src/icons/rich-text/aligncenter.svg +6 -0
- package/src/icons/rich-text/alignleft.svg +6 -0
- package/src/icons/rich-text/alignright.svg +6 -0
- package/src/icons/rich-text/bold.svg +4 -0
- package/src/icons/rich-text/clear.svg +6 -0
- package/src/icons/rich-text/code.svg +4 -0
- package/src/icons/rich-text/heading1.svg +3 -0
- package/src/icons/rich-text/heading2.svg +3 -0
- package/src/icons/rich-text/image.svg +6 -0
- package/src/icons/rich-text/italic.svg +5 -0
- package/src/icons/rich-text/line.svg +3 -0
- package/src/icons/rich-text/link.svg +4 -0
- package/src/icons/rich-text/olist.svg +8 -0
- package/src/icons/rich-text/paragraph.svg +3 -0
- package/src/icons/rich-text/quote.svg +4 -0
- package/src/icons/rich-text/strikethrough.svg +4 -0
- package/src/icons/rich-text/ulist.svg +8 -0
- package/src/icons/rich-text/underline.svg +4 -0
- package/src/index.ts +125 -0
- package/src/js/compatibility/dom-adapter.ts +129 -0
- package/src/js/compatibility/event-map.ts +72 -0
- package/src/js/compatibility/validator-adapter.ts +105 -0
- package/src/js/contracts/client.ts +43 -0
- package/src/js/contracts/common.ts +14 -0
- package/src/js/contracts/modules.ts +53 -0
- package/src/js/contracts/schema.ts +83 -0
- package/src/js/contracts/theme.ts +1 -0
- package/src/js/core/create-formie-client.ts +1519 -0
- package/src/js/core/dom-events.ts +8 -0
- package/src/js/core/formie.ts +242 -0
- package/src/js/core/hydrate-modules.ts +102 -0
- package/src/js/core/page-client-event.ts +129 -0
- package/src/js/core/page-tab-errors.ts +37 -0
- package/src/js/core/submit-flow.ts +120 -0
- package/src/js/core/submit-result-state.ts +597 -0
- package/src/js/core/submit-result-ui.ts +448 -0
- package/src/js/events/event-bus.ts +109 -0
- package/src/js/modules/address/address-finder.ts +85 -0
- package/src/js/modules/address/api.ts +22 -0
- package/src/js/modules/address/constants.ts +15 -0
- package/src/js/modules/address/factories.ts +203 -0
- package/src/js/modules/address/google-address.ts +345 -0
- package/src/js/modules/address/host.ts +137 -0
- package/src/js/modules/address/index.ts +10 -0
- package/src/js/modules/address/loqate.ts +128 -0
- package/src/js/modules/address/place-kit.ts +94 -0
- package/src/js/modules/captchas/api.ts +25 -0
- package/src/js/modules/captchas/captcha-eu.ts +86 -0
- package/src/js/modules/captchas/constants.ts +4 -0
- package/src/js/modules/captchas/factories.ts +485 -0
- package/src/js/modules/captchas/friendly-captcha-v1.ts +65 -0
- package/src/js/modules/captchas/friendly-captcha-v2.ts +84 -0
- package/src/js/modules/captchas/hcaptcha.ts +153 -0
- package/src/js/modules/captchas/host.ts +448 -0
- package/src/js/modules/captchas/index.ts +16 -0
- package/src/js/modules/captchas/recaptcha-enterprise.ts +138 -0
- package/src/js/modules/captchas/recaptcha-shared.ts +69 -0
- package/src/js/modules/captchas/recaptcha-v2-checkbox.ts +72 -0
- package/src/js/modules/captchas/recaptcha-v2-invisible.ts +108 -0
- package/src/js/modules/captchas/recaptcha-v3.ts +62 -0
- package/src/js/modules/captchas/snaptcha.ts +10 -0
- package/src/js/modules/captchas/turnstile.ts +131 -0
- package/src/js/modules/captchas/utils.ts +85 -0
- package/src/js/modules/fields/calculations.ts +273 -0
- package/src/js/modules/fields/checkbox-radio.ts +295 -0
- package/src/js/modules/fields/conditions/config.ts +79 -0
- package/src/js/modules/fields/conditions/effects.ts +166 -0
- package/src/js/modules/fields/conditions/evaluator.ts +44 -0
- package/src/js/modules/fields/conditions/references.ts +165 -0
- package/src/js/modules/fields/conditions/transforms.ts +206 -0
- package/src/js/modules/fields/conditions/types.ts +33 -0
- package/src/js/modules/fields/conditions/values.ts +115 -0
- package/src/js/modules/fields/conditions.ts +229 -0
- package/src/js/modules/fields/date-picker.ts +272 -0
- package/src/js/modules/fields/file-upload.ts +628 -0
- package/src/js/modules/fields/hidden.ts +58 -0
- package/src/js/modules/fields/index.ts +19 -0
- package/src/js/modules/fields/phone-country.ts +226 -0
- package/src/js/modules/fields/repeater.ts +231 -0
- package/src/js/modules/fields/rich-text.ts +217 -0
- package/src/js/modules/fields/shared.ts +238 -0
- package/src/js/modules/fields/signature.ts +202 -0
- package/src/js/modules/fields/summary.ts +272 -0
- package/src/js/modules/fields/table.ts +197 -0
- package/src/js/modules/fields/text-limit.ts +280 -0
- package/src/js/modules/loader.ts +331 -0
- package/src/js/modules/payments/api.ts +20 -0
- package/src/js/modules/payments/bpoint.ts +48 -0
- package/src/js/modules/payments/constants.ts +17 -0
- package/src/js/modules/payments/eway.ts +132 -0
- package/src/js/modules/payments/factories.ts +332 -0
- package/src/js/modules/payments/go-cardless.ts +37 -0
- package/src/js/modules/payments/host.ts +459 -0
- package/src/js/modules/payments/index.ts +17 -0
- package/src/js/modules/payments/mollie.ts +38 -0
- package/src/js/modules/payments/moneris.ts +216 -0
- package/src/js/modules/payments/opayo.ts +272 -0
- package/src/js/modules/payments/paddle.ts +111 -0
- package/src/js/modules/payments/payment.ts +183 -0
- package/src/js/modules/payments/paypal.ts +214 -0
- package/src/js/modules/payments/payway.ts +114 -0
- package/src/js/modules/payments/square.ts +106 -0
- package/src/js/modules/payments/stripe.ts +426 -0
- package/src/js/modules/payments/stub-payment-module.ts +87 -0
- package/src/js/modules/payments/utils.ts +60 -0
- package/src/js/modules/registry.ts +38 -0
- package/src/js/modules/styles.ts +29 -0
- package/src/js/submit/pipeline.ts +514 -0
- package/src/js/theme/theme-classes.ts +106 -0
- package/src/js/transport/forms-api.ts +345 -0
- package/src/js/utils/async.ts +81 -0
- package/src/js/utils/debug.ts +59 -0
- package/src/js/utils/event-names.ts +60 -0
- package/src/js/utils/field-references.keys.ts +47 -0
- package/src/js/utils/field-references.parser.ts +121 -0
- package/src/js/utils/field-references.registry.ts +50 -0
- package/src/js/utils/field-references.resolver.ts +115 -0
- package/src/js/utils/field-references.ts +11 -0
- package/src/js/utils/field-references.types.ts +31 -0
- package/src/js/utils/fields.ts +58 -0
- package/src/js/utils/http.ts +51 -0
- package/src/js/utils/i18n.ts +98 -0
- package/src/js/utils/scripts.ts +84 -0
- package/src/js/utils/unload-warning.ts +190 -0
- package/src/js/validation/rules/email.ts +18 -0
- package/src/js/validation/rules/match.ts +26 -0
- package/src/js/validation/rules/minmax.ts +47 -0
- package/src/js/validation/rules/number.ts +55 -0
- package/src/js/validation/rules/pattern.ts +29 -0
- package/src/js/validation/rules/required.ts +30 -0
- package/src/js/validation/rules/shared.ts +47 -0
- package/src/js/validation/rules/url.ts +23 -0
- package/src/js/validation/rules.ts +16 -0
- package/src/js/validation/types.ts +50 -0
- package/src/js/validation/validator.ts +643 -0
- package/src/vendor.d.ts +100 -0
- package/src/vite-env.d.ts +22 -0
- package/vite-dev.mjs +22 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defineCaptchaModule,
|
|
3
|
+
} from '#modules/captchas/api';
|
|
4
|
+
import {
|
|
5
|
+
CAPTCHA_PROVIDER_LOAD_TIMEOUT_MS,
|
|
6
|
+
} from '#modules/captchas/constants';
|
|
7
|
+
import { ensureGlobal, loadExternalScript } from '#utils/scripts';
|
|
8
|
+
import { getScriptAttributes } from '#modules/captchas/utils';
|
|
9
|
+
|
|
10
|
+
// Minimal subset of the hCaptcha browser API that this provider needs.
|
|
11
|
+
// Keeping this local makes it obvious which parts of the SDK contract this
|
|
12
|
+
// module relies on, without teaching shared captcha services about hCaptcha.
|
|
13
|
+
type HcaptchaGlobal = {
|
|
14
|
+
render: (container: HTMLElement, options: Record<string, unknown>) => string | number;
|
|
15
|
+
execute: (widgetId: string | number) => void;
|
|
16
|
+
reset: (widgetId: string | number) => void;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// These are hCaptcha-specific settings only. Anything generic such as token
|
|
20
|
+
// field names or error messaging now comes from shared captcha services config.
|
|
21
|
+
type HcaptchaProviderOptions = {
|
|
22
|
+
siteKey?: string | null;
|
|
23
|
+
theme?: string;
|
|
24
|
+
size?: string;
|
|
25
|
+
language?: string;
|
|
26
|
+
loadingMethod?: string;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
async function loadHcaptchaGlobal(options: HcaptchaProviderOptions): Promise<HcaptchaGlobal> {
|
|
30
|
+
// hCaptcha exposes a single global (`window.hcaptcha`) after its script
|
|
31
|
+
// has loaded and fired the configured onload callback. This helper stays
|
|
32
|
+
// local to the provider because the exact script URL, callback wiring and
|
|
33
|
+
// readiness contract are all hCaptcha-specific.
|
|
34
|
+
const language = typeof options.language === 'string' && options.language.trim() !== '' ? options.language.trim() : 'en';
|
|
35
|
+
const { async, defer } = getScriptAttributes(options.loadingMethod);
|
|
36
|
+
const callbackName = 'FORMIE_HCAPTCHA_ONLOAD';
|
|
37
|
+
const globalWindow = window as unknown as Record<string, unknown>;
|
|
38
|
+
const existing = globalWindow.hcaptcha;
|
|
39
|
+
|
|
40
|
+
// Re-use the already-loaded SDK when multiple forms/providers exist on
|
|
41
|
+
// the page. We want one shared browser global, not duplicate script loads.
|
|
42
|
+
if (existing) {
|
|
43
|
+
return existing as HcaptchaGlobal;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// The script calls this named function when its internals are ready. We
|
|
47
|
+
// bridge that callback to a promise so the rest of the module can stay
|
|
48
|
+
// async/await based and deterministic.
|
|
49
|
+
const callbackPromise = new Promise<void>((resolve) => {
|
|
50
|
+
globalWindow[callbackName] = () => {
|
|
51
|
+
delete globalWindow[callbackName];
|
|
52
|
+
resolve();
|
|
53
|
+
};
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
await loadExternalScript({
|
|
57
|
+
id: 'FORMIE_HCAPTCHA_SCRIPT',
|
|
58
|
+
src: `https://js.hcaptcha.com/1/api.js?recaptchacompat=off&render=explicit&onload=${encodeURIComponent(callbackName)}&hl=${encodeURIComponent(language)}`,
|
|
59
|
+
async,
|
|
60
|
+
defer,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
await callbackPromise;
|
|
64
|
+
|
|
65
|
+
return ensureGlobal<HcaptchaGlobal>('hcaptcha', CAPTCHA_PROVIDER_LOAD_TIMEOUT_MS);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export const hcaptchaModule = defineCaptchaModule<HcaptchaProviderOptions, HcaptchaGlobal, number | string>({
|
|
69
|
+
id: 'hcaptcha',
|
|
70
|
+
defaultPlaceholderSelector: '[data-hcaptcha-placeholder]',
|
|
71
|
+
defaultTokenFieldNames: ['h-captcha-response'],
|
|
72
|
+
load: ({ options }) => {
|
|
73
|
+
// `load()` is deliberately separate from `mount()`: the factory can
|
|
74
|
+
// cache and share this provider API promise across placeholder mounts,
|
|
75
|
+
// resets and page transitions without reloading the SDK each time.
|
|
76
|
+
return loadHcaptchaGlobal(options.provider);
|
|
77
|
+
},
|
|
78
|
+
mount: ({ api, container, provider, services }) => {
|
|
79
|
+
// Mount only renders/configures the widget. It does not decide whether
|
|
80
|
+
// a submit should be blocked; that responsibility lives in `screen()`.
|
|
81
|
+
return api.render(container, {
|
|
82
|
+
sitekey: provider.siteKey || '',
|
|
83
|
+
theme: provider.theme || 'light',
|
|
84
|
+
size: provider.size || 'normal',
|
|
85
|
+
callback: (token?: string) => {
|
|
86
|
+
// hCaptcha gives us the token in the verify callback. We push
|
|
87
|
+
// that into the shared transport inputs so the backend sees the
|
|
88
|
+
// same payload shape regardless of provider implementation.
|
|
89
|
+
if (typeof token === 'string' && token.trim() !== '') {
|
|
90
|
+
services.tokens.write(token.trim());
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// If the user previously tried to submit without a token, the
|
|
94
|
+
// shared services may have rendered an inline error. Clear it as
|
|
95
|
+
// soon as the challenge completes successfully.
|
|
96
|
+
services.errors.clear();
|
|
97
|
+
},
|
|
98
|
+
'expired-callback': () => {
|
|
99
|
+
// Expiry means the old token is no longer valid, so keep the
|
|
100
|
+
// DOM transport layer honest by clearing it immediately.
|
|
101
|
+
services.tokens.clear();
|
|
102
|
+
services.errors.clear();
|
|
103
|
+
},
|
|
104
|
+
'chalexpired-callback': () => {
|
|
105
|
+
// hCaptcha has a second expiry-style callback for challenge
|
|
106
|
+
// expiration; treat it the same as normal token expiration.
|
|
107
|
+
services.tokens.clear();
|
|
108
|
+
services.errors.clear();
|
|
109
|
+
},
|
|
110
|
+
'error-callback': () => {
|
|
111
|
+
// SDK/network errors should not leave a stale token behind.
|
|
112
|
+
services.tokens.clear();
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
},
|
|
116
|
+
screen: ({ api, widget, placeholder, services, stageCtx }) => {
|
|
117
|
+
// `screen()` runs at submit time. By the time we get here the widget is
|
|
118
|
+
// already mounted, so this method only answers "do we have a valid
|
|
119
|
+
// token yet, and if not, can we get one before the screen stage ends?"
|
|
120
|
+
if (services.tokens.has()) {
|
|
121
|
+
// Users can complete hCaptcha before clicking submit. In that case
|
|
122
|
+
// there is nothing to do; we already have the token the backend
|
|
123
|
+
// expects, so let the submit pipeline continue immediately.
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// No token yet, so tell hCaptcha to start/continue the challenge flow.
|
|
128
|
+
// For invisible or programmatic widget modes this is the moment the
|
|
129
|
+
// provider gets a chance to prompt the user.
|
|
130
|
+
api.execute(widget);
|
|
131
|
+
|
|
132
|
+
// After execute(), the token will arrive asynchronously via the widget
|
|
133
|
+
// callback configured in `mount()`. We therefore wait on the shared
|
|
134
|
+
// token transport layer, not on a provider-specific promise chain.
|
|
135
|
+
return services.tokens.wait().then((hasToken) => {
|
|
136
|
+
if (!hasToken) {
|
|
137
|
+
// If the callback never produced a token in time, surface a
|
|
138
|
+
// normal themed error and abort the submit pipeline's `screen`
|
|
139
|
+
// stage so the form is not posted without verification.
|
|
140
|
+
const message = services.errors.getDefaultMessage();
|
|
141
|
+
services.errors.show(message, placeholder);
|
|
142
|
+
stageCtx.abort(message);
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
},
|
|
146
|
+
unmount: ({ api, widget, services }) => {
|
|
147
|
+
// Reset tears down provider state and clears any token the widget had
|
|
148
|
+
// produced. This keeps later page visits/submits from accidentally
|
|
149
|
+
// reusing an old solved challenge.
|
|
150
|
+
api.reset(widget);
|
|
151
|
+
services.tokens.clear();
|
|
152
|
+
},
|
|
153
|
+
});
|
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
import type { ModuleSetupContext } from '#contracts/modules';
|
|
2
|
+
import type { FormRefreshTokensPayload } from '#contracts/schema';
|
|
3
|
+
import { addThemeClasses } from '#theme/theme-classes';
|
|
4
|
+
import { debounce } from '#utils/async';
|
|
5
|
+
import { t } from '#utils/i18n';
|
|
6
|
+
import { DEFAULT_WAIT_FOR_VALUE_MS } from '#modules/captchas/constants';
|
|
7
|
+
import {
|
|
8
|
+
clearCaptchaValues,
|
|
9
|
+
ensureCaptchaValueInput,
|
|
10
|
+
getInputValue,
|
|
11
|
+
hasCaptchaValue,
|
|
12
|
+
waitForCaptchaValue,
|
|
13
|
+
} from '#modules/captchas/utils';
|
|
14
|
+
|
|
15
|
+
type Cleanup = () => void;
|
|
16
|
+
|
|
17
|
+
type ObserveVisiblePlaceholdersResult = {
|
|
18
|
+
cleanup: Cleanup;
|
|
19
|
+
reconcile: () => void;
|
|
20
|
+
getVisible: () => HTMLElement[];
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export type CaptchaRefreshEntry = {
|
|
24
|
+
formId?: string;
|
|
25
|
+
sessionKey?: string | null;
|
|
26
|
+
value?: string | null;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export type CaptchaModuleOptions<TProvider extends Record<string, unknown> = Record<string, unknown>> = {
|
|
30
|
+
handle?: string;
|
|
31
|
+
placeholderSelector?: string;
|
|
32
|
+
errorMessage?: string;
|
|
33
|
+
sessionKey?: string | null;
|
|
34
|
+
value?: string | null;
|
|
35
|
+
} & TProvider;
|
|
36
|
+
|
|
37
|
+
export type NormalizedCaptchaModuleOptions<TProvider extends Record<string, unknown>> = {
|
|
38
|
+
handle: string;
|
|
39
|
+
ui: {
|
|
40
|
+
placeholderSelector: string;
|
|
41
|
+
errorMessage: string;
|
|
42
|
+
};
|
|
43
|
+
transport: {
|
|
44
|
+
tokenFieldNames: string[];
|
|
45
|
+
waitForValueMs: number;
|
|
46
|
+
sessionKey: string | null;
|
|
47
|
+
value: string | null;
|
|
48
|
+
};
|
|
49
|
+
provider: TProvider;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
type CaptchaModuleDefaults = {
|
|
53
|
+
defaultPlaceholderSelector: string;
|
|
54
|
+
defaultTokenFieldNames?: string[];
|
|
55
|
+
defaultWaitForValueMs?: number;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export type CaptchaHostServices = {
|
|
59
|
+
form: HTMLFormElement | null;
|
|
60
|
+
root: Element;
|
|
61
|
+
placeholder: {
|
|
62
|
+
query: () => HTMLElement[];
|
|
63
|
+
getPrimary: () => HTMLElement | null;
|
|
64
|
+
observe: (
|
|
65
|
+
onShow: (placeholder: HTMLElement) => void,
|
|
66
|
+
onHide: (placeholder: HTMLElement) => void,
|
|
67
|
+
) => ObserveVisiblePlaceholdersResult;
|
|
68
|
+
createContainer: (placeholder: HTMLElement) => HTMLElement;
|
|
69
|
+
clear: (placeholder: HTMLElement | null) => void;
|
|
70
|
+
};
|
|
71
|
+
errors: {
|
|
72
|
+
getDefaultMessage: () => string;
|
|
73
|
+
show: (message?: string, placeholder?: HTMLElement | null) => void;
|
|
74
|
+
clear: (placeholder?: HTMLElement | null) => void;
|
|
75
|
+
};
|
|
76
|
+
tokens: {
|
|
77
|
+
names: string[];
|
|
78
|
+
has: (names?: string[], root?: ParentNode) => boolean;
|
|
79
|
+
read: (name?: string, root?: ParentNode) => string;
|
|
80
|
+
write: (
|
|
81
|
+
value: string,
|
|
82
|
+
{
|
|
83
|
+
names,
|
|
84
|
+
root,
|
|
85
|
+
container,
|
|
86
|
+
}?: {
|
|
87
|
+
names?: string[];
|
|
88
|
+
root?: ParentNode;
|
|
89
|
+
container?: HTMLElement | null;
|
|
90
|
+
},
|
|
91
|
+
) => void;
|
|
92
|
+
clear: (names?: string[], root?: ParentNode) => void;
|
|
93
|
+
wait: (timeoutMs?: number, names?: string[], root?: ParentNode) => Promise<boolean>;
|
|
94
|
+
};
|
|
95
|
+
refresh: {
|
|
96
|
+
providerHandle: string;
|
|
97
|
+
onTokensRefreshed: (callback: (entry: CaptchaRefreshEntry) => void) => Cleanup;
|
|
98
|
+
};
|
|
99
|
+
events: {
|
|
100
|
+
onRoot: (eventName: string, callback: EventListener) => Cleanup;
|
|
101
|
+
onForm: (eventName: string, callback: EventListener) => Cleanup;
|
|
102
|
+
};
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const CAPTCHA_OPTION_KEYS = new Set([
|
|
106
|
+
'handle',
|
|
107
|
+
'placeholderSelector',
|
|
108
|
+
'errorMessage',
|
|
109
|
+
'sessionKey',
|
|
110
|
+
'value',
|
|
111
|
+
]);
|
|
112
|
+
|
|
113
|
+
const CAPTCHA_ERROR_SELECTOR = '[data-formie-captcha-error-container]';
|
|
114
|
+
const CAPTCHA_VISIBILITY_EVENTS = [
|
|
115
|
+
'formie:page:navigate',
|
|
116
|
+
'formie:page:navigate:after',
|
|
117
|
+
'formie:submit:result',
|
|
118
|
+
];
|
|
119
|
+
|
|
120
|
+
function bindDomEvent(target: EventTarget, eventName: string, callback: EventListener): Cleanup {
|
|
121
|
+
target.addEventListener(eventName, callback);
|
|
122
|
+
|
|
123
|
+
return () => {
|
|
124
|
+
target.removeEventListener(eventName, callback);
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function queryCaptchaPlaceholders(root: Element, selector: string): HTMLElement[] {
|
|
129
|
+
if (root instanceof HTMLElement && root.matches(selector)) {
|
|
130
|
+
return [root, ...Array.from(root.querySelectorAll(selector)) as HTMLElement[]];
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return Array.from(root.querySelectorAll(selector)) as HTMLElement[];
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function isElementVisible(target: Element): target is HTMLElement {
|
|
137
|
+
if (!(target instanceof HTMLElement)) {
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (!target.isConnected) {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (target.hidden || target.closest('[hidden]')) {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (target.closest('[data-formie-page-hidden]') || target.closest('[aria-hidden="true"]')) {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const style = window.getComputedStyle(target);
|
|
154
|
+
|
|
155
|
+
return style.display !== 'none' && style.visibility !== 'hidden';
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function getPrimaryPlaceholder(root: Element, selector: string): HTMLElement | null {
|
|
159
|
+
const placeholders = queryCaptchaPlaceholders(root, selector);
|
|
160
|
+
|
|
161
|
+
return placeholders.find((placeholder) => isElementVisible(placeholder)) || placeholders[0] || null;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function createCaptchaContainer(placeholder: HTMLElement): HTMLElement {
|
|
165
|
+
placeholder.innerHTML = '';
|
|
166
|
+
|
|
167
|
+
const container = document.createElement('div');
|
|
168
|
+
placeholder.appendChild(container);
|
|
169
|
+
|
|
170
|
+
return container;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function clearCaptchaError(placeholder: HTMLElement | null): void {
|
|
174
|
+
placeholder?.querySelector(CAPTCHA_ERROR_SELECTOR)?.remove();
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function showCaptchaError(placeholder: HTMLElement | null, message: string, themeSource?: Element | null): void {
|
|
178
|
+
if (!placeholder) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
clearCaptchaError(placeholder);
|
|
183
|
+
|
|
184
|
+
const container = document.createElement('div');
|
|
185
|
+
container.setAttribute('data-formie-captcha-error-container', '');
|
|
186
|
+
container.setAttribute('aria-live', 'polite');
|
|
187
|
+
container.setAttribute('aria-atomic', 'true');
|
|
188
|
+
addThemeClasses(container, themeSource || placeholder, 'fieldErrors');
|
|
189
|
+
|
|
190
|
+
const error = document.createElement('div');
|
|
191
|
+
error.setAttribute('data-formie-captcha-error', '');
|
|
192
|
+
error.setAttribute('role', 'alert');
|
|
193
|
+
addThemeClasses(error, themeSource || placeholder, 'fieldError');
|
|
194
|
+
error.textContent = message;
|
|
195
|
+
|
|
196
|
+
container.appendChild(error);
|
|
197
|
+
placeholder.appendChild(container);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function parseRefreshTokensEvent(event: Event): FormRefreshTokensPayload | null {
|
|
201
|
+
const detail = event instanceof CustomEvent ? event.detail : null;
|
|
202
|
+
|
|
203
|
+
if (!detail || typeof detail !== 'object') {
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return detail as FormRefreshTokensPayload;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function getCaptchaRefreshEntry(
|
|
211
|
+
payload: FormRefreshTokensPayload | null,
|
|
212
|
+
providerHandle: string,
|
|
213
|
+
): CaptchaRefreshEntry | null {
|
|
214
|
+
if (!payload?.captchas || typeof payload.captchas !== 'object') {
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const entry = payload.captchas[providerHandle];
|
|
219
|
+
|
|
220
|
+
if (!entry || typeof entry !== 'object') {
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return entry as CaptchaRefreshEntry;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function observeVisiblePlaceholders(
|
|
228
|
+
root: Element,
|
|
229
|
+
selector: string,
|
|
230
|
+
onShow: (placeholder: HTMLElement) => void,
|
|
231
|
+
onHide: (placeholder: HTMLElement) => void,
|
|
232
|
+
): ObserveVisiblePlaceholdersResult {
|
|
233
|
+
const visible = new Set<HTMLElement>();
|
|
234
|
+
|
|
235
|
+
const reconcileNow = () => {
|
|
236
|
+
const placeholders = queryCaptchaPlaceholders(root, selector);
|
|
237
|
+
const nextVisible = new Set(placeholders.filter((placeholder) => isElementVisible(placeholder)));
|
|
238
|
+
|
|
239
|
+
placeholders.forEach((placeholder) => {
|
|
240
|
+
if (nextVisible.has(placeholder) && !visible.has(placeholder)) {
|
|
241
|
+
visible.add(placeholder);
|
|
242
|
+
onShow(placeholder);
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
Array.from(visible).forEach((placeholder) => {
|
|
247
|
+
if (nextVisible.has(placeholder)) {
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
visible.delete(placeholder);
|
|
252
|
+
onHide(placeholder);
|
|
253
|
+
});
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
const reconcile = debounce(reconcileNow, 20);
|
|
257
|
+
const mutationObserver = new MutationObserver(() => {
|
|
258
|
+
reconcile();
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
mutationObserver.observe(root, {
|
|
262
|
+
childList: true,
|
|
263
|
+
subtree: true,
|
|
264
|
+
attributes: true,
|
|
265
|
+
attributeFilter: ['class', 'style', 'hidden', 'aria-hidden', 'data-formie-page-hidden'],
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
const cleanups = [
|
|
269
|
+
bindDomEvent(window, 'resize', () => {
|
|
270
|
+
reconcile();
|
|
271
|
+
}),
|
|
272
|
+
...CAPTCHA_VISIBILITY_EVENTS.map((eventName) => {
|
|
273
|
+
return bindDomEvent(root, eventName, () => {
|
|
274
|
+
reconcile();
|
|
275
|
+
});
|
|
276
|
+
}),
|
|
277
|
+
];
|
|
278
|
+
|
|
279
|
+
reconcileNow();
|
|
280
|
+
|
|
281
|
+
return {
|
|
282
|
+
cleanup: () => {
|
|
283
|
+
mutationObserver.disconnect();
|
|
284
|
+
cleanups.forEach((cleanup) => {
|
|
285
|
+
cleanup();
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
Array.from(visible).forEach((placeholder) => {
|
|
289
|
+
onHide(placeholder);
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
visible.clear();
|
|
293
|
+
},
|
|
294
|
+
reconcile,
|
|
295
|
+
getVisible: () => {
|
|
296
|
+
return queryCaptchaPlaceholders(root, selector).filter((placeholder) => isElementVisible(placeholder));
|
|
297
|
+
},
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function getCaptchaProviderHandle(id: string, options: Record<string, unknown>): string {
|
|
302
|
+
const handle = typeof options.handle === 'string' && options.handle.trim() !== ''
|
|
303
|
+
? options.handle.trim()
|
|
304
|
+
: '';
|
|
305
|
+
|
|
306
|
+
return handle || id;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
export function normalizeCaptchaModuleOptions<TProvider extends Record<string, unknown>>(
|
|
310
|
+
id: string,
|
|
311
|
+
rawOptions: Record<string, unknown> | undefined,
|
|
312
|
+
{
|
|
313
|
+
defaultPlaceholderSelector,
|
|
314
|
+
defaultTokenFieldNames = [],
|
|
315
|
+
defaultWaitForValueMs = DEFAULT_WAIT_FOR_VALUE_MS,
|
|
316
|
+
}: CaptchaModuleDefaults,
|
|
317
|
+
): NormalizedCaptchaModuleOptions<TProvider> {
|
|
318
|
+
const options = rawOptions || {};
|
|
319
|
+
const provider = Object.entries(options).reduce((carry, [key, value]) => {
|
|
320
|
+
if (CAPTCHA_OPTION_KEYS.has(key)) {
|
|
321
|
+
return carry;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
carry[key] = value;
|
|
325
|
+
|
|
326
|
+
return carry;
|
|
327
|
+
}, {} as Record<string, unknown>) as TProvider;
|
|
328
|
+
const tokenFieldNames = defaultTokenFieldNames.map(String).filter(Boolean);
|
|
329
|
+
const waitForValueMs = Number(defaultWaitForValueMs);
|
|
330
|
+
const placeholderSelector = typeof options.placeholderSelector === 'string' && options.placeholderSelector.trim() !== ''
|
|
331
|
+
? options.placeholderSelector.trim()
|
|
332
|
+
: defaultPlaceholderSelector;
|
|
333
|
+
const errorMessage = typeof options.errorMessage === 'string' && options.errorMessage.trim() !== ''
|
|
334
|
+
? options.errorMessage.trim()
|
|
335
|
+
: t('Captcha challenge must be completed.');
|
|
336
|
+
const sessionKey = typeof options.sessionKey === 'string' && options.sessionKey.trim() !== ''
|
|
337
|
+
? options.sessionKey.trim()
|
|
338
|
+
: null;
|
|
339
|
+
const value = typeof options.value === 'string'
|
|
340
|
+
? options.value
|
|
341
|
+
: null;
|
|
342
|
+
|
|
343
|
+
return {
|
|
344
|
+
handle: getCaptchaProviderHandle(id, options),
|
|
345
|
+
ui: {
|
|
346
|
+
placeholderSelector,
|
|
347
|
+
errorMessage,
|
|
348
|
+
},
|
|
349
|
+
transport: {
|
|
350
|
+
tokenFieldNames,
|
|
351
|
+
waitForValueMs: Number.isFinite(waitForValueMs) ? waitForValueMs : defaultWaitForValueMs,
|
|
352
|
+
sessionKey,
|
|
353
|
+
value,
|
|
354
|
+
},
|
|
355
|
+
provider,
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
export function createCaptchaHostServices<TProvider extends Record<string, unknown>>(
|
|
360
|
+
ctx: ModuleSetupContext,
|
|
361
|
+
options: NormalizedCaptchaModuleOptions<TProvider>,
|
|
362
|
+
): CaptchaHostServices {
|
|
363
|
+
const tokenRoot = ctx.form || ctx.root;
|
|
364
|
+
const placeholderSelector = options.ui.placeholderSelector;
|
|
365
|
+
const providerHandle = options.handle;
|
|
366
|
+
|
|
367
|
+
return {
|
|
368
|
+
form: ctx.form,
|
|
369
|
+
root: ctx.root,
|
|
370
|
+
placeholder: {
|
|
371
|
+
query: () => queryCaptchaPlaceholders(ctx.root, placeholderSelector),
|
|
372
|
+
getPrimary: () => getPrimaryPlaceholder(ctx.root, placeholderSelector),
|
|
373
|
+
observe: (onShow, onHide) => observeVisiblePlaceholders(ctx.root, placeholderSelector, onShow, onHide),
|
|
374
|
+
createContainer: (placeholder) => createCaptchaContainer(placeholder),
|
|
375
|
+
clear: (placeholder) => {
|
|
376
|
+
if (!placeholder) {
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
clearCaptchaError(placeholder);
|
|
381
|
+
placeholder.innerHTML = '';
|
|
382
|
+
},
|
|
383
|
+
},
|
|
384
|
+
errors: {
|
|
385
|
+
getDefaultMessage: () => options.ui.errorMessage,
|
|
386
|
+
show: (message, placeholder) => {
|
|
387
|
+
showCaptchaError(placeholder || getPrimaryPlaceholder(ctx.root, placeholderSelector), message || options.ui.errorMessage, ctx.form || ctx.root);
|
|
388
|
+
},
|
|
389
|
+
clear: (placeholder) => {
|
|
390
|
+
clearCaptchaError(placeholder || getPrimaryPlaceholder(ctx.root, placeholderSelector));
|
|
391
|
+
},
|
|
392
|
+
},
|
|
393
|
+
tokens: {
|
|
394
|
+
names: options.transport.tokenFieldNames,
|
|
395
|
+
has: (names = options.transport.tokenFieldNames, root = tokenRoot) => hasCaptchaValue(root, names),
|
|
396
|
+
read: (name = options.transport.tokenFieldNames[0], root = tokenRoot) => (name ? getInputValue(root, name) : ''),
|
|
397
|
+
write: (value, {
|
|
398
|
+
names = options.transport.tokenFieldNames,
|
|
399
|
+
root = tokenRoot,
|
|
400
|
+
container = ctx.form,
|
|
401
|
+
} = {}) => {
|
|
402
|
+
names.forEach((name) => {
|
|
403
|
+
ensureCaptchaValueInput(root, name, {
|
|
404
|
+
value,
|
|
405
|
+
container,
|
|
406
|
+
});
|
|
407
|
+
});
|
|
408
|
+
},
|
|
409
|
+
clear: (names = options.transport.tokenFieldNames, root = tokenRoot) => {
|
|
410
|
+
clearCaptchaValues(root, names);
|
|
411
|
+
},
|
|
412
|
+
wait: (timeoutMs = options.transport.waitForValueMs, names = options.transport.tokenFieldNames, root = tokenRoot) => {
|
|
413
|
+
return waitForCaptchaValue(root, names, timeoutMs);
|
|
414
|
+
},
|
|
415
|
+
},
|
|
416
|
+
refresh: {
|
|
417
|
+
providerHandle,
|
|
418
|
+
onTokensRefreshed: (callback) => {
|
|
419
|
+
const handlers = ['formie:refresh-tokens:after', 'formie:refresh-tokens:refreshed'].map((eventName) => {
|
|
420
|
+
return bindDomEvent(ctx.root, eventName, (event) => {
|
|
421
|
+
const payload = parseRefreshTokensEvent(event);
|
|
422
|
+
const entry = getCaptchaRefreshEntry(payload, providerHandle);
|
|
423
|
+
|
|
424
|
+
if (entry) {
|
|
425
|
+
callback(entry);
|
|
426
|
+
}
|
|
427
|
+
});
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
return () => {
|
|
431
|
+
handlers.forEach((cleanup) => {
|
|
432
|
+
cleanup();
|
|
433
|
+
});
|
|
434
|
+
};
|
|
435
|
+
},
|
|
436
|
+
},
|
|
437
|
+
events: {
|
|
438
|
+
onRoot: (eventName, callback) => bindDomEvent(ctx.root, eventName, callback),
|
|
439
|
+
onForm: (eventName, callback) => {
|
|
440
|
+
if (!ctx.form) {
|
|
441
|
+
return () => {};
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
return bindDomEvent(ctx.form, eventName, callback);
|
|
445
|
+
},
|
|
446
|
+
},
|
|
447
|
+
};
|
|
448
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { FormieModuleDefinition } from '#contracts/modules';
|
|
2
|
+
|
|
3
|
+
export const builtinCaptchaModuleLoaders: Record<string, () => Promise<FormieModuleDefinition>> = {
|
|
4
|
+
// Module ids map directly to importer functions so the loader can fetch only
|
|
5
|
+
// the captcha chunks required by the current form manifest.
|
|
6
|
+
'captcha-eu': () => import('#modules/captchas/captcha-eu').then((module) => module.captchaEuModule),
|
|
7
|
+
'friendly-captcha-v1': () => import('#modules/captchas/friendly-captcha-v1').then((module) => module.friendlyCaptchaV1Module),
|
|
8
|
+
'friendly-captcha-v2': () => import('#modules/captchas/friendly-captcha-v2').then((module) => module.friendlyCaptchaV2Module),
|
|
9
|
+
'hcaptcha': () => import('#modules/captchas/hcaptcha').then((module) => module.hcaptchaModule),
|
|
10
|
+
'recaptcha-enterprise': () => import('#modules/captchas/recaptcha-enterprise').then((module) => module.recaptchaEnterpriseModule),
|
|
11
|
+
'recaptcha-v2-checkbox': () => import('#modules/captchas/recaptcha-v2-checkbox').then((module) => module.recaptchaV2CheckboxModule),
|
|
12
|
+
'recaptcha-v2-invisible': () => import('#modules/captchas/recaptcha-v2-invisible').then((module) => module.recaptchaV2InvisibleModule),
|
|
13
|
+
'recaptcha-v3': () => import('#modules/captchas/recaptcha-v3').then((module) => module.recaptchaV3Module),
|
|
14
|
+
'snaptcha': () => import('#modules/captchas/snaptcha').then((module) => module.snaptchaModule),
|
|
15
|
+
'turnstile': () => import('#modules/captchas/turnstile').then((module) => module.turnstileModule),
|
|
16
|
+
};
|