@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,485 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
FormieModuleDefinition,
|
|
3
|
+
FormieModuleInstance,
|
|
4
|
+
ModuleSetupContext,
|
|
5
|
+
SubmitHookContext,
|
|
6
|
+
} from '#contracts/modules';
|
|
7
|
+
import type { FormSubmitResult } from '#contracts/schema';
|
|
8
|
+
import { DEFAULT_WAIT_FOR_VALUE_MS } from '#modules/captchas/constants';
|
|
9
|
+
import { ensureCaptchaValueInput, waitForCaptchaValue } from '#modules/captchas/utils';
|
|
10
|
+
import {
|
|
11
|
+
createCaptchaHostServices,
|
|
12
|
+
type CaptchaHostServices,
|
|
13
|
+
type CaptchaModuleOptions,
|
|
14
|
+
type NormalizedCaptchaModuleOptions,
|
|
15
|
+
normalizeCaptchaModuleOptions,
|
|
16
|
+
} from '#modules/captchas/host';
|
|
17
|
+
import { createDebug } from '#utils/debug';
|
|
18
|
+
import { getFormStateEventName } from '#utils/event-names';
|
|
19
|
+
|
|
20
|
+
type Cleanup = () => void;
|
|
21
|
+
const debug = createDebug('captchas');
|
|
22
|
+
|
|
23
|
+
type CaptchaModuleFactory<TProvider extends Record<string, unknown>> = {
|
|
24
|
+
id: string;
|
|
25
|
+
defaultPlaceholderSelector: string;
|
|
26
|
+
defaultTokenFieldNames?: string[];
|
|
27
|
+
defaultWaitForValueMs?: number;
|
|
28
|
+
setup: (ctx: CaptchaModuleSetupContext<TProvider>) => Promise<FormieModuleInstance | void>;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export type ManagedCaptchaModuleAdapter<
|
|
32
|
+
TProvider extends Record<string, unknown>,
|
|
33
|
+
TApi,
|
|
34
|
+
TWidget,
|
|
35
|
+
> = {
|
|
36
|
+
id: string;
|
|
37
|
+
defaultPlaceholderSelector: string;
|
|
38
|
+
defaultTokenFieldNames?: string[];
|
|
39
|
+
load: (ctx: CaptchaModuleSetupContext<TProvider>) => Promise<TApi>;
|
|
40
|
+
mount: (args: {
|
|
41
|
+
api: TApi;
|
|
42
|
+
placeholder: HTMLElement;
|
|
43
|
+
container: HTMLElement;
|
|
44
|
+
services: CaptchaHostServices;
|
|
45
|
+
options: NormalizedCaptchaModuleOptions<TProvider>;
|
|
46
|
+
provider: TProvider;
|
|
47
|
+
}) => Promise<TWidget> | TWidget;
|
|
48
|
+
screen: (args: {
|
|
49
|
+
api: TApi;
|
|
50
|
+
widget: TWidget;
|
|
51
|
+
placeholder: HTMLElement;
|
|
52
|
+
services: CaptchaHostServices;
|
|
53
|
+
options: NormalizedCaptchaModuleOptions<TProvider>;
|
|
54
|
+
provider: TProvider;
|
|
55
|
+
stageCtx: SubmitHookContext;
|
|
56
|
+
}) => Promise<void> | void;
|
|
57
|
+
unmount?: (args: {
|
|
58
|
+
api: TApi;
|
|
59
|
+
widget: TWidget;
|
|
60
|
+
placeholder: HTMLElement;
|
|
61
|
+
services: CaptchaHostServices;
|
|
62
|
+
options: NormalizedCaptchaModuleOptions<TProvider>;
|
|
63
|
+
provider: TProvider;
|
|
64
|
+
}) => Promise<void> | void;
|
|
65
|
+
reset?: (args: {
|
|
66
|
+
api: TApi;
|
|
67
|
+
widget: TWidget;
|
|
68
|
+
placeholder: HTMLElement;
|
|
69
|
+
services: CaptchaHostServices;
|
|
70
|
+
options: NormalizedCaptchaModuleOptions<TProvider>;
|
|
71
|
+
provider: TProvider;
|
|
72
|
+
reason: 'submit-result' | 'reset-state';
|
|
73
|
+
}) => Promise<void> | void;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export type CaptchaModuleSetupContext<TProvider extends Record<string, unknown>> = Omit<ModuleSetupContext, 'options'> & {
|
|
77
|
+
options: NormalizedCaptchaModuleOptions<TProvider>;
|
|
78
|
+
services: CaptchaHostServices;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export function createCaptchaModule<TProvider extends Record<string, unknown> = Record<string, unknown>>({
|
|
82
|
+
id,
|
|
83
|
+
defaultPlaceholderSelector,
|
|
84
|
+
defaultTokenFieldNames = [],
|
|
85
|
+
defaultWaitForValueMs = DEFAULT_WAIT_FOR_VALUE_MS,
|
|
86
|
+
setup,
|
|
87
|
+
}: CaptchaModuleFactory<TProvider>): FormieModuleDefinition {
|
|
88
|
+
return {
|
|
89
|
+
id,
|
|
90
|
+
kind: 'captcha',
|
|
91
|
+
match: () => true,
|
|
92
|
+
setup: async(ctx) => {
|
|
93
|
+
// Every captcha module, passive or widget-backed, starts from the
|
|
94
|
+
// same two building blocks:
|
|
95
|
+
// 1. normalized options from the backend manifest
|
|
96
|
+
// 2. shared host services for placeholders, errors, tokens, and
|
|
97
|
+
// refresh-token events
|
|
98
|
+
const options = normalizeCaptchaModuleOptions<TProvider>(id, ctx.options || {}, {
|
|
99
|
+
defaultPlaceholderSelector,
|
|
100
|
+
defaultTokenFieldNames,
|
|
101
|
+
defaultWaitForValueMs,
|
|
102
|
+
});
|
|
103
|
+
debug.log('Setup module.', {
|
|
104
|
+
moduleId: id,
|
|
105
|
+
placeholderSelector: options.ui.placeholderSelector,
|
|
106
|
+
tokenFieldNames: options.transport.tokenFieldNames,
|
|
107
|
+
});
|
|
108
|
+
const services = createCaptchaHostServices(ctx, options);
|
|
109
|
+
|
|
110
|
+
return setup({
|
|
111
|
+
...ctx,
|
|
112
|
+
options,
|
|
113
|
+
services,
|
|
114
|
+
});
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function createPassiveCaptchaModule({
|
|
120
|
+
id,
|
|
121
|
+
defaultPlaceholderSelector,
|
|
122
|
+
defaultTokenFieldNames = [],
|
|
123
|
+
defaultWaitForValueMs = DEFAULT_WAIT_FOR_VALUE_MS,
|
|
124
|
+
}: {
|
|
125
|
+
id: string;
|
|
126
|
+
defaultPlaceholderSelector: string;
|
|
127
|
+
defaultTokenFieldNames?: string[];
|
|
128
|
+
defaultWaitForValueMs?: number;
|
|
129
|
+
}): FormieModuleDefinition {
|
|
130
|
+
return createCaptchaModule<Record<string, never>>({
|
|
131
|
+
id,
|
|
132
|
+
defaultPlaceholderSelector,
|
|
133
|
+
defaultTokenFieldNames,
|
|
134
|
+
defaultWaitForValueMs,
|
|
135
|
+
setup: async({ services, options, root }) => {
|
|
136
|
+
// Passive captchas do not have a browser SDK or visible widget.
|
|
137
|
+
// Their lifecycle is basically "keep the hidden transport input in
|
|
138
|
+
// sync, then verify it still exists at screen-stage submit time".
|
|
139
|
+
const cleanups: Cleanup[] = [];
|
|
140
|
+
let activePlaceholder = services.placeholder.getPrimary();
|
|
141
|
+
let sessionKey = options.transport.sessionKey;
|
|
142
|
+
let value = options.transport.value || '';
|
|
143
|
+
|
|
144
|
+
const renderPlaceholder = (placeholder: HTMLElement | null) => {
|
|
145
|
+
if (!placeholder || !sessionKey) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// For passive providers, rendering simply means writing the
|
|
150
|
+
// hidden input into the current placeholder.
|
|
151
|
+
placeholder.innerHTML = '';
|
|
152
|
+
ensureCaptchaValueInput(placeholder, sessionKey, {
|
|
153
|
+
value,
|
|
154
|
+
container: placeholder,
|
|
155
|
+
});
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const visibility = services.placeholder.observe(
|
|
159
|
+
(placeholder) => {
|
|
160
|
+
activePlaceholder = placeholder;
|
|
161
|
+
debug.log('Passive placeholder visible.', {
|
|
162
|
+
moduleId: id,
|
|
163
|
+
});
|
|
164
|
+
renderPlaceholder(placeholder);
|
|
165
|
+
},
|
|
166
|
+
(placeholder) => {
|
|
167
|
+
if (activePlaceholder === placeholder) {
|
|
168
|
+
activePlaceholder = services.placeholder.getPrimary();
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
placeholder.innerHTML = '';
|
|
172
|
+
},
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
cleanups.push(visibility.cleanup);
|
|
176
|
+
renderPlaceholder(activePlaceholder);
|
|
177
|
+
|
|
178
|
+
cleanups.push(services.refresh.onTokensRefreshed((entry) => {
|
|
179
|
+
sessionKey = typeof entry.sessionKey === 'string' && entry.sessionKey.trim() !== ''
|
|
180
|
+
? entry.sessionKey.trim()
|
|
181
|
+
: sessionKey;
|
|
182
|
+
value = typeof entry.value === 'string' ? entry.value : '';
|
|
183
|
+
|
|
184
|
+
const placeholder = services.placeholder.getPrimary() || activePlaceholder;
|
|
185
|
+
activePlaceholder = placeholder;
|
|
186
|
+
renderPlaceholder(placeholder);
|
|
187
|
+
}));
|
|
188
|
+
|
|
189
|
+
return {
|
|
190
|
+
destroy: () => {
|
|
191
|
+
cleanups.forEach((cleanup) => {
|
|
192
|
+
cleanup();
|
|
193
|
+
});
|
|
194
|
+
},
|
|
195
|
+
onBeforeStage: async(stageCtx) => {
|
|
196
|
+
if (stageCtx.stage !== 'screen' || stageCtx.action !== 'submit') {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const tokenFieldNames = sessionKey ? [sessionKey] : options.transport.tokenFieldNames;
|
|
201
|
+
|
|
202
|
+
if (tokenFieldNames.length === 0) {
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const hasToken = await waitForCaptchaValue(root, tokenFieldNames, options.transport.waitForValueMs);
|
|
207
|
+
|
|
208
|
+
if (!hasToken) {
|
|
209
|
+
const message = services.errors.getDefaultMessage();
|
|
210
|
+
services.errors.show(message, activePlaceholder);
|
|
211
|
+
debug.warn('Passive captcha missing token.', {
|
|
212
|
+
moduleId: id,
|
|
213
|
+
tokenFieldNames,
|
|
214
|
+
});
|
|
215
|
+
stageCtx.abort(message);
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
};
|
|
219
|
+
},
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export function createManagedCaptchaModule<
|
|
224
|
+
TProvider extends Record<string, unknown>,
|
|
225
|
+
TApi,
|
|
226
|
+
TWidget,
|
|
227
|
+
>(adapter: ManagedCaptchaModuleAdapter<TProvider, TApi, TWidget>): FormieModuleDefinition {
|
|
228
|
+
return createCaptchaModule<TProvider>({
|
|
229
|
+
id: adapter.id,
|
|
230
|
+
defaultPlaceholderSelector: adapter.defaultPlaceholderSelector,
|
|
231
|
+
defaultTokenFieldNames: adapter.defaultTokenFieldNames,
|
|
232
|
+
setup: async(ctx) => {
|
|
233
|
+
// Managed providers are the widget/SDK-backed family. The factory
|
|
234
|
+
// owns only the generic plumbing:
|
|
235
|
+
// - load the provider API once
|
|
236
|
+
// - mount/unmount when placeholders appear/disappear
|
|
237
|
+
// - call the provider's `screen()` at submit time
|
|
238
|
+
//
|
|
239
|
+
// It intentionally does not know provider policy such as "execute
|
|
240
|
+
// now" vs "must already be solved" - that stays in each module.
|
|
241
|
+
const cleanups: Cleanup[] = [];
|
|
242
|
+
const mountedWidgets = new Map<HTMLElement, TWidget>();
|
|
243
|
+
const mountPromises = new Map<HTMLElement, Promise<void>>();
|
|
244
|
+
let activePlaceholder = ctx.services.placeholder.getPrimary();
|
|
245
|
+
let destroyed = false;
|
|
246
|
+
|
|
247
|
+
let apiPromise: Promise<TApi> | null = null;
|
|
248
|
+
|
|
249
|
+
const getApi = async(): Promise<TApi> => {
|
|
250
|
+
if (!apiPromise) {
|
|
251
|
+
debug.log('Loading captcha provider API.', {
|
|
252
|
+
moduleId: adapter.id,
|
|
253
|
+
});
|
|
254
|
+
apiPromise = adapter.load(ctx);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return apiPromise;
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
const unmountPlaceholder = async(placeholder: HTMLElement) => {
|
|
261
|
+
const widget = mountedWidgets.get(placeholder);
|
|
262
|
+
|
|
263
|
+
ctx.services.errors.clear(placeholder);
|
|
264
|
+
|
|
265
|
+
if (!widget) {
|
|
266
|
+
placeholder.innerHTML = '';
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const api = await getApi();
|
|
271
|
+
|
|
272
|
+
if (adapter.unmount) {
|
|
273
|
+
await adapter.unmount({
|
|
274
|
+
api,
|
|
275
|
+
widget,
|
|
276
|
+
placeholder,
|
|
277
|
+
services: ctx.services,
|
|
278
|
+
options: ctx.options,
|
|
279
|
+
provider: ctx.options.provider,
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
mountedWidgets.delete(placeholder);
|
|
284
|
+
placeholder.innerHTML = '';
|
|
285
|
+
ctx.services.tokens.clear();
|
|
286
|
+
debug.log('Unmounted captcha placeholder widget.', {
|
|
287
|
+
moduleId: adapter.id,
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
if (activePlaceholder === placeholder) {
|
|
291
|
+
activePlaceholder = ctx.services.placeholder.getPrimary();
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
const mountPlaceholder = async(placeholder: HTMLElement) => {
|
|
296
|
+
if (destroyed || mountedWidgets.has(placeholder) || mountPromises.has(placeholder)) {
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Guard against repeated visibility events or rapid DOM churn
|
|
301
|
+
// by tracking an in-flight mount promise per placeholder.
|
|
302
|
+
const promise = (async() => {
|
|
303
|
+
const api = await getApi();
|
|
304
|
+
|
|
305
|
+
if (destroyed || mountedWidgets.has(placeholder)) {
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const container = ctx.services.placeholder.createContainer(placeholder);
|
|
310
|
+
// Providers always render into a fresh container so the
|
|
311
|
+
// shared services can safely tear down and rebuild
|
|
312
|
+
// placeholder DOM.
|
|
313
|
+
const widget = await adapter.mount({
|
|
314
|
+
api,
|
|
315
|
+
placeholder,
|
|
316
|
+
container,
|
|
317
|
+
services: ctx.services,
|
|
318
|
+
options: ctx.options,
|
|
319
|
+
provider: ctx.options.provider,
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
mountedWidgets.set(placeholder, widget);
|
|
323
|
+
activePlaceholder = placeholder;
|
|
324
|
+
debug.log('Mounted captcha placeholder widget.', {
|
|
325
|
+
moduleId: adapter.id,
|
|
326
|
+
});
|
|
327
|
+
})().finally(() => {
|
|
328
|
+
mountPromises.delete(placeholder);
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
mountPromises.set(placeholder, promise);
|
|
332
|
+
|
|
333
|
+
await promise;
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
const visibility = ctx.services.placeholder.observe(
|
|
337
|
+
(placeholder) => {
|
|
338
|
+
activePlaceholder = placeholder;
|
|
339
|
+
void mountPlaceholder(placeholder);
|
|
340
|
+
},
|
|
341
|
+
(placeholder) => {
|
|
342
|
+
void unmountPlaceholder(placeholder);
|
|
343
|
+
},
|
|
344
|
+
);
|
|
345
|
+
|
|
346
|
+
cleanups.push(visibility.cleanup);
|
|
347
|
+
|
|
348
|
+
const rerenderVisiblePlaceholders = async(reason: 'submit-result' | 'reset-state') => {
|
|
349
|
+
// Some providers can cheaply reset in-place, while others are
|
|
350
|
+
// safer to unmount and mount again. The provider advertises
|
|
351
|
+
// that through the optional `reset()` hook.
|
|
352
|
+
const visiblePlaceholders = visibility.getVisible();
|
|
353
|
+
const placeholdersToMount = visiblePlaceholders;
|
|
354
|
+
|
|
355
|
+
if (adapter.reset) {
|
|
356
|
+
const api = await getApi();
|
|
357
|
+
|
|
358
|
+
for (const placeholder of placeholdersToMount) {
|
|
359
|
+
const widget = mountedWidgets.get(placeholder);
|
|
360
|
+
|
|
361
|
+
if (!widget) {
|
|
362
|
+
await mountPlaceholder(placeholder);
|
|
363
|
+
continue;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
await adapter.reset({
|
|
367
|
+
api,
|
|
368
|
+
widget,
|
|
369
|
+
placeholder,
|
|
370
|
+
services: ctx.services,
|
|
371
|
+
options: ctx.options,
|
|
372
|
+
provider: ctx.options.provider,
|
|
373
|
+
reason,
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
ctx.services.tokens.clear();
|
|
377
|
+
ctx.services.errors.clear(placeholder);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
visibility.reconcile();
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
for (const placeholder of Array.from(mountedWidgets.keys())) {
|
|
385
|
+
await unmountPlaceholder(placeholder);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
for (const placeholder of placeholdersToMount) {
|
|
389
|
+
await mountPlaceholder(placeholder);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
visibility.reconcile();
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
cleanups.push(ctx.services.events.onRoot('formie:submit:result', (event) => {
|
|
396
|
+
const detail = event instanceof CustomEvent ? event.detail as FormSubmitResult : null;
|
|
397
|
+
|
|
398
|
+
if (detail?.stage === 'validate') {
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
if (detail?.ok === false && detail?.stage === 'screen') {
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
if (detail?.ok === true) {
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
void rerenderVisiblePlaceholders('submit-result');
|
|
411
|
+
}));
|
|
412
|
+
|
|
413
|
+
if (ctx.form) {
|
|
414
|
+
cleanups.push(ctx.services.events.onForm(getFormStateEventName('reset'), () => {
|
|
415
|
+
activePlaceholder = ctx.services.placeholder.getPrimary() || activePlaceholder;
|
|
416
|
+
|
|
417
|
+
window.setTimeout(() => {
|
|
418
|
+
void rerenderVisiblePlaceholders('reset-state');
|
|
419
|
+
}, 0);
|
|
420
|
+
}));
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
return {
|
|
424
|
+
destroy: async() => {
|
|
425
|
+
destroyed = true;
|
|
426
|
+
cleanups.forEach((cleanup) => {
|
|
427
|
+
cleanup();
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
for (const placeholder of Array.from(mountedWidgets.keys())) {
|
|
431
|
+
await unmountPlaceholder(placeholder);
|
|
432
|
+
}
|
|
433
|
+
},
|
|
434
|
+
onBeforeStage: async(stageCtx) => {
|
|
435
|
+
if (stageCtx.stage !== 'screen' || stageCtx.action !== 'submit') {
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// By the time provider `screen()` runs, the widget is
|
|
440
|
+
// guaranteed to be mounted and the active placeholder is
|
|
441
|
+
// resolved. That lets provider code focus on challenge
|
|
442
|
+
// policy rather than generic lifecycle setup.
|
|
443
|
+
const visiblePlaceholders = visibility.getVisible();
|
|
444
|
+
|
|
445
|
+
// Captcha fields on hidden pages should not run in screen stage.
|
|
446
|
+
if (visiblePlaceholders.length === 0) {
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
let placeholder = visiblePlaceholders.find((candidate) => candidate === activePlaceholder)
|
|
451
|
+
|| visiblePlaceholders[0];
|
|
452
|
+
|
|
453
|
+
await mountPlaceholder(placeholder);
|
|
454
|
+
placeholder = activePlaceholder || placeholder;
|
|
455
|
+
|
|
456
|
+
ctx.services.errors.clear(placeholder);
|
|
457
|
+
|
|
458
|
+
const widget = mountedWidgets.get(placeholder);
|
|
459
|
+
|
|
460
|
+
if (!widget) {
|
|
461
|
+
const message = ctx.services.errors.getDefaultMessage();
|
|
462
|
+
ctx.services.errors.show(message, placeholder);
|
|
463
|
+
debug.warn('Captcha widget unavailable at screen stage.', {
|
|
464
|
+
moduleId: adapter.id,
|
|
465
|
+
});
|
|
466
|
+
stageCtx.abort(message);
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
const api = await getApi();
|
|
471
|
+
|
|
472
|
+
await adapter.screen({
|
|
473
|
+
api,
|
|
474
|
+
widget,
|
|
475
|
+
placeholder,
|
|
476
|
+
services: ctx.services,
|
|
477
|
+
options: ctx.options,
|
|
478
|
+
provider: ctx.options.provider,
|
|
479
|
+
stageCtx,
|
|
480
|
+
});
|
|
481
|
+
},
|
|
482
|
+
};
|
|
483
|
+
},
|
|
484
|
+
});
|
|
485
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { defineCaptchaModule } from '#modules/captchas/api';
|
|
2
|
+
|
|
3
|
+
type FriendlyChallengeModule = typeof import('friendly-challenge');
|
|
4
|
+
|
|
5
|
+
// FriendlyCaptcha v1 ships a different package and callback shape from v2, so
|
|
6
|
+
// it keeps its own provider module even though the high-level flow is similar.
|
|
7
|
+
type FriendlyCaptchaProviderOptions = {
|
|
8
|
+
siteKey?: string | null;
|
|
9
|
+
language?: string;
|
|
10
|
+
startMode?: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const friendlyCaptchaV1Module = defineCaptchaModule<
|
|
14
|
+
FriendlyCaptchaProviderOptions,
|
|
15
|
+
FriendlyChallengeModule,
|
|
16
|
+
import('friendly-challenge').WidgetInstance
|
|
17
|
+
>({
|
|
18
|
+
id: 'friendly-captcha-v1',
|
|
19
|
+
defaultPlaceholderSelector: '[data-friendly-captcha-placeholder]',
|
|
20
|
+
defaultTokenFieldNames: ['frc-captcha-solution'],
|
|
21
|
+
load: async() => {
|
|
22
|
+
// The provider owns its package choice. Shared captcha services only
|
|
23
|
+
// cares that `load()` returns some API object for later lifecycle work.
|
|
24
|
+
return import('friendly-challenge');
|
|
25
|
+
},
|
|
26
|
+
mount: ({ api, container, provider, services }) => {
|
|
27
|
+
return new api.WidgetInstance(container, {
|
|
28
|
+
sitekey: provider.siteKey || '',
|
|
29
|
+
startMode: (provider.startMode as 'auto' | 'focus' | 'none' | undefined) || 'none',
|
|
30
|
+
language: (provider.language as 'en' | undefined) || 'en',
|
|
31
|
+
solutionFieldName: 'frc-captcha-solution',
|
|
32
|
+
doneCallback: (token?: string) => {
|
|
33
|
+
// v1 writes to its provider-defined solution field name, while
|
|
34
|
+
// the shared transport services own how that ends up in the form DOM.
|
|
35
|
+
if (typeof token === 'string' && token.trim() !== '') {
|
|
36
|
+
services.tokens.write(token.trim());
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
services.errors.clear();
|
|
40
|
+
},
|
|
41
|
+
errorCallback: () => {
|
|
42
|
+
services.tokens.clear();
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
},
|
|
46
|
+
screen: async({ widget, placeholder, services, stageCtx }) => {
|
|
47
|
+
// FriendlyCaptcha is started programmatically on submit when needed.
|
|
48
|
+
if (services.tokens.has()) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
await widget.start();
|
|
53
|
+
const hasToken = await services.tokens.wait();
|
|
54
|
+
|
|
55
|
+
if (!hasToken) {
|
|
56
|
+
const message = services.errors.getDefaultMessage();
|
|
57
|
+
services.errors.show(message, placeholder);
|
|
58
|
+
stageCtx.abort(message);
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
unmount: ({ widget, services }) => {
|
|
62
|
+
widget.destroy();
|
|
63
|
+
services.tokens.clear();
|
|
64
|
+
},
|
|
65
|
+
});
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { defineCaptchaModule } from '#modules/captchas/api';
|
|
2
|
+
|
|
3
|
+
type FriendlyCaptchaSdkModule = typeof import('@friendlycaptcha/sdk');
|
|
4
|
+
type FriendlyCaptchaWidget = import('@friendlycaptcha/sdk').WidgetHandle;
|
|
5
|
+
|
|
6
|
+
// FriendlyCaptcha v2 is similar in intent to v1, but its SDK, widget handle
|
|
7
|
+
// type and emitted event names are different enough that keeping a dedicated
|
|
8
|
+
// provider module is clearer than trying to abstract them together.
|
|
9
|
+
type FriendlyCaptchaProviderOptions = {
|
|
10
|
+
siteKey?: string | null;
|
|
11
|
+
language?: string;
|
|
12
|
+
startMode?: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const friendlyCaptchaV2Module = defineCaptchaModule<
|
|
16
|
+
FriendlyCaptchaProviderOptions,
|
|
17
|
+
FriendlyCaptchaSdkModule,
|
|
18
|
+
FriendlyCaptchaWidget
|
|
19
|
+
>({
|
|
20
|
+
id: 'friendly-captcha-v2',
|
|
21
|
+
defaultPlaceholderSelector: '[data-friendly-captcha-placeholder]',
|
|
22
|
+
defaultTokenFieldNames: ['frc-captcha-response'],
|
|
23
|
+
load: async () => {
|
|
24
|
+
return import('@friendlycaptcha/sdk');
|
|
25
|
+
},
|
|
26
|
+
mount: ({ api, container, provider, services }) => {
|
|
27
|
+
// v2 uses an SDK instance that then creates a widget handle. This is a
|
|
28
|
+
// good example of provider-specific lifecycle detail that should stay
|
|
29
|
+
// outside the generic captcha services layer.
|
|
30
|
+
const sdk = new api.FriendlyCaptchaSDK();
|
|
31
|
+
const widget = sdk.createWidget({
|
|
32
|
+
element: container,
|
|
33
|
+
sitekey: provider.siteKey || '',
|
|
34
|
+
formFieldName: 'frc-captcha-response',
|
|
35
|
+
language: provider.language,
|
|
36
|
+
startMode: (provider.startMode as 'auto' | 'focus' | 'none' | undefined) || 'none',
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
widget.addEventListener('frc:widget.complete', (event) => {
|
|
40
|
+
const detail = (event as CustomEvent<{ response?: string }>).detail;
|
|
41
|
+
|
|
42
|
+
// v2 exposes the solved response in its custom event detail rather
|
|
43
|
+
// than a direct callback argument.
|
|
44
|
+
if (typeof detail?.response === 'string' && detail.response.trim() !== '') {
|
|
45
|
+
services.tokens.write(detail.response.trim());
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
services.errors.clear();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
widget.addEventListener('frc:widget.expire', () => {
|
|
52
|
+
services.tokens.clear();
|
|
53
|
+
services.errors.clear();
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
widget.addEventListener('frc:widget.error', (event) => {
|
|
57
|
+
const detail = (event as CustomEvent<{ error?: unknown }>).detail;
|
|
58
|
+
if (detail?.error) {
|
|
59
|
+
services.tokens.clear();
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
return widget;
|
|
64
|
+
},
|
|
65
|
+
screen: async ({ widget, placeholder, services, stageCtx }) => {
|
|
66
|
+
// As with v1, start the challenge only if no token is currently present.
|
|
67
|
+
if (services.tokens.has()) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
widget.start();
|
|
72
|
+
const hasToken = await services.tokens.wait();
|
|
73
|
+
|
|
74
|
+
if (!hasToken) {
|
|
75
|
+
const message = services.errors.getDefaultMessage();
|
|
76
|
+
services.errors.show(message, placeholder);
|
|
77
|
+
stageCtx.abort(message);
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
unmount: ({ widget, services }) => {
|
|
81
|
+
widget.destroy();
|
|
82
|
+
services.tokens.clear();
|
|
83
|
+
},
|
|
84
|
+
});
|