@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,238 @@
|
|
|
1
|
+
import type { ModuleSetupContext } from '#contracts/modules';
|
|
2
|
+
import { getFieldModuleEventName } from '#utils/event-names';
|
|
3
|
+
import type { ValidationContext } from '#validation/types';
|
|
4
|
+
|
|
5
|
+
type ElementCleanup = void | (() => void);
|
|
6
|
+
type ValidatorApi = {
|
|
7
|
+
addValidator: (name: string, validatorFunction: (ctx: ValidationContext) => boolean, errorMessage?: (ctx: ValidationContext) => string) => void;
|
|
8
|
+
removeValidator: (name: string) => void;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
type FormWithValidationApi = HTMLFormElement & {
|
|
12
|
+
formieValidation?: ValidatorApi;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const fallbackCssEscape = (value: string): string => {
|
|
16
|
+
return value.replace(/["\\]/g, '\\$&');
|
|
17
|
+
};
|
|
18
|
+
const validatorRegistrations = new WeakMap<HTMLFormElement, Map<string, number>>();
|
|
19
|
+
|
|
20
|
+
export function escapeSelectorValue(value: string): string {
|
|
21
|
+
if (typeof window.CSS?.escape === 'function') {
|
|
22
|
+
return window.CSS.escape(value);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return fallbackCssEscape(value);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function getFieldContainers(root: Element, fieldHandle?: string): HTMLElement[] {
|
|
29
|
+
if (!fieldHandle) {
|
|
30
|
+
return Array.from(root.querySelectorAll('[data-formie-field-handle]')).filter((element): element is HTMLElement => {
|
|
31
|
+
return element instanceof HTMLElement;
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return Array.from(root.querySelectorAll(`[data-formie-field-handle="${escapeSelectorValue(fieldHandle)}"]`)).filter((element): element is HTMLElement => {
|
|
36
|
+
return element instanceof HTMLElement;
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function getModuleFieldContainers(ctx: ModuleSetupContext): HTMLElement[] {
|
|
41
|
+
// Target-aware manifests may already hand a module one concrete field node.
|
|
42
|
+
// Fall back to scanning descendants only when the target is a broader surface.
|
|
43
|
+
if (ctx.target instanceof HTMLElement && ctx.target.hasAttribute('data-formie-field-handle')) {
|
|
44
|
+
return [ctx.target];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (ctx.target instanceof HTMLElement) {
|
|
48
|
+
return Array.from(ctx.target.querySelectorAll('[data-formie-field-handle]')).filter((element): element is HTMLElement => {
|
|
49
|
+
return element instanceof HTMLElement;
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return [];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function getModuleFieldTarget(ctx: ModuleSetupContext): HTMLElement | null {
|
|
57
|
+
return getModuleFieldContainers(ctx)[0] || null;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function getFormValidator(form: HTMLFormElement | null): ValidatorApi | null {
|
|
61
|
+
if (!form) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const formWithValidationApi = form as FormWithValidationApi;
|
|
66
|
+
return formWithValidationApi.formieValidation || null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function retainFormValidators(
|
|
70
|
+
form: HTMLFormElement | null,
|
|
71
|
+
key: string,
|
|
72
|
+
register: (validator: ValidatorApi) => void,
|
|
73
|
+
): void {
|
|
74
|
+
if (!form) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const formRegistrations = validatorRegistrations.get(form) || new Map<string, number>();
|
|
79
|
+
const currentCount = formRegistrations.get(key) || 0;
|
|
80
|
+
|
|
81
|
+
if (currentCount === 0) {
|
|
82
|
+
const validator = getFormValidator(form);
|
|
83
|
+
if (validator) {
|
|
84
|
+
register(validator);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
formRegistrations.set(key, currentCount + 1);
|
|
89
|
+
validatorRegistrations.set(form, formRegistrations);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function releaseFormValidators(form: HTMLFormElement | null, key: string, validatorNames: readonly string[]): void {
|
|
93
|
+
if (!form) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const formRegistrations = validatorRegistrations.get(form);
|
|
98
|
+
const currentCount = formRegistrations?.get(key) || 0;
|
|
99
|
+
|
|
100
|
+
if (currentCount <= 1) {
|
|
101
|
+
const validator = getFormValidator(form);
|
|
102
|
+
validatorNames.forEach((validatorName) => {
|
|
103
|
+
validator?.removeValidator(validatorName);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
formRegistrations?.delete(key);
|
|
107
|
+
|
|
108
|
+
if (!formRegistrations || formRegistrations.size === 0) {
|
|
109
|
+
validatorRegistrations.delete(form);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
validatorRegistrations.set(form, formRegistrations);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
formRegistrations?.set(key, currentCount - 1);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function observeMatchingElements<TElement extends Element>(
|
|
121
|
+
root: Element,
|
|
122
|
+
selector: string,
|
|
123
|
+
isMatch: (element: Element) => element is TElement,
|
|
124
|
+
init: (element: TElement) => ElementCleanup,
|
|
125
|
+
): () => void {
|
|
126
|
+
const cleanups = new Map<TElement, () => void>();
|
|
127
|
+
|
|
128
|
+
const register = (element: Element): void => {
|
|
129
|
+
if (!isMatch(element) || cleanups.has(element)) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const cleanup = init(element);
|
|
134
|
+
cleanups.set(element, cleanup || (() => {}));
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const scan = (node: ParentNode): void => {
|
|
138
|
+
if (node instanceof Element && node.matches(selector)) {
|
|
139
|
+
register(node);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
node.querySelectorAll(selector).forEach((element) => {
|
|
143
|
+
register(element);
|
|
144
|
+
});
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const prune = (): void => {
|
|
148
|
+
cleanups.forEach((cleanup, element) => {
|
|
149
|
+
if (root.contains(element)) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Dynamic row/page removal should run per-element teardown immediately
|
|
154
|
+
// so nested modules do not retain stale listeners or observer state.
|
|
155
|
+
cleanup();
|
|
156
|
+
cleanups.delete(element);
|
|
157
|
+
});
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
scan(root);
|
|
161
|
+
|
|
162
|
+
const observer = new MutationObserver((mutations) => {
|
|
163
|
+
mutations.forEach((mutation) => {
|
|
164
|
+
mutation.addedNodes.forEach((node) => {
|
|
165
|
+
if (node instanceof Element) {
|
|
166
|
+
scan(node);
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
prune();
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
observer.observe(root, {
|
|
175
|
+
childList: true,
|
|
176
|
+
subtree: true,
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
return () => {
|
|
180
|
+
observer.disconnect();
|
|
181
|
+
|
|
182
|
+
cleanups.forEach((cleanup) => {
|
|
183
|
+
cleanup();
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
cleanups.clear();
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function getOwnerDocument(root: Element): Document {
|
|
191
|
+
return root.ownerDocument || document;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export function getTemplateSource(
|
|
195
|
+
root: Element,
|
|
196
|
+
templateId: string | null | undefined,
|
|
197
|
+
): HTMLTemplateElement | HTMLScriptElement | HTMLElement | null {
|
|
198
|
+
const doc = getOwnerDocument(root);
|
|
199
|
+
|
|
200
|
+
if (templateId) {
|
|
201
|
+
const explicitCandidates: Array<Element | null> = [
|
|
202
|
+
root.querySelector(`template[data-formie-template-id="${escapeSelectorValue(templateId)}"]`),
|
|
203
|
+
root.querySelector(`script[data-formie-template-id="${escapeSelectorValue(templateId)}"]`),
|
|
204
|
+
doc.querySelector(`template[data-formie-template-id="${escapeSelectorValue(templateId)}"]`),
|
|
205
|
+
doc.querySelector(`script[data-formie-template-id="${escapeSelectorValue(templateId)}"]`),
|
|
206
|
+
doc.getElementById(templateId),
|
|
207
|
+
];
|
|
208
|
+
|
|
209
|
+
for (const candidate of explicitCandidates) {
|
|
210
|
+
if (candidate instanceof HTMLTemplateElement || candidate instanceof HTMLScriptElement) {
|
|
211
|
+
return candidate;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export function getTemplateSourceHtml(source: HTMLTemplateElement | HTMLScriptElement | HTMLElement): string {
|
|
220
|
+
if (source instanceof HTMLTemplateElement) {
|
|
221
|
+
return source.innerHTML;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (source instanceof HTMLScriptElement) {
|
|
225
|
+
return source.textContent || '';
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return source.innerHTML;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export function dispatchFieldEvent(target: Element, moduleId: string, name: string, detail: Record<string, unknown>): void {
|
|
232
|
+
const eventName = getFieldModuleEventName(moduleId, name);
|
|
233
|
+
|
|
234
|
+
target.dispatchEvent(new CustomEvent(eventName, {
|
|
235
|
+
bubbles: true,
|
|
236
|
+
detail,
|
|
237
|
+
}));
|
|
238
|
+
}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import SignaturePad from 'signature_pad';
|
|
2
|
+
import signatureCss from '#theme/fields/_signature.css?inline';
|
|
3
|
+
|
|
4
|
+
import type { FormieModuleDefinition } from '#contracts/modules';
|
|
5
|
+
import { dispatchFieldEvent, getModuleFieldContainers } from '#modules/fields/shared';
|
|
6
|
+
import { ensureModuleStyles } from '#modules/styles';
|
|
7
|
+
|
|
8
|
+
const INPUT_SELECTOR = 'input[data-formie-signature-input]';
|
|
9
|
+
const CANVAS_SELECTOR = 'canvas[data-formie-signature-canvas]';
|
|
10
|
+
const CLEAR_SELECTOR = '[data-formie-signature-clear]';
|
|
11
|
+
const MODULE_ID = 'signature';
|
|
12
|
+
|
|
13
|
+
ensureModuleStyles(MODULE_ID, [signatureCss]);
|
|
14
|
+
|
|
15
|
+
type SignatureOptions = {
|
|
16
|
+
backgroundColor?: string;
|
|
17
|
+
penColor?: string;
|
|
18
|
+
penWeight?: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
function getCanvasSize(canvas: HTMLCanvasElement): { width: number; height: number } {
|
|
22
|
+
const rect = canvas.getBoundingClientRect();
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
width: Math.round(rect.width),
|
|
26
|
+
height: Math.round(rect.height),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function drawValueOnCanvas(canvas: HTMLCanvasElement, value: string): void {
|
|
31
|
+
if (!value) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const image = new Image();
|
|
36
|
+
image.src = value;
|
|
37
|
+
image.onload = () => {
|
|
38
|
+
const ratio = Math.max(window.devicePixelRatio || 1, 1);
|
|
39
|
+
const context = canvas.getContext('2d');
|
|
40
|
+
if (!context) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
context.drawImage(image, 0, 0, canvas.width / ratio, canvas.height / ratio);
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function initSignatureField(
|
|
49
|
+
root: HTMLElement,
|
|
50
|
+
field: HTMLElement,
|
|
51
|
+
input: HTMLInputElement,
|
|
52
|
+
canvas: HTMLCanvasElement,
|
|
53
|
+
clearButton: HTMLElement | null,
|
|
54
|
+
options: SignatureOptions,
|
|
55
|
+
): () => void {
|
|
56
|
+
const penWeight = parseFloat(options.penWeight || '2') || 2;
|
|
57
|
+
const resizeTarget = canvas.parentElement instanceof HTMLElement ? canvas.parentElement : field;
|
|
58
|
+
const signaturePad = new SignaturePad(canvas, {
|
|
59
|
+
backgroundColor: options.backgroundColor || 'rgba(255, 255, 255, 0)',
|
|
60
|
+
penColor: options.penColor || '#000000',
|
|
61
|
+
dotSize: penWeight,
|
|
62
|
+
minWidth: penWeight,
|
|
63
|
+
maxWidth: penWeight,
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const resizeCanvas = () => {
|
|
67
|
+
const { width, height } = getCanvasSize(canvas);
|
|
68
|
+
|
|
69
|
+
if (!(width > 0) || !(height > 0)) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const ratio = Math.max(window.devicePixelRatio || 1, 1);
|
|
74
|
+
const context = canvas.getContext('2d');
|
|
75
|
+
if (!context) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// SignaturePad clears bitmap state when the canvas size changes, so resize
|
|
80
|
+
// captures the current data URL first and redraws it onto the new surface.
|
|
81
|
+
const existingValue = input.value || (signaturePad.isEmpty() ? '' : signaturePad.toDataURL());
|
|
82
|
+
canvas.width = width * ratio;
|
|
83
|
+
canvas.height = height * ratio;
|
|
84
|
+
context.setTransform(1, 0, 0, 1, 0, 0);
|
|
85
|
+
context.scale(ratio, ratio);
|
|
86
|
+
signaturePad.clear();
|
|
87
|
+
drawValueOnCanvas(canvas, existingValue);
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const scheduleResize = (delay = 0) => {
|
|
91
|
+
window.setTimeout(() => {
|
|
92
|
+
window.requestAnimationFrame(() => {
|
|
93
|
+
resizeCanvas();
|
|
94
|
+
});
|
|
95
|
+
}, delay);
|
|
96
|
+
};
|
|
97
|
+
const resizeHandler = () => {
|
|
98
|
+
scheduleResize();
|
|
99
|
+
};
|
|
100
|
+
const pageNavigateHandler = () => {
|
|
101
|
+
// Multi-page forms can reveal a signature pad after layout changes; delay
|
|
102
|
+
// slightly so the newly visible page has settled before measuring.
|
|
103
|
+
scheduleResize(100);
|
|
104
|
+
};
|
|
105
|
+
const resizeObserver = typeof ResizeObserver === 'undefined'
|
|
106
|
+
? null
|
|
107
|
+
: new ResizeObserver(() => {
|
|
108
|
+
scheduleResize();
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
const syncInputValue = (nextValue: string) => {
|
|
112
|
+
const valueChanged = input.value !== nextValue;
|
|
113
|
+
input.value = nextValue;
|
|
114
|
+
|
|
115
|
+
if (!valueChanged) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
120
|
+
input.dispatchEvent(new Event('change', { bubbles: true }));
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
const syncValue = () => {
|
|
124
|
+
syncInputValue(signaturePad.isEmpty() ? '' : signaturePad.toDataURL());
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
const clearSignature = () => {
|
|
128
|
+
signaturePad.clear();
|
|
129
|
+
syncInputValue('');
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
signaturePad.addEventListener('endStroke', syncValue);
|
|
133
|
+
window.addEventListener('resize', resizeHandler);
|
|
134
|
+
root.addEventListener('formie:page:navigate:after', pageNavigateHandler as EventListener);
|
|
135
|
+
resizeObserver?.observe(resizeTarget);
|
|
136
|
+
scheduleResize();
|
|
137
|
+
|
|
138
|
+
if (clearButton) {
|
|
139
|
+
clearButton.addEventListener('click', clearSignature);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
dispatchFieldEvent(field, MODULE_ID, 'init', {
|
|
143
|
+
signature: signaturePad,
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
return () => {
|
|
147
|
+
signaturePad.removeEventListener('endStroke', syncValue);
|
|
148
|
+
window.removeEventListener('resize', resizeHandler);
|
|
149
|
+
root.removeEventListener('formie:page:navigate:after', pageNavigateHandler as EventListener);
|
|
150
|
+
resizeObserver?.disconnect();
|
|
151
|
+
if (clearButton) {
|
|
152
|
+
clearButton.removeEventListener('click', clearSignature);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
signaturePad.clear();
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export const signatureModule: FormieModuleDefinition = {
|
|
160
|
+
id: MODULE_ID,
|
|
161
|
+
kind: 'field',
|
|
162
|
+
match: (ctx) => {
|
|
163
|
+
return !!ctx.target.querySelector(CANVAS_SELECTOR);
|
|
164
|
+
},
|
|
165
|
+
setup: async(ctx) => {
|
|
166
|
+
const options = (ctx.options || {}) as SignatureOptions;
|
|
167
|
+
const root = ctx.root instanceof HTMLElement
|
|
168
|
+
? ctx.root
|
|
169
|
+
: (ctx.target instanceof HTMLElement ? ctx.target : null);
|
|
170
|
+
|
|
171
|
+
if (!root) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const fields = getModuleFieldContainers(ctx);
|
|
176
|
+
const cleanups = fields.map((field) => {
|
|
177
|
+
const input = field.querySelector(INPUT_SELECTOR);
|
|
178
|
+
const canvas = field.querySelector(CANVAS_SELECTOR);
|
|
179
|
+
const clearButton = field.querySelector(CLEAR_SELECTOR);
|
|
180
|
+
|
|
181
|
+
if (!(input instanceof HTMLInputElement) || !(canvas instanceof HTMLCanvasElement)) {
|
|
182
|
+
return () => {};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return initSignatureField(root, field, input, canvas, clearButton instanceof HTMLElement ? clearButton : null, options);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
await ctx.emit('formie:module:signature:init', {
|
|
189
|
+
count: cleanups.length,
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
return {
|
|
193
|
+
destroy: () => {
|
|
194
|
+
cleanups.forEach((cleanup) => {
|
|
195
|
+
cleanup();
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
void ctx.emit('formie:module:signature:destroy', {});
|
|
199
|
+
},
|
|
200
|
+
};
|
|
201
|
+
},
|
|
202
|
+
};
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import summaryCss from '#theme/fields/_summary.css?inline';
|
|
2
|
+
|
|
3
|
+
import type { FormieModuleDefinition } from '#contracts/modules';
|
|
4
|
+
import { dispatchFieldEvent, getModuleFieldContainers } from '#modules/fields/shared';
|
|
5
|
+
import { ensureModuleStyles } from '#modules/styles';
|
|
6
|
+
import { toggleThemeClasses } from '#theme/theme-classes';
|
|
7
|
+
import { debounce } from '#utils/async';
|
|
8
|
+
import { createDebug } from '#utils/debug';
|
|
9
|
+
import { requestText } from '#utils/http';
|
|
10
|
+
|
|
11
|
+
const BLOCKS_SELECTOR = '[data-formie-summary-blocks]';
|
|
12
|
+
const CONTAINER_SELECTOR = '[data-formie-summary-container]';
|
|
13
|
+
const SUMMARY_ACTION = 'formie/fields/get-summary-html';
|
|
14
|
+
const MODULE_ID = 'summary';
|
|
15
|
+
const debug = createDebug('fields', 'summary');
|
|
16
|
+
|
|
17
|
+
ensureModuleStyles(MODULE_ID, [summaryCss]);
|
|
18
|
+
|
|
19
|
+
type SummaryRequestState = {
|
|
20
|
+
accessToken: string | null;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
function getSummaryRequestUrl(): string {
|
|
24
|
+
const url = new URL(window.location.href);
|
|
25
|
+
url.hash = '';
|
|
26
|
+
|
|
27
|
+
return url.toString();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function getSummaryRequestState(field: HTMLElement): SummaryRequestState {
|
|
31
|
+
const summaryTokenInput = field.querySelector('[data-formie-summary-token]') as HTMLInputElement | null;
|
|
32
|
+
const accessToken = summaryTokenInput?.value?.trim() || null;
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
accessToken,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async function requestSummaryHtml(form: HTMLFormElement, state: SummaryRequestState, signal?: AbortSignal): Promise<string> {
|
|
40
|
+
if (!state.accessToken) {
|
|
41
|
+
throw new Error('Summary field requires an access token.');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Summary output is server-rendered from the current submission state rather
|
|
45
|
+
// than rebuilt in JS, so it stays aligned with backend formatting rules.
|
|
46
|
+
const formData = new FormData(form);
|
|
47
|
+
formData.set('action', SUMMARY_ACTION);
|
|
48
|
+
formData.set('accessToken', state.accessToken);
|
|
49
|
+
|
|
50
|
+
return requestText(getSummaryRequestUrl(), {
|
|
51
|
+
method: 'POST',
|
|
52
|
+
body: formData,
|
|
53
|
+
signal,
|
|
54
|
+
headers: {
|
|
55
|
+
Accept: 'text/html',
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function initSummaryField(field: HTMLElement, root: Element): () => void {
|
|
61
|
+
const form = field.closest('form');
|
|
62
|
+
|
|
63
|
+
if (!(form instanceof HTMLFormElement)) {
|
|
64
|
+
debug.warn('Missing form ancestor; skipping field.');
|
|
65
|
+
return () => {};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
let hasFetched = false;
|
|
69
|
+
let isDirty = true;
|
|
70
|
+
let isVisible = false;
|
|
71
|
+
let dirtyVersion = 0;
|
|
72
|
+
let requestVersion = 0;
|
|
73
|
+
let activeRequest: AbortController | null = null;
|
|
74
|
+
|
|
75
|
+
const getBlocks = (): HTMLElement | null => {
|
|
76
|
+
const blocks = field.querySelector(BLOCKS_SELECTOR);
|
|
77
|
+
return blocks instanceof HTMLElement ? blocks : null;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const getContainer = (): HTMLElement | null => {
|
|
81
|
+
const container = field.querySelector(CONTAINER_SELECTOR);
|
|
82
|
+
return container instanceof HTMLElement ? container : null;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const setLoadingState = (isLoading: boolean): void => {
|
|
86
|
+
const blocks = getBlocks();
|
|
87
|
+
|
|
88
|
+
if (!blocks) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (isLoading) {
|
|
93
|
+
blocks.setAttribute('data-formie-loading', 'true');
|
|
94
|
+
blocks.setAttribute('aria-busy', 'true');
|
|
95
|
+
toggleThemeClasses(blocks, form, 'loading', true);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
blocks.removeAttribute('data-formie-loading');
|
|
100
|
+
blocks.removeAttribute('aria-busy');
|
|
101
|
+
toggleThemeClasses(blocks, form, 'loading', false);
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const initialState = getSummaryRequestState(field);
|
|
105
|
+
setLoadingState(!!initialState.accessToken);
|
|
106
|
+
|
|
107
|
+
const queueFetch = (): void => {
|
|
108
|
+
if (!isVisible || (hasFetched && !isDirty)) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
debug.log('Queueing fetch.');
|
|
113
|
+
void fetchSummary();
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const fetchSummary = debounce(async() => {
|
|
117
|
+
const state = getSummaryRequestState(field);
|
|
118
|
+
|
|
119
|
+
if (!getBlocks() || !state.accessToken) {
|
|
120
|
+
debug.warn('Missing state for fetch.', state);
|
|
121
|
+
setLoadingState(false);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
requestVersion += 1;
|
|
126
|
+
const currentRequestVersion = requestVersion;
|
|
127
|
+
const requestDirtyVersion = dirtyVersion;
|
|
128
|
+
activeRequest?.abort();
|
|
129
|
+
activeRequest = new AbortController();
|
|
130
|
+
setLoadingState(true);
|
|
131
|
+
|
|
132
|
+
try {
|
|
133
|
+
const html = await requestSummaryHtml(form, state, activeRequest.signal);
|
|
134
|
+
|
|
135
|
+
if (currentRequestVersion !== requestVersion) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const container = getContainer();
|
|
140
|
+
const nextMarkup = document.createElement('template');
|
|
141
|
+
nextMarkup.innerHTML = html.trim();
|
|
142
|
+
const nextContainer = nextMarkup.content.querySelector(CONTAINER_SELECTOR);
|
|
143
|
+
|
|
144
|
+
if (container && nextContainer instanceof HTMLElement) {
|
|
145
|
+
container.replaceWith(nextContainer);
|
|
146
|
+
} else if (container) {
|
|
147
|
+
container.innerHTML = html;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
hasFetched = true;
|
|
151
|
+
isDirty = dirtyVersion !== requestDirtyVersion;
|
|
152
|
+
debug.log('Fetch complete.', {
|
|
153
|
+
isDirty,
|
|
154
|
+
dirtyVersion,
|
|
155
|
+
requestVersion: currentRequestVersion,
|
|
156
|
+
});
|
|
157
|
+
dispatchFieldEvent(field, MODULE_ID, 'fetch-summary', {
|
|
158
|
+
summary: field,
|
|
159
|
+
html,
|
|
160
|
+
});
|
|
161
|
+
} catch (error) {
|
|
162
|
+
if (error instanceof DOMException && error.name === 'AbortError') {
|
|
163
|
+
debug.log('Fetch aborted.');
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
console.error('[formie] Failed to load summary field HTML.', error);
|
|
168
|
+
} finally {
|
|
169
|
+
if (currentRequestVersion === requestVersion) {
|
|
170
|
+
setLoadingState(false);
|
|
171
|
+
activeRequest = null;
|
|
172
|
+
|
|
173
|
+
if (isDirty) {
|
|
174
|
+
queueFetch();
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}, 300);
|
|
179
|
+
|
|
180
|
+
const markDirty = (event?: Event): void => {
|
|
181
|
+
const target = event?.target;
|
|
182
|
+
|
|
183
|
+
if (target instanceof Node && field.contains(target)) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
isDirty = true;
|
|
188
|
+
dirtyVersion += 1;
|
|
189
|
+
debug.log('Marked dirty.', { dirtyVersion });
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
const handleFieldMutation = (event: Event): void => {
|
|
193
|
+
markDirty(event);
|
|
194
|
+
queueFetch();
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
const handleSubmitResult = (): void => {
|
|
198
|
+
isDirty = true;
|
|
199
|
+
debug.log('Submit result received; refreshing.');
|
|
200
|
+
queueFetch();
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
const handlePageNavigate = (): void => {
|
|
204
|
+
isDirty = true;
|
|
205
|
+
debug.log('Page navigation received; refreshing.');
|
|
206
|
+
queueFetch();
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
// Defer the summary fetch until the field is near view. This avoids extra
|
|
210
|
+
// requests for hidden pages or summaries the user never reaches.
|
|
211
|
+
const observer = new IntersectionObserver((entries) => {
|
|
212
|
+
isVisible = !!entries[0]?.isIntersecting;
|
|
213
|
+
|
|
214
|
+
if (!isVisible) {
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
debug.log('Field became visible.');
|
|
219
|
+
dispatchFieldEvent(field, MODULE_ID, 'field-visible', {
|
|
220
|
+
summary: field,
|
|
221
|
+
});
|
|
222
|
+
queueFetch();
|
|
223
|
+
}, {
|
|
224
|
+
root: form,
|
|
225
|
+
rootMargin: '50px',
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
observer.observe(field);
|
|
229
|
+
form.addEventListener('input', handleFieldMutation);
|
|
230
|
+
form.addEventListener('change', handleFieldMutation);
|
|
231
|
+
root.addEventListener('formie:page:navigate:after', handlePageNavigate as EventListener);
|
|
232
|
+
root.addEventListener('formie:submit:result', handleSubmitResult as EventListener);
|
|
233
|
+
|
|
234
|
+
return () => {
|
|
235
|
+
activeRequest?.abort();
|
|
236
|
+
observer.disconnect();
|
|
237
|
+
form.removeEventListener('input', handleFieldMutation);
|
|
238
|
+
form.removeEventListener('change', handleFieldMutation);
|
|
239
|
+
root.removeEventListener('formie:page:navigate:after', handlePageNavigate as EventListener);
|
|
240
|
+
root.removeEventListener('formie:submit:result', handleSubmitResult as EventListener);
|
|
241
|
+
debug.log('Field destroyed.');
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
export const summaryModule: FormieModuleDefinition = {
|
|
246
|
+
id: MODULE_ID,
|
|
247
|
+
kind: 'field',
|
|
248
|
+
match: (ctx) => {
|
|
249
|
+
return !!ctx.target.querySelector(BLOCKS_SELECTOR);
|
|
250
|
+
},
|
|
251
|
+
setup: async(ctx) => {
|
|
252
|
+
const cleanups = getModuleFieldContainers(ctx).map((field) => {
|
|
253
|
+
return initSummaryField(field, ctx.root);
|
|
254
|
+
});
|
|
255
|
+
debug.log('Module setup.', { fieldCount: cleanups.length });
|
|
256
|
+
|
|
257
|
+
await ctx.emit('formie:module:summary:init', {
|
|
258
|
+
count: cleanups.length,
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
return {
|
|
262
|
+
destroy: () => {
|
|
263
|
+
cleanups.forEach((cleanup) => {
|
|
264
|
+
cleanup();
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
debug.log('Module destroy.', { fieldCount: cleanups.length });
|
|
268
|
+
void ctx.emit('formie:module:summary:destroy', {});
|
|
269
|
+
},
|
|
270
|
+
};
|
|
271
|
+
},
|
|
272
|
+
};
|