@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,138 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defineCaptchaModule,
|
|
3
|
+
} from '#modules/captchas/api';
|
|
4
|
+
import { CAPTCHA_EXECUTE_WAIT_FOR_VALUE_MS } from '#modules/captchas/constants';
|
|
5
|
+
import {
|
|
6
|
+
loadRecaptchaGlobal,
|
|
7
|
+
type RecaptchaGlobal,
|
|
8
|
+
type RecaptchaProviderOptions,
|
|
9
|
+
} from '#modules/captchas/recaptcha-shared';
|
|
10
|
+
|
|
11
|
+
type RecaptchaEnterpriseProviderOptions = RecaptchaProviderOptions & {
|
|
12
|
+
enterpriseType?: string | null;
|
|
13
|
+
action?: string;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// Enterprise is intentionally still one module because Google ships these as
|
|
17
|
+
// one SDK with three web-facing modes:
|
|
18
|
+
// - checkbox: rendered widget, user solves before submit
|
|
19
|
+
// - score: no visible widget, execute() returns a score token
|
|
20
|
+
// - policy: execute() triggers the challenge/assessment flow for policy keys
|
|
21
|
+
//
|
|
22
|
+
// Shared captcha services should not know about any of those distinctions, so
|
|
23
|
+
// this module owns the branching itself.
|
|
24
|
+
export const recaptchaEnterpriseModule = defineCaptchaModule<RecaptchaEnterpriseProviderOptions, RecaptchaGlobal, number | string>({
|
|
25
|
+
id: 'recaptcha-enterprise',
|
|
26
|
+
defaultPlaceholderSelector: '[data-recaptcha-placeholder]',
|
|
27
|
+
defaultTokenFieldNames: ['g-recaptcha-response'],
|
|
28
|
+
load: ({ options }) => {
|
|
29
|
+
// Score/policy keys use the site-key `render=` script mode, while
|
|
30
|
+
// checkbox still behaves like an explicit widget render.
|
|
31
|
+
return loadRecaptchaGlobal(
|
|
32
|
+
options.provider,
|
|
33
|
+
true,
|
|
34
|
+
options.provider.enterpriseType === 'score' || options.provider.enterpriseType === 'policy' ? (options.provider.siteKey || undefined) : undefined,
|
|
35
|
+
);
|
|
36
|
+
},
|
|
37
|
+
mount: ({ api, container, provider, services }) => {
|
|
38
|
+
const enterpriseApi = api.enterprise || api;
|
|
39
|
+
|
|
40
|
+
return new Promise((resolve) => {
|
|
41
|
+
enterpriseApi.ready(() => {
|
|
42
|
+
if (provider.enterpriseType !== 'checkbox') {
|
|
43
|
+
// Score and policy modes do not produce a widget id. As
|
|
44
|
+
// with reCAPTCHA v3, we keep the site key as the managed
|
|
45
|
+
// instance value so the provider still fits the generic
|
|
46
|
+
// managed-captcha lifecycle.
|
|
47
|
+
resolve(provider.siteKey || `recaptcha-enterprise-${provider.enterpriseType || 'score'}`);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Checkbox mode is a true rendered widget and therefore follows
|
|
52
|
+
// the more traditional render/callback/reset lifecycle.
|
|
53
|
+
resolve(enterpriseApi.render(container, {
|
|
54
|
+
sitekey: provider.siteKey || '',
|
|
55
|
+
theme: provider.theme || 'light',
|
|
56
|
+
badge: provider.badge || 'bottomright',
|
|
57
|
+
size: provider.size || 'normal',
|
|
58
|
+
action: provider.action || 'submit',
|
|
59
|
+
callback: (token?: string) => {
|
|
60
|
+
if (typeof token === 'string' && token.trim() !== '') {
|
|
61
|
+
services.tokens.write(token.trim());
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
services.errors.clear();
|
|
65
|
+
},
|
|
66
|
+
'expired-callback': () => {
|
|
67
|
+
services.tokens.clear();
|
|
68
|
+
services.errors.clear();
|
|
69
|
+
},
|
|
70
|
+
'error-callback': () => {
|
|
71
|
+
services.tokens.clear();
|
|
72
|
+
},
|
|
73
|
+
}));
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
},
|
|
77
|
+
screen: async({ api, widget, provider, placeholder, services, stageCtx }) => {
|
|
78
|
+
const enterpriseApi = api.enterprise || api;
|
|
79
|
+
|
|
80
|
+
if (provider.enterpriseType === 'checkbox') {
|
|
81
|
+
// Checkbox mode behaves like reCAPTCHA v2 checkbox: by submit time
|
|
82
|
+
// we only verify that the user has already solved the widget.
|
|
83
|
+
if (services.tokens.has()) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const message = services.errors.getDefaultMessage();
|
|
88
|
+
services.errors.show(message, placeholder);
|
|
89
|
+
stageCtx.abort(message);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (services.tokens.has()) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (provider.enterpriseType === 'score' || provider.enterpriseType === 'policy') {
|
|
98
|
+
// Score and policy-based keys execute by site key and can resolve
|
|
99
|
+
// directly to a token. We write that token into the shared transport
|
|
100
|
+
// layer so the backend can validate it in the usual way.
|
|
101
|
+
const token = await enterpriseApi.execute(provider.siteKey || '', { action: provider.action || 'submit' });
|
|
102
|
+
|
|
103
|
+
if (typeof token === 'string' && token.trim() !== '') {
|
|
104
|
+
services.tokens.write(token.trim());
|
|
105
|
+
}
|
|
106
|
+
} else {
|
|
107
|
+
// Fallback branch for any future Enterprise widget-like mode.
|
|
108
|
+
enterpriseApi.execute(widget);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const hasToken = await services.tokens.wait(CAPTCHA_EXECUTE_WAIT_FOR_VALUE_MS);
|
|
112
|
+
|
|
113
|
+
if (!hasToken) {
|
|
114
|
+
const message = services.errors.getDefaultMessage();
|
|
115
|
+
services.errors.show(message, placeholder);
|
|
116
|
+
stageCtx.abort(message);
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
reset: ({ api, widget, provider, services }) => {
|
|
120
|
+
const enterpriseApi = api.enterprise || api;
|
|
121
|
+
|
|
122
|
+
if (provider.enterpriseType === 'checkbox') {
|
|
123
|
+
// Only checkbox mode has a long-lived rendered widget to reset.
|
|
124
|
+
enterpriseApi.reset(widget);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
services.tokens.clear();
|
|
128
|
+
},
|
|
129
|
+
unmount: ({ api, widget, provider, services }) => {
|
|
130
|
+
const enterpriseApi = api.enterprise || api;
|
|
131
|
+
|
|
132
|
+
if (provider.enterpriseType === 'checkbox') {
|
|
133
|
+
enterpriseApi.reset(widget);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
services.tokens.clear();
|
|
137
|
+
},
|
|
138
|
+
});
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { loadScriptAndEnsureGlobal } from '#utils/scripts';
|
|
2
|
+
import { CAPTCHA_PROVIDER_LOAD_TIMEOUT_MS } from '#modules/captchas/constants';
|
|
3
|
+
import { getScriptAttributes } from '#modules/captchas/utils';
|
|
4
|
+
|
|
5
|
+
// reCAPTCHA is the one place where a provider-local "shared" file still earns
|
|
6
|
+
// its keep: v2 checkbox, v2 invisible, v3, and Enterprise all rely on the same
|
|
7
|
+
// Google global and script-loading rules, but use different module lifecycles.
|
|
8
|
+
export type RecaptchaGlobal = {
|
|
9
|
+
ready: (callback: () => void) => void;
|
|
10
|
+
render: (container: HTMLElement, options: Record<string, unknown>) => number | string;
|
|
11
|
+
execute: (widgetIdOrSiteKey?: number | string, options?: Record<string, unknown>) => Promise<string> | void;
|
|
12
|
+
getResponse?: (widgetId?: number | string) => string;
|
|
13
|
+
reset: (widgetId?: number | string) => void;
|
|
14
|
+
enterprise?: {
|
|
15
|
+
ready: (callback: () => void) => void;
|
|
16
|
+
render: (container: HTMLElement, options: Record<string, unknown>) => number | string;
|
|
17
|
+
execute: (widgetIdOrSiteKey?: number | string, options?: Record<string, unknown>) => Promise<string> | void;
|
|
18
|
+
getResponse?: (widgetId?: number | string) => string;
|
|
19
|
+
reset: (widgetId?: number | string) => void;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export type RecaptchaProviderOptions = {
|
|
24
|
+
siteKey?: string | null;
|
|
25
|
+
badge?: string;
|
|
26
|
+
theme?: string;
|
|
27
|
+
size?: string;
|
|
28
|
+
language?: string;
|
|
29
|
+
loadingMethod?: string;
|
|
30
|
+
action?: string;
|
|
31
|
+
enterpriseType?: string | null;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export async function loadRecaptchaGlobal(
|
|
35
|
+
options: RecaptchaProviderOptions,
|
|
36
|
+
enterprise = false,
|
|
37
|
+
renderValue?: string,
|
|
38
|
+
): Promise<RecaptchaGlobal> {
|
|
39
|
+
// Google reCAPTCHA has two loading styles:
|
|
40
|
+
// - `render=explicit` for widget-based modes where the module later calls
|
|
41
|
+
// `grecaptcha.render(container, ...)`
|
|
42
|
+
// - `render=<siteKey>` for execute-by-site-key modes such as v3 and some
|
|
43
|
+
// Enterprise flows
|
|
44
|
+
//
|
|
45
|
+
// That distinction matters across multiple reCAPTCHA modules, which is why
|
|
46
|
+
// this helper is worth sharing even though singular providers were inlined.
|
|
47
|
+
const language = typeof options.language === 'string' && options.language.trim() !== '' ? options.language.trim() : 'en';
|
|
48
|
+
const { async, defer } = getScriptAttributes(options.loadingMethod);
|
|
49
|
+
const host = enterprise ? 'https://www.google.com/recaptcha/enterprise.js' : 'https://www.recaptcha.net/recaptcha/api.js';
|
|
50
|
+
const render = typeof renderValue === 'string' && renderValue.trim() !== '' ? renderValue.trim() : 'explicit';
|
|
51
|
+
const src = new URL(host);
|
|
52
|
+
|
|
53
|
+
src.searchParams.set('render', render);
|
|
54
|
+
src.searchParams.set('hl', language);
|
|
55
|
+
|
|
56
|
+
// Badge placement is configured on the script URL for the execute-by-site-
|
|
57
|
+
// key flows because there is no later widget render call to carry it.
|
|
58
|
+
if (render !== 'explicit' && typeof options.badge === 'string' && options.badge.trim() !== '') {
|
|
59
|
+
src.searchParams.set('badge', options.badge.trim());
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return loadScriptAndEnsureGlobal<RecaptchaGlobal>('grecaptcha', {
|
|
63
|
+
id: enterprise ? 'FORMIE_RECAPTCHA_ENTERPRISE_SCRIPT' : 'FORMIE_RECAPTCHA_SCRIPT',
|
|
64
|
+
src: src.toString(),
|
|
65
|
+
async,
|
|
66
|
+
defer,
|
|
67
|
+
timeoutMs: CAPTCHA_PROVIDER_LOAD_TIMEOUT_MS,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defineCaptchaModule,
|
|
3
|
+
} from '#modules/captchas/api';
|
|
4
|
+
import {
|
|
5
|
+
loadRecaptchaGlobal,
|
|
6
|
+
type RecaptchaGlobal,
|
|
7
|
+
type RecaptchaProviderOptions,
|
|
8
|
+
} from '#modules/captchas/recaptcha-shared';
|
|
9
|
+
|
|
10
|
+
// This is the classic checkbox widget. The important distinction from the
|
|
11
|
+
// invisible/score flows is that we never trigger execution ourselves; the user
|
|
12
|
+
// must solve the already-rendered widget before submit succeeds.
|
|
13
|
+
export const recaptchaV2CheckboxModule = defineCaptchaModule<RecaptchaProviderOptions, RecaptchaGlobal, number | string>({
|
|
14
|
+
id: 'recaptcha-v2-checkbox',
|
|
15
|
+
defaultPlaceholderSelector: '[data-recaptcha-placeholder]',
|
|
16
|
+
defaultTokenFieldNames: ['g-recaptcha-response'],
|
|
17
|
+
load: ({ options }) => {
|
|
18
|
+
return loadRecaptchaGlobal(options.provider);
|
|
19
|
+
},
|
|
20
|
+
mount: ({ api, container, provider, services }) => {
|
|
21
|
+
return new Promise((resolve) => {
|
|
22
|
+
api.ready(() => {
|
|
23
|
+
// For checkbox mode the Google SDK gives us a widget id, which
|
|
24
|
+
// later becomes important for reset/unmount.
|
|
25
|
+
resolve(api.render(container, {
|
|
26
|
+
sitekey: provider.siteKey || '',
|
|
27
|
+
theme: provider.theme || 'light',
|
|
28
|
+
size: provider.size || 'normal',
|
|
29
|
+
callback: (token?: string) => {
|
|
30
|
+
// Checkbox mode solves interactively before submit, so
|
|
31
|
+
// the callback is the point where the transport layer
|
|
32
|
+
// finally becomes "screen-stage ready".
|
|
33
|
+
if (typeof token === 'string' && token.trim() !== '') {
|
|
34
|
+
services.tokens.write(token.trim());
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
services.errors.clear();
|
|
38
|
+
},
|
|
39
|
+
'expired-callback': () => {
|
|
40
|
+
services.tokens.clear();
|
|
41
|
+
services.errors.clear();
|
|
42
|
+
},
|
|
43
|
+
'error-callback': () => {
|
|
44
|
+
services.tokens.clear();
|
|
45
|
+
},
|
|
46
|
+
}));
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
},
|
|
50
|
+
screen: ({ placeholder, services, stageCtx }) => {
|
|
51
|
+
// Checkbox mode does not execute at submit time. We simply check if the
|
|
52
|
+
// user already solved it; if not, abort immediately with a field-style
|
|
53
|
+
// error and let the user interact with the widget.
|
|
54
|
+
if (services.tokens.has()) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const message = services.errors.getDefaultMessage();
|
|
59
|
+
services.errors.show(message, placeholder);
|
|
60
|
+
stageCtx.abort(message);
|
|
61
|
+
},
|
|
62
|
+
reset: ({ api, widget, services }) => {
|
|
63
|
+
// A successful AJAX submit or form reset should leave the checkbox
|
|
64
|
+
// rendered but unsolved, so `reset()` is the right provider behavior.
|
|
65
|
+
api.reset(widget);
|
|
66
|
+
services.tokens.clear();
|
|
67
|
+
},
|
|
68
|
+
unmount: ({ api, widget, services }) => {
|
|
69
|
+
api.reset(widget);
|
|
70
|
+
services.tokens.clear();
|
|
71
|
+
},
|
|
72
|
+
});
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defineCaptchaModule,
|
|
3
|
+
} from '#modules/captchas/api';
|
|
4
|
+
import { CAPTCHA_EXECUTE_WAIT_FOR_VALUE_MS } from '#modules/captchas/constants';
|
|
5
|
+
import {
|
|
6
|
+
loadRecaptchaGlobal,
|
|
7
|
+
type RecaptchaGlobal,
|
|
8
|
+
type RecaptchaProviderOptions,
|
|
9
|
+
} from '#modules/captchas/recaptcha-shared';
|
|
10
|
+
|
|
11
|
+
type RecaptchaWidgetState = {
|
|
12
|
+
id: number | string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
async function waitForRecaptchaResponse(api: RecaptchaGlobal, widgetId: number | string, timeoutMs = 1000): Promise<string | undefined> {
|
|
16
|
+
// Invisible reCAPTCHA does not always synchronously pass the final token
|
|
17
|
+
// through the callback at the exact moment we need it. Polling `getResponse`
|
|
18
|
+
// gives us a provider-local fallback without leaking Google-specific logic
|
|
19
|
+
// into shared captcha services.
|
|
20
|
+
const deadline = Date.now() + timeoutMs;
|
|
21
|
+
|
|
22
|
+
while (Date.now() < deadline) {
|
|
23
|
+
const response = typeof api.getResponse === 'function' ? api.getResponse(widgetId) : '';
|
|
24
|
+
|
|
25
|
+
if (typeof response === 'string' && response.trim() !== '') {
|
|
26
|
+
return response.trim();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
await new Promise((resolve) => {
|
|
30
|
+
window.setTimeout(resolve, 100);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const recaptchaV2InvisibleModule = defineCaptchaModule<RecaptchaProviderOptions, RecaptchaGlobal, RecaptchaWidgetState>({
|
|
38
|
+
id: 'recaptcha-v2-invisible',
|
|
39
|
+
defaultPlaceholderSelector: '[data-recaptcha-placeholder]',
|
|
40
|
+
defaultTokenFieldNames: ['g-recaptcha-response'],
|
|
41
|
+
load: ({ options }) => {
|
|
42
|
+
return loadRecaptchaGlobal(options.provider);
|
|
43
|
+
},
|
|
44
|
+
mount: ({ api, container, provider, services }) => {
|
|
45
|
+
return new Promise((resolve) => {
|
|
46
|
+
api.ready(() => {
|
|
47
|
+
const widgetId = api.render(container, {
|
|
48
|
+
sitekey: provider.siteKey || '',
|
|
49
|
+
badge: provider.badge || 'bottomright',
|
|
50
|
+
size: 'invisible',
|
|
51
|
+
callback: (token?: string) => {
|
|
52
|
+
// Google sometimes passes the token directly and other
|
|
53
|
+
// times expects consumers to read it back from the
|
|
54
|
+
// widget response API. Normalize both paths here.
|
|
55
|
+
const response = typeof token === 'string' && token.trim() !== ''
|
|
56
|
+
? token.trim()
|
|
57
|
+
: (typeof api.getResponse === 'function' ? api.getResponse(widgetId) : '');
|
|
58
|
+
|
|
59
|
+
if (response) {
|
|
60
|
+
services.tokens.write(response);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
services.errors.clear();
|
|
64
|
+
},
|
|
65
|
+
'expired-callback': () => {
|
|
66
|
+
services.tokens.clear();
|
|
67
|
+
services.errors.clear();
|
|
68
|
+
},
|
|
69
|
+
'error-callback': () => {
|
|
70
|
+
services.tokens.clear();
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
resolve({
|
|
75
|
+
// Keep the widget id in a tiny object so later lifecycle
|
|
76
|
+
// methods have a stable shape to work with.
|
|
77
|
+
id: widgetId,
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
},
|
|
82
|
+
screen: async({ api, widget, placeholder, services, stageCtx }) => {
|
|
83
|
+
// If we already have a token, do not re-execute the invisible widget.
|
|
84
|
+
if (services.tokens.has()) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Invisible mode needs an explicit submit-time execute call.
|
|
89
|
+
api.execute(widget.id);
|
|
90
|
+
const token = await waitForRecaptchaResponse(api, widget.id);
|
|
91
|
+
|
|
92
|
+
if (typeof token === 'string' && token.trim() !== '') {
|
|
93
|
+
services.tokens.write(token.trim());
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const hasToken = await services.tokens.wait(CAPTCHA_EXECUTE_WAIT_FOR_VALUE_MS);
|
|
97
|
+
|
|
98
|
+
if (!hasToken) {
|
|
99
|
+
const message = services.errors.getDefaultMessage();
|
|
100
|
+
services.errors.show(message, placeholder);
|
|
101
|
+
stageCtx.abort(message);
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
unmount: ({ api, widget, services }) => {
|
|
105
|
+
api.reset(widget.id);
|
|
106
|
+
services.tokens.clear();
|
|
107
|
+
},
|
|
108
|
+
});
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defineCaptchaModule,
|
|
3
|
+
} from '#modules/captchas/api';
|
|
4
|
+
import { CAPTCHA_EXECUTE_WAIT_FOR_VALUE_MS } from '#modules/captchas/constants';
|
|
5
|
+
import {
|
|
6
|
+
loadRecaptchaGlobal,
|
|
7
|
+
type RecaptchaGlobal,
|
|
8
|
+
type RecaptchaProviderOptions,
|
|
9
|
+
} from '#modules/captchas/recaptcha-shared';
|
|
10
|
+
|
|
11
|
+
// reCAPTCHA v3 is the "no visible widget" score flow. We still mount a module
|
|
12
|
+
// instance so it can participate in the same submit lifecycle as other
|
|
13
|
+
// providers, but most of the work happens at screen time.
|
|
14
|
+
export const recaptchaV3Module = defineCaptchaModule<RecaptchaProviderOptions, RecaptchaGlobal, number | string>({
|
|
15
|
+
id: 'recaptcha-v3',
|
|
16
|
+
defaultPlaceholderSelector: '[data-recaptcha-placeholder]',
|
|
17
|
+
defaultTokenFieldNames: ['g-recaptcha-response'],
|
|
18
|
+
load: ({ options }) => {
|
|
19
|
+
// Score-based flows use a site-key `render=` mode instead of an
|
|
20
|
+
// explicit widget render, so the loader needs the site key up front.
|
|
21
|
+
return loadRecaptchaGlobal(options.provider, false, options.provider.siteKey || undefined);
|
|
22
|
+
},
|
|
23
|
+
mount: ({ api, provider }) => {
|
|
24
|
+
return new Promise((resolve) => {
|
|
25
|
+
api.ready(() => {
|
|
26
|
+
// There is no real widget id for v3. We store the site key as
|
|
27
|
+
// the "widget" value purely so the managed factory can treat
|
|
28
|
+
// this provider like every other captcha module instance.
|
|
29
|
+
resolve(provider.siteKey || 'recaptcha-v3');
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
},
|
|
33
|
+
screen: async({ api, provider, placeholder, services, stageCtx }) => {
|
|
34
|
+
// If a token already exists we can skip execution, which matters for
|
|
35
|
+
// re-renders or multi-step flows where the same challenge was already
|
|
36
|
+
// completed very recently.
|
|
37
|
+
if (services.tokens.has()) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// v3 returns its token directly from `execute()`, unlike widget-based
|
|
42
|
+
// captchas that signal completion later via callbacks.
|
|
43
|
+
const token = await api.execute(provider.siteKey || '', { action: provider.action || 'submit' });
|
|
44
|
+
|
|
45
|
+
if (typeof token === 'string' && token.trim() !== '') {
|
|
46
|
+
services.tokens.write(token.trim());
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// We still wait on the shared token layer so the module follows the
|
|
50
|
+
// same transport contract as every other captcha provider.
|
|
51
|
+
const hasToken = await services.tokens.wait(CAPTCHA_EXECUTE_WAIT_FOR_VALUE_MS);
|
|
52
|
+
|
|
53
|
+
if (!hasToken) {
|
|
54
|
+
const message = services.errors.getDefaultMessage();
|
|
55
|
+
services.errors.show(message, placeholder);
|
|
56
|
+
stageCtx.abort(message);
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
unmount: ({ services }) => {
|
|
60
|
+
services.tokens.clear();
|
|
61
|
+
},
|
|
62
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { definePassiveCaptchaModule } from '#modules/captchas/api';
|
|
2
|
+
|
|
3
|
+
// Snaptcha is the remaining "passive" captcha style: there is no browser SDK
|
|
4
|
+
// to load and no user-facing widget to render. The shared passive factory is a
|
|
5
|
+
// good fit here because the provider is really just about keeping a hidden
|
|
6
|
+
// transport value in sync across renders and token refreshes.
|
|
7
|
+
export const snaptchaModule = definePassiveCaptchaModule({
|
|
8
|
+
id: 'snaptcha',
|
|
9
|
+
defaultPlaceholderSelector: '[data-snaptcha-captcha-placeholder]',
|
|
10
|
+
});
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defineCaptchaModule,
|
|
3
|
+
} from '#modules/captchas/api';
|
|
4
|
+
import {
|
|
5
|
+
CAPTCHA_EXECUTE_WAIT_FOR_VALUE_MS,
|
|
6
|
+
CAPTCHA_PROVIDER_LOAD_TIMEOUT_MS,
|
|
7
|
+
CAPTCHA_SUBMIT_WAIT_FOR_VALUE_MS,
|
|
8
|
+
} from '#modules/captchas/constants';
|
|
9
|
+
import { loadScriptAndEnsureGlobal } from '#utils/scripts';
|
|
10
|
+
import { getScriptAttributes } from '#modules/captchas/utils';
|
|
11
|
+
|
|
12
|
+
// Narrow local contract for the Cloudflare Turnstile browser SDK.
|
|
13
|
+
type TurnstileGlobal = {
|
|
14
|
+
render: (container: HTMLElement, options: Record<string, unknown>) => string;
|
|
15
|
+
execute: (widgetId: string) => void;
|
|
16
|
+
reset: (widgetId: string) => void;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// Provider-specific options only. Generic captcha concerns are handled by the
|
|
20
|
+
// shared captcha services/factory layer.
|
|
21
|
+
type TurnstileProviderOptions = {
|
|
22
|
+
siteKey?: string | null;
|
|
23
|
+
theme?: string;
|
|
24
|
+
size?: string;
|
|
25
|
+
appearance?: string;
|
|
26
|
+
execution?: string;
|
|
27
|
+
loadingMethod?: string;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
function getTurnstileWaitForValueMs(provider: TurnstileProviderOptions): number {
|
|
31
|
+
const appearance = provider.appearance || 'always';
|
|
32
|
+
const execution = provider.execution || (appearance === 'execute' ? 'execute' : 'render');
|
|
33
|
+
|
|
34
|
+
return execution === 'execute' ? CAPTCHA_EXECUTE_WAIT_FOR_VALUE_MS : CAPTCHA_SUBMIT_WAIT_FOR_VALUE_MS;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async function loadTurnstileGlobal(options: TurnstileProviderOptions): Promise<TurnstileGlobal> {
|
|
38
|
+
// Turnstile is simpler than hCaptcha/reCAPTCHA: once the script has loaded,
|
|
39
|
+
// the global is ready to use immediately. This helper stays local because
|
|
40
|
+
// the URL and readiness assumptions are specific to Turnstile.
|
|
41
|
+
const { async, defer } = getScriptAttributes(options.loadingMethod);
|
|
42
|
+
|
|
43
|
+
return loadScriptAndEnsureGlobal<TurnstileGlobal>('turnstile', {
|
|
44
|
+
id: 'FORMIE_TURNSTILE_SCRIPT',
|
|
45
|
+
src: 'https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit',
|
|
46
|
+
async,
|
|
47
|
+
defer,
|
|
48
|
+
timeoutMs: CAPTCHA_PROVIDER_LOAD_TIMEOUT_MS,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export const turnstileModule = defineCaptchaModule<TurnstileProviderOptions, TurnstileGlobal, string>({
|
|
53
|
+
id: 'turnstile',
|
|
54
|
+
defaultPlaceholderSelector: '[data-turnstile-placeholder]',
|
|
55
|
+
defaultTokenFieldNames: ['cf-turnstile-response'],
|
|
56
|
+
load: ({ options }) => {
|
|
57
|
+
// Load once, then let the managed captcha factory share the resolved
|
|
58
|
+
// SDK across any remount/reset work for this form.
|
|
59
|
+
return loadTurnstileGlobal(options.provider);
|
|
60
|
+
},
|
|
61
|
+
mount: ({ api, container, provider, services }) => {
|
|
62
|
+
// Turnstile has two related concepts:
|
|
63
|
+
// - `appearance`: when/if the widget should visibly appear
|
|
64
|
+
// - `execution`: whether the challenge runs automatically or only when
|
|
65
|
+
// we explicitly call `turnstile.execute(widget)` during submit
|
|
66
|
+
//
|
|
67
|
+
// We normalize that relationship here because it is a provider concern,
|
|
68
|
+
// not something the shared captcha module should need to understand.
|
|
69
|
+
const appearance = provider.appearance || 'always';
|
|
70
|
+
const execution = provider.execution || (appearance === 'execute' ? 'execute' : 'render');
|
|
71
|
+
|
|
72
|
+
return api.render(container, {
|
|
73
|
+
sitekey: provider.siteKey || '',
|
|
74
|
+
theme: provider.theme || 'auto',
|
|
75
|
+
size: provider.size || 'normal',
|
|
76
|
+
appearance,
|
|
77
|
+
execution,
|
|
78
|
+
callback: (token?: string) => {
|
|
79
|
+
// Turnstile verification completed successfully, so copy its
|
|
80
|
+
// token into the shared transport inputs for backend submit.
|
|
81
|
+
if (typeof token === 'string' && token.trim() !== '') {
|
|
82
|
+
services.tokens.write(token.trim());
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
services.errors.clear();
|
|
86
|
+
},
|
|
87
|
+
'expired-callback': () => {
|
|
88
|
+
// Expired tokens must be removed immediately so a later submit
|
|
89
|
+
// cannot reuse something Turnstile no longer accepts.
|
|
90
|
+
services.tokens.clear();
|
|
91
|
+
services.errors.clear();
|
|
92
|
+
},
|
|
93
|
+
'timeout-callback': () => {
|
|
94
|
+
// Treat timeouts like expiry: the challenge must be solved again.
|
|
95
|
+
services.tokens.clear();
|
|
96
|
+
services.errors.clear();
|
|
97
|
+
},
|
|
98
|
+
'error-callback': () => {
|
|
99
|
+
// Provider-side failures should not leave stale transport state.
|
|
100
|
+
services.tokens.clear();
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
},
|
|
104
|
+
screen: ({ api, widget, placeholder, services, provider, stageCtx }) => {
|
|
105
|
+
// Submit-time rule: if a valid token already exists, do nothing. This
|
|
106
|
+
// covers cases where Turnstile solved itself on load or before submit.
|
|
107
|
+
if (services.tokens.has()) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Otherwise explicitly ask Turnstile to run now. This is what supports
|
|
112
|
+
// "run on submit" style configurations without the shared module
|
|
113
|
+
// needing any Turnstile-specific policy logic.
|
|
114
|
+
api.execute(widget);
|
|
115
|
+
return services.tokens.wait(getTurnstileWaitForValueMs(provider)).then((hasToken) => {
|
|
116
|
+
if (!hasToken) {
|
|
117
|
+
// No token arrived in time, so block the screen stage and show
|
|
118
|
+
// the shared themed inline error next to the active placeholder.
|
|
119
|
+
const message = services.errors.getDefaultMessage();
|
|
120
|
+
services.errors.show(message, placeholder);
|
|
121
|
+
stageCtx.abort(message);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
},
|
|
125
|
+
unmount: ({ api, widget, services }) => {
|
|
126
|
+
// Reset provider state whenever the widget is torn down so the DOM
|
|
127
|
+
// transport layer and the provider widget stay in sync.
|
|
128
|
+
api.reset(widget);
|
|
129
|
+
services.tokens.clear();
|
|
130
|
+
},
|
|
131
|
+
});
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { sleep } from '#utils/async';
|
|
2
|
+
|
|
3
|
+
export function getScriptAttributes(loadingMethod?: string): { async: boolean; defer: boolean } {
|
|
4
|
+
const normalized = String(loadingMethod || 'asyncDefer').toLowerCase();
|
|
5
|
+
|
|
6
|
+
return {
|
|
7
|
+
async: normalized.includes('async'),
|
|
8
|
+
defer: normalized.includes('defer'),
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function getInputValue(root: ParentNode, name: string): string {
|
|
13
|
+
const inputs = Array.from(root.querySelectorAll(`input[name="${name}"], textarea[name="${name}"]`)) as Array<HTMLInputElement | HTMLTextAreaElement>;
|
|
14
|
+
|
|
15
|
+
for (const input of inputs) {
|
|
16
|
+
const value = String(input.value || '').trim();
|
|
17
|
+
|
|
18
|
+
if (value !== '') {
|
|
19
|
+
return value;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return '';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function hasCaptchaValue(root: ParentNode, names: string[]): boolean {
|
|
27
|
+
return names.some((name) => {
|
|
28
|
+
return getInputValue(root, name) !== '';
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function clearCaptchaValues(root: ParentNode, names: string[]): void {
|
|
33
|
+
names.forEach((name) => {
|
|
34
|
+
const inputs = Array.from(root.querySelectorAll(`input[name="${name}"], textarea[name="${name}"]`)) as Array<HTMLInputElement | HTMLTextAreaElement>;
|
|
35
|
+
|
|
36
|
+
inputs.forEach((input) => {
|
|
37
|
+
input.value = '';
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function ensureCaptchaValueInput(
|
|
43
|
+
root: ParentNode,
|
|
44
|
+
name: string,
|
|
45
|
+
{
|
|
46
|
+
value = '',
|
|
47
|
+
container,
|
|
48
|
+
}: {
|
|
49
|
+
value?: string;
|
|
50
|
+
container?: HTMLElement | null;
|
|
51
|
+
} = {},
|
|
52
|
+
): HTMLInputElement {
|
|
53
|
+
let input = root.querySelector(`input[name="${name}"]`) as HTMLInputElement | null;
|
|
54
|
+
|
|
55
|
+
if (!input) {
|
|
56
|
+
input = document.createElement('input');
|
|
57
|
+
input.type = 'hidden';
|
|
58
|
+
input.name = name;
|
|
59
|
+
|
|
60
|
+
const target = container || (root instanceof HTMLElement ? root : null);
|
|
61
|
+
target?.appendChild(input);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
input.value = value;
|
|
65
|
+
|
|
66
|
+
return input;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export async function waitForCaptchaValue(root: ParentNode, names: string[], waitForValueMs: number): Promise<boolean> {
|
|
70
|
+
if (hasCaptchaValue(root, names)) {
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const deadline = Date.now() + Math.max(waitForValueMs, 0);
|
|
75
|
+
|
|
76
|
+
while (Date.now() < deadline) {
|
|
77
|
+
await sleep(120);
|
|
78
|
+
|
|
79
|
+
if (hasCaptchaValue(root, names)) {
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return false;
|
|
85
|
+
}
|