@rtstic.dev/pulse 0.0.55 → 0.0.56

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.
@@ -1,2 +1,962 @@
1
- "use strict";(()=>{var H=Object.create;var S=Object.defineProperty;var I=Object.getOwnPropertyDescriptor;var q=Object.getOwnPropertyNames;var k=Object.getPrototypeOf,x=Object.prototype.hasOwnProperty;var F=(l=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(l,{get:(t,e)=>(typeof require<"u"?require:t)[e]}):l)(function(l){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+l+'" is not supported')});var w=(l,t,e,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of q(t))!x.call(l,n)&&n!==e&&S(l,n,{get:()=>t[n],enumerable:!(r=I(t,n))||r.enumerable});return l};var A=(l,t,e)=>(e=l!=null?H(k(l)):{},w(t||!l||!l.__esModule?S(e,"default",{value:l,enumerable:!0}):e,l));function g(l={}){let{root:t=document,initialCountry:e="us",separateDialCode:r=!0,countryCodeSelector:n='input[pulse-form-field="country-code"]',onInit:i,onError:o=c=>console.warn(`[initIntlTelInput] ${c}`)}=l,s=new Map,u=window.intlTelInput;return u?(t.querySelectorAll('input[type="tel"]').forEach(c=>{try{let m=u(c,{initialCountry:e,separateDialCode:r,strictMode:!1,loadUtils:()=>import("https://cdn.jsdelivr.net/npm/intl-tel-input@25/build/js/utils.js")});s.set(c,m),b(m,n),c.addEventListener("countrychange",()=>{b(m,n)}),i?.(c,m)}catch(m){o(`Failed to init on input inside "${C(c)}"`,m)}}),s):(o(`intlTelInput not found on window. Include the script before calling this function.
2
- e.g. <script src="https://cdn.jsdelivr.net/npm/intl-tel-input@25/build/js/intlTelInput.min.js"><\/script>`),s)}function b(l,t){try{let e=l.getSelectedCountryData?.();if(!e?.dialCode)return;document.querySelectorAll(t).forEach(r=>{r.value=`+${e.dialCode}`})}catch{}}function C(l){return l.closest("[pulse-form-block]")?.getAttribute("pulse-field-name")??"unknown"}var L=window.location.host==="influur-staging.webflow.io";function d(l,...t){L&&console.warn(`[MSF:${l}]`,...t)}function p(l,...t){L&&console.error(`[MSF:${l}]`,...t)}var N={1:[{selector:'[data-action="back"]',property:"display",value:"none"},{selector:'[pricing-form-element="progress-fill"]',property:"width",value:"50%"},{selector:"[data-step-1-terms]",property:"display",value:"block"}],2:[{selector:'[data-action="back"]',property:"display",value:"flex"},{selector:'[pricing-form-element="progress-fill"]',property:"width",value:"100%"},{selector:"[data-step-1-terms]",property:"display",value:"none"}]},v=[{type:"company_type",name:"Record Label / Music Distributor","calender-name":"valeria","embed-url":"https://meetings.hubspot.com/valeria-angelini/pulse-valeria-and-alessandra?embed=true"},{type:"industry",name:"Financial Services","calender-name":"david","embed-url":"https://meetings.hubspot.com/david-zarate2?embed=true"},{type:"industry",name:"Sports","calender-name":"steven","embed-url":"https://meetings.hubspot.com/steven-campos?embed=true"},{type:"industry",name:"Beauty","calender-name":"albany","embed-url":"https://meetings.hubspot.com/david-zarate2?embed=true"},{type:"industry",name:"Music","calender-name":"steven","embed-url":"https://meetings.hubspot.com/steven-campos?embed=true"},{type:"industry",name:"Customer Packaged Goods","calender-name":"david","embed-url":"https://meetings.hubspot.com/david-zarate2?embed=true"},{type:"industry",name:"Other","calender-name":"david","embed-url":"https://meetings.hubspot.com/david-zarate2?embed=true"}],T={required:"This field is required",email_invalid:"Please enter a valid email address",email_company:"Please use your company email address",phone_invalid:"Please enter a valid phone number",selection_required:"Please select at least one option",legal_required:"You must accept this to continue"},_={"pulse-demo":["pulse-demo-only","common-fields"],"white-glove-services":["white-glove-only","common-fields"]},O={1:{heading:"Your info",subheading:"Pulse is launching March 2025. Spots for onboarding cohort 1 are limited.",counter:"Step 1/2"},2:{heading:"Personalize",subheading:"Help us personalize your demo.",counter:"Step 2/2"}},E=class{constructor(t,e){this.currentStepIndex=0;this.stepHasBeenValidated=!1;this.originalRequired=new WeakMap;this.fieldState=new Map;this.isFormSubmitted=!1;this.isFormStarted=!1;this.form=t,this.itiInstances=e,this.steps=Array.from(t.querySelectorAll('[data-msf="step"]')),this.steps.length===0&&p("init","No steps found! Check [data-msf='step'] selectors in HTML."),this.steps.forEach((r,n)=>{r.dataset.step||d("init",`Step element at index ${n} is missing data-step attribute`)}),this.bindEvents(),this.cacheOriginalRequiredState(),this.initializeFieldState(),this.showStep(0),this.applyFlowConditions(),this.syncAllFieldState()}bindEvents(){let t=()=>{this.isFormStarted||(this.isFormStarted=!0,this.startAbandonmentCheck())};this.form.addEventListener("input",t),this.form.addEventListener("change",t),this.form.addEventListener("click",e=>{let r=e.target;if(!r)return;let n=r.closest("[data-action]");if(!n)return;let i=n.dataset.action;i==="next"&&(e.preventDefault(),this.next()),i==="back"&&(e.preventDefault(),this.back())}),this.form.addEventListener("submit",e=>{e.preventDefault()}),this.form.addEventListener("input",e=>{let r=e.target;r&&(!(r instanceof HTMLInputElement)&&!(r instanceof HTMLTextAreaElement)&&!(r instanceof HTMLSelectElement)||this.handleLiveValidation())}),this.itiInstances.forEach((e,r)=>{r.addEventListener("countrychange",()=>{this.stepHasBeenValidated&&this.handleLiveValidation()})}),this.form.addEventListener("change",e=>{let r=e.target;r&&r instanceof HTMLInputElement&&r.type==="radio"&&r.name==="flow-type"&&this.applyFlowConditions()}),this.form.addEventListener("input",e=>{let r=e.target;if(!r)return;let n=r.closest("[data-field-key]");if(!n)return;let i=n.dataset.fieldKey;i&&this.updateFieldState(i)}),this.form.addEventListener("change",e=>{let r=e.target;if(!r)return;let n=r.closest("[data-field-key]");if(!n)return;let i=n.dataset.fieldKey;i&&this.updateFieldState(i)})}handleLiveValidation(){if(!this.stepHasBeenValidated)return;let t=this.validateStep(this.currentStepIndex);this.clearErrors(),Object.keys(t).length>0&&this.showErrors(t)}showStep(t){if(t<0||t>=this.steps.length){p("showStep",`Invalid step index: ${t} (total steps: ${this.steps.length})`);return}this.steps.forEach((r,n)=>{r.style.display=n===t?"flex":"none"}),this.currentStepIndex=t,this.stepHasBeenValidated=!1,this.clearErrors();let e=t+1;this.updateStepText(e),this.applyStepStyles(e)}next(){this.stepHasBeenValidated=!0;let t=this.validateStep(this.currentStepIndex);if(Object.keys(t).length>0){this.clearErrors(),this.showErrors(t),this.focusFirstError(t);return}this.clearErrors(),this.stepHasBeenValidated=!1;let e=this.currentStepIndex+1;if(e>=this.steps.length){let n=this.steps[this.currentStepIndex].querySelector('[data-action="next"]');if(n){let s=n.querySelector("[data-action-text]");s?s.textContent="Submitting...":d("next","No [data-action-text] element found inside next button")}else d("next","No [data-action='next'] button found in current step");this.mirrorFieldStateToDOM(),this.setQualificationStatus(),this.loadCalendarEmbed();let i=document.getElementById("webflow-form-submit"),o=document.getElementById("hubspot-form-submit");i||p("submit","Missing #webflow-form-submit button in DOM!"),o||p("submit","Missing #hubspot-form-submit button in DOM!"),i&&o?(this.setSubmissionType("manual"),i.click(),o.click(),this.isFormSubmitted=!0):p("submit","One or both submit buttons not found \u2014 form NOT submitted");return}this.showStep(e)}showErrors(t){Object.entries(t).forEach(([e,r])=>{let n=this.form.querySelector(`[data-required-group="${e}"]`)||this.form.querySelector(`[data-required-legal="${e}"]`);if(n){n.classList.add("has-error");let s=n.querySelector(".field-error");s||(s=document.createElement("div"),s.className="field-error",n.appendChild(s)),s.textContent=T[r],s.setAttribute("data-error-code",r);return}let i=this.form.querySelector(`[name="${e}"]`);if(!i){d("showErrors",`Cannot find field or group for error key: "${e}"`);return}i.classList.add("has-error");let o=i.parentElement?.querySelector(".field-error");o||(o=document.createElement("div"),o.className="field-error",i.parentElement?.appendChild(o)),o.textContent=T[r],o.setAttribute("data-error-code",r)})}clearErrors(){let t=this.form.querySelectorAll(".field-error"),e=this.form.querySelectorAll(".has-error");t.forEach(r=>r.remove()),e.forEach(r=>r.classList.remove("has-error"))}back(){let t=this.currentStepIndex-1;t<0||this.showStep(t)}getFieldsForStep(t){let e=this.steps[t];return e?Array.from(e.querySelectorAll("input, select, textarea")):(p("getFieldsForStep",`Step at index ${t} does not exist`),[])}validateStep(t){let e={};this.getFieldsForStep(t).forEach(s=>{let u=s.name;if(!u||s.type==="checkbox"||s.type==="radio")return;let a=s.value.trim();if(s.hasAttribute("required")&&!a){e[u]="required";return}if(s.type==="email"&&a){if(!this.isValidEmailFormat(a)){e[u]="email_invalid";return}if(!this.isCompanyEmail(a)){e[u]="email_company";return}}if(s.type==="tel"&&a&&this.validatePhoneField(s)){e[u]="phone_invalid";return}});let n=this.validateRequiredSelectionGroups(t),i=this.validateLegalGroups(t);return{...e,...n,...i}}validateRequiredSelectionGroups(t){let e=this.steps[t],r={};return e.querySelectorAll("[data-required-group]").forEach(i=>{let o=i.dataset.requiredGroup;if(!o)return;let u=Array.from(i.querySelectorAll('input[type="checkbox"], input[type="radio"]')).filter(c=>!c.disabled);if(u.length===0)return;u.some(c=>c.checked)||(r[o]="selection_required")}),r}validateLegalGroups(t){let e=this.steps[t],r={};return e.querySelectorAll("[data-required-legal]").forEach(i=>{let o=i.dataset.requiredLegal;if(!o)return;let s=i.querySelector('input[type="checkbox"]');!s||s.disabled||s.checked||(r[o]="legal_required")}),r}startAbandonmentCheck(){setTimeout(()=>{if(this.isFormSubmitted)return;let t=this.getFormStateJSON().find(s=>s["field-name"]==="email"),e=this.getFormStateJSON().find(s=>s["field-name"]==="first_name"),r=this.getFormStateJSON().find(s=>s["field-name"]==="last_name"),n=t&&t.value&&this.isValidEmailFormat(t.value),i=e&&e.value.trim().length>0,o=r&&r.value.trim().length>0;if(n&&i&&o){console.warn("[MSF] User is likely to skip the form submission \u2014 losing a lead. Email:",t.value),this.mirrorFieldStateToDOM();let s=document.getElementById("hubspot-form-submit");s?(this.setSubmissionType("automated"),s.click()):p("abandonCheck","Missing #hubspot-form-submit button in DOM!")}},30*60*1e3)}setSubmissionType(t){let e=document.getElementById("submission_type");e?e.value=t:d("setSubmissionType","No element found with id 'submission_type'")}isValidEmailFormat(t){return/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(t)}isCompanyEmail(t){let e=["gmail.com","yahoo.com","hotmail.com","outlook.com","icloud.com","aol.com"],r=t.split("@")[1]?.toLowerCase();return r?!e.includes(r):!1}validatePhoneField(t){let e=this.itiInstances.get(t);return e?t.value.trim()?e.isValidNumber()?null:"phone_invalid":null:(d("phoneValidation",`No ITI instance found for field "${t.name}" \u2014 skipping phone validation`),null)}focusFirstError(t){let e=Object.keys(t)[0];if(!e)return;let r=this.form.querySelector(`[data-required-group="${e}"]`)||this.form.querySelector(`[data-required-legal="${e}"]`);if(r){let i=r.querySelector("input, select, textarea");i&&i.focus();return}let n=this.form.querySelector(`[name="${e}"]`);n&&n.focus()}getFlowType(){let t=this.form.querySelector('[data-required-group="flow-type"]');return t?t.querySelector('input[type="radio"]:checked')?.value??null:(d("getFlowType",'No [data-required-group="flow-type"] element found'),null)}applyFlowConditions(){let t=this.getFlowType();if(!t)return;let e=_[t]||[];e.length===0&&d("flowConditions",`No FLOW_CONDITIONS entry for flow type: "${t}"`),this.form.querySelectorAll("[data-conditional]").forEach(n=>{let i=n.dataset.conditional;if(!i)return;let o=e.includes(i),s=n.querySelectorAll("input, select, textarea");if(o)n.style.display="",s.forEach(u=>{u.disabled=!1,this.originalRequired.get(u)&&u.setAttribute("required","true")});else{n.style.display="none",s.forEach(a=>{a.disabled=!0,a.removeAttribute("required"),a instanceof HTMLInputElement?a.type==="checkbox"||a.type==="radio"?a.checked=!1:a.value="":a instanceof HTMLSelectElement?a.selectedIndex=0:a instanceof HTMLTextAreaElement&&(a.value="");let c=a.closest("[data-field-key]");if(!c)return;let m=c.dataset.fieldKey;if(!m)return;let f=this.fieldState.get(m);f&&(f.required=!1,f.valid=!0,f.value="",this.fieldState.set(m,f))});let u=n.dataset.fieldKey;if(u){let a=this.fieldState.get(u);a&&(a.required=!1,a.valid=!0,a.value="",this.fieldState.set(u,a))}this.clearErrorsInBlock(n)}}),this.updateValidityForStep(this.currentStepIndex+1)}cacheOriginalRequiredState(){this.form.querySelectorAll("input, select, textarea").forEach(e=>{let r=e.hasAttribute("required");this.originalRequired.set(e,r)})}clearErrorsInBlock(t){t.querySelectorAll(".field-error").forEach(e=>e.remove()),t.querySelectorAll(".has-error").forEach(e=>e.classList.remove("has-error"))}initializeFieldState(){this.form.querySelectorAll("[data-field-key]").forEach(e=>{let r=e.dataset.fieldKey;if(!r)return;let n=e.closest("[data-msf='step']"),i=n?Number(n.dataset.step):this.currentStepIndex+1;n||d("initFieldState",`Field "${r}" is not inside a [data-msf="step"] element \u2014 defaulting to step ${i}`),this.fieldState.set(r,{"field-name":r,value:"",required:!1,valid:!0,"step-number":i})})}updateFieldState(t){let e=this.form.querySelector(`[data-field-key="${t}"]`);if(!e){d("updateFieldState",`No element found for field key: "${t}"`);return}let r="",n=!1;if(e.hasAttribute("data-group")){let u=Array.from(e.querySelectorAll("input[type='radio'], input[type='checkbox']")).filter(a=>!a.disabled);if(n=e.hasAttribute("data-required-group"),u.some(a=>a.type==="radio")){let a=u.find(c=>c.checked);a?r=a.closest("label")?.querySelector("span")?.textContent?.trim()??a.value??"":r=""}else r=u.filter(c=>c.checked).map(c=>c.closest("label")?.querySelector("span")?.textContent?.trim()??c.value??"").join(",")}else if(e.hasAttribute("data-required-legal")){let u=e.querySelector("input[type='checkbox']");u&&!u.disabled&&(n=!0,r=u.checked?"true":"false")}else(e instanceof HTMLInputElement||e instanceof HTMLSelectElement||e instanceof HTMLTextAreaElement)&&(n=e.hasAttribute("required")&&!e.disabled,e instanceof HTMLInputElement&&e.type==="checkbox"?r=e.checked?"true":"false":r=e.value.trim());let i=e.closest("[data-msf='step']"),o=i?Number(i.dataset.step):this.currentStepIndex+1,s=this.fieldState.get(t);if(!s){d("updateFieldState",`No state entry for key "${t}" \u2014 was it initialized?`);return}s.value=r,s.required=n,s["step-number"]=o,this.fieldState.set(t,s),this.updateValidityForStep(o)}updateValidityForStep(t){let e=this.steps.findIndex(i=>Number(i.dataset.step)===t);if(e===-1){d("updateValidity",`No step element found with data-step="${t}"`);return}let r=this.validateStep(e);Array.from(this.fieldState.values()).filter(i=>i["step-number"]===t).forEach(i=>{i.valid=!r[i["field-name"]]})}getFormStateJSON(){return Array.from(this.fieldState.values())}updateStepText(t){let e=O[t];if(!e){d("updateStepText",`No STEP_TEXT config for step ${t}`);return}if(e.heading){let r=this.form.querySelector('[data-dynamic-text="heading"]');r?r.textContent=e.heading:d("updateStepText",'Missing [data-dynamic-text="heading"] element')}if(e.subheading){let r=this.form.querySelector('[data-dynamic-text="subheading"]');r?r.textContent=e.subheading:d("updateStepText",'Missing [data-dynamic-text="subheading"] element')}if(e.counter){let r=this.form.querySelector('[data-dynamic-text="counter"]');r?r.textContent=e.counter:d("updateStepText",'Missing [data-dynamic-text="counter"] element')}}syncAllFieldState(){this.fieldState.forEach((t,e)=>{this.updateFieldState(e)})}mirrorFieldStateToDOM(){let t=this.getFormStateJSON(),e=document.getElementById("form-hubspot-book-a-demo");if(!e){p("mirror","HubSpot form #form-hubspot-book-a-demo NOT FOUND in DOM!");return}t.forEach(r=>{let n=e?.querySelector(`[data-mirror="${r["field-name"]}"]`);if(!n){d("mirror",`No mirror element for data-mirror="${r["field-name"]}"`);return}n instanceof HTMLInputElement&&n.disabled||(n instanceof HTMLInputElement?n.type==="checkbox"?n.checked=r.value==="true":n.type==="radio"?n.checked=n.value===r.value:n.value=r.value:n.value=r.value)})}resolveCalendarEntry(){let t=this.fieldState.get("company_type")?.value??"",e=this.fieldState.get("industry")?.value??"";return v.find(r=>r.type==="company_type"&&r.name===t)??v.find(r=>r.type==="industry"&&r.name===e)??null}loadCalendarEmbed(){let t=document.querySelector("[hs-calender-block]");if(!t){p("calendar","No [hs-calender-block] element found in DOM!");return}let e=this.resolveCalendarEntry();if(!e){t.setAttribute("hs-calender-block-active","false"),t.innerHTML="",document.querySelectorAll("[hs-thankyou-block-active]").forEach(M=>M.setAttribute("hs-thankyou-block-active","true"));return}t.setAttribute("hs-calender-block-active","true"),t.innerHTML="",document.querySelectorAll("[hs-thankyou-block-active]").forEach(y=>y.setAttribute("hs-thankyou-block-active","false"));let n=this.fieldState.get("first_name")?.value??"",i=this.fieldState.get("last_name")?.value??"",o=this.fieldState.get("email")?.value??"",s=new URLSearchParams;n&&s.set("firstName",n),i&&s.set("lastName",i),o&&s.set("email",o);let u=e["embed-url"].includes("?")?"&":"?",a=s.toString()?`${e["embed-url"]}${u}${s.toString()}`:e["embed-url"],c=document.createElement("div");c.className="meetings-iframe-container",c.setAttribute("data-src",a),t.appendChild(c);let m="https://static.hsappstatic.net/MeetingsEmbed/ex/MeetingsEmbedCode.js",f=document.querySelector(`script[src="${m}"]`);f&&f.remove();let h=document.createElement("script");h.type="text/javascript",h.src=m,h.addEventListener("error",y=>{p("calendar","HubSpot meetings script FAILED to load:",y)}),t.appendChild(h)}applyStepStyles(t){let e=N[t];if(!e){d("applyStepStyles",`No STEP_STYLES config for step ${t}`);return}e.forEach(({selector:r,property:n,value:i})=>{let o=document.querySelectorAll(r);o.length===0&&d("applyStepStyles",`Selector "${r}" matched 0 elements`),o.forEach(s=>{s.style.setProperty(n,i)})})}setQualificationStatus(){let t=this.fieldState.get("company_type")?.value??"",e=document.getElementById("qualified_unqualified");if(!e){d("qualification","No element found with id 'qualified_unqualified'");return}e.value=t==="Record Label / Music Distributor"?"qualified":"unqualified"}};document.addEventListener("DOMContentLoaded",()=>{let l=document.querySelector('[data-msf="form"]');if(!l){p("boot",'No form element found with [data-msf="form"] \u2014 MultiStepForm NOT initialized');return}let t;try{t=g({root:l})}catch(e){p("boot","intl-tel-input initialization FAILED:",e),t=new Map}try{let e=new E(l,t);window.msf=e}catch(e){p("boot","MultiStepForm constructor THREW:",e)}});})();
1
+ "use strict";
2
+ (() => {
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
10
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
11
+ }) : x)(function(x) {
12
+ if (typeof require !== "undefined") return require.apply(this, arguments);
13
+ throw Error('Dynamic require of "' + x + '" is not supported');
14
+ });
15
+ var __copyProps = (to, from, except, desc) => {
16
+ if (from && typeof from === "object" || typeof from === "function") {
17
+ for (let key of __getOwnPropNames(from))
18
+ if (!__hasOwnProp.call(to, key) && key !== except)
19
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
20
+ }
21
+ return to;
22
+ };
23
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
24
+ // If the importer is in node compatibility mode or this is not an ESM
25
+ // file that has been converted to a CommonJS file using a Babel-
26
+ // compatible transform (i.e. "__esModule" has not been set), then set
27
+ // "default" to the CommonJS "module.exports" for node compatibility.
28
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
29
+ mod
30
+ ));
31
+
32
+ // src/form/utils/initIntlTelInput.ts
33
+ function initIntlTelInput(options = {}) {
34
+ const {
35
+ root = document,
36
+ initialCountry = "us",
37
+ separateDialCode = true,
38
+ countryCodeSelector = 'input[pulse-form-field="country-code"]',
39
+ onInit,
40
+ onError = (msg) => console.warn(`[initIntlTelInput] ${msg}`)
41
+ } = options;
42
+ const instances = /* @__PURE__ */ new Map();
43
+ const intlTelInput = window.intlTelInput;
44
+ if (!intlTelInput) {
45
+ onError(
46
+ 'intlTelInput not found on window. Include the script before calling this function.\ne.g. <script src="https://cdn.jsdelivr.net/npm/intl-tel-input@25/build/js/intlTelInput.min.js"><\/script>'
47
+ );
48
+ return instances;
49
+ }
50
+ const phoneInputs = root.querySelectorAll(
51
+ 'input[type="tel"]'
52
+ );
53
+ phoneInputs.forEach((input) => {
54
+ try {
55
+ const iti = intlTelInput(input, {
56
+ initialCountry,
57
+ separateDialCode,
58
+ strictMode: false,
59
+ // @ts-ignore — runtime CDN import
60
+ loadUtils: () => import(
61
+ // @ts-ignore — runtime CDN import, not a TS module
62
+ "https://cdn.jsdelivr.net/npm/intl-tel-input@25/build/js/utils.js"
63
+ )
64
+ });
65
+ instances.set(input, iti);
66
+ fillCountryCode(iti, countryCodeSelector);
67
+ input.addEventListener("countrychange", () => {
68
+ fillCountryCode(iti, countryCodeSelector);
69
+ });
70
+ onInit?.(input, iti);
71
+ } catch (err) {
72
+ onError(`Failed to init on input inside "${fieldNameOf(input)}"`, err);
73
+ }
74
+ });
75
+ return instances;
76
+ }
77
+ function fillCountryCode(iti, selector) {
78
+ try {
79
+ const countryData = iti.getSelectedCountryData?.();
80
+ if (!countryData?.dialCode) return;
81
+ document.querySelectorAll(selector).forEach((input) => {
82
+ input.value = `+${countryData.dialCode}`;
83
+ });
84
+ } catch {
85
+ }
86
+ }
87
+ function fieldNameOf(input) {
88
+ return input.closest("[pulse-form-block]")?.getAttribute("pulse-field-name") ?? "unknown";
89
+ }
90
+
91
+ // src/form/index.ts
92
+ var IS_STAGING = window.location.host === "influur-staging.webflow.io";
93
+ function dbgWarn(tag, ...args) {
94
+ if (!IS_STAGING) return;
95
+ console.warn(`[MSF:${tag}]`, ...args);
96
+ }
97
+ function dbgError(tag, ...args) {
98
+ if (!IS_STAGING) return;
99
+ console.error(`[MSF:${tag}]`, ...args);
100
+ }
101
+ var STEP_STYLES = {
102
+ 1: [
103
+ { selector: '[data-action="back"]', property: "display", value: "none" },
104
+ { selector: '[pricing-form-element="progress-fill"]', property: "width", value: "50%" },
105
+ { selector: "[data-step-1-terms]", property: "display", value: "block" }
106
+ ],
107
+ 2: [
108
+ { selector: '[data-action="back"]', property: "display", value: "flex" },
109
+ { selector: '[pricing-form-element="progress-fill"]', property: "width", value: "100%" },
110
+ { selector: "[data-step-1-terms]", property: "display", value: "none" }
111
+ ]
112
+ };
113
+ var CALENDAR_ENTRIES = [
114
+ {
115
+ type: "company_type",
116
+ name: "Record Label / Music Distributor",
117
+ "calender-name": "valeria",
118
+ "embed-url": "https://meetings.hubspot.com/valeria-angelini/pulse-valeria-and-alessandra?embed=true"
119
+ },
120
+ {
121
+ type: "industry",
122
+ name: "Financial Services",
123
+ "calender-name": "david",
124
+ "embed-url": "https://meetings.hubspot.com/david-zarate2?embed=true"
125
+ },
126
+ {
127
+ type: "industry",
128
+ name: "Sports",
129
+ "calender-name": "steven",
130
+ "embed-url": "https://meetings.hubspot.com/steven-campos?embed=true"
131
+ },
132
+ {
133
+ type: "industry",
134
+ name: "Beauty",
135
+ "calender-name": "albany",
136
+ "embed-url": "https://meetings.hubspot.com/david-zarate2?embed=true"
137
+ },
138
+ {
139
+ type: "industry",
140
+ name: "Music",
141
+ "calender-name": "steven",
142
+ "embed-url": "https://meetings.hubspot.com/steven-campos?embed=true"
143
+ },
144
+ {
145
+ type: "industry",
146
+ name: "Customer Packaged Goods",
147
+ "calender-name": "david",
148
+ "embed-url": "https://meetings.hubspot.com/david-zarate2?embed=true"
149
+ },
150
+ {
151
+ type: "industry",
152
+ name: "Other",
153
+ "calender-name": "david",
154
+ "embed-url": "https://meetings.hubspot.com/david-zarate2?embed=true"
155
+ }
156
+ ];
157
+ var ERROR_MESSAGES = {
158
+ required: "This field is required",
159
+ email_invalid: "Please enter a valid email address",
160
+ email_company: "Please use your company email address",
161
+ phone_invalid: "Please enter a valid phone number",
162
+ selection_required: "Please select at least one option",
163
+ legal_required: "You must accept this to continue"
164
+ };
165
+ var FLOW_CONDITIONS = {
166
+ "pulse-demo": [
167
+ "pulse-demo-only",
168
+ "common-fields"
169
+ ],
170
+ "white-glove-services": [
171
+ "white-glove-only",
172
+ "common-fields"
173
+ ]
174
+ };
175
+ var STEP_TEXT = {
176
+ 1: {
177
+ heading: "Your info",
178
+ subheading: "Pulse is launching March 2025. Spots for onboarding cohort 1 are limited.",
179
+ counter: "Step 1/2"
180
+ },
181
+ 2: {
182
+ heading: "Personalize",
183
+ subheading: "Help us personalize your demo.",
184
+ counter: "Step 2/2"
185
+ }
186
+ };
187
+ var MultiStepForm = class {
188
+ constructor(form, itiInstances) {
189
+ this.currentStepIndex = 0;
190
+ this.stepHasBeenValidated = false;
191
+ this.originalRequired = /* @__PURE__ */ new WeakMap();
192
+ this.fieldState = /* @__PURE__ */ new Map();
193
+ this.isFormSubmitted = false;
194
+ this.isFormStarted = false;
195
+ this.form = form;
196
+ this.itiInstances = itiInstances;
197
+ this.steps = Array.from(
198
+ form.querySelectorAll('[data-msf="step"]')
199
+ );
200
+ if (this.steps.length === 0) {
201
+ dbgError("init", "No steps found! Check [data-msf='step'] selectors in HTML.");
202
+ }
203
+ this.steps.forEach((step, i) => {
204
+ const stepNum = step.dataset.step;
205
+ if (!stepNum) {
206
+ dbgWarn("init", `Step element at index ${i} is missing data-step attribute`);
207
+ }
208
+ });
209
+ this.bindEvents();
210
+ this.cacheOriginalRequiredState();
211
+ this.initializeFieldState();
212
+ this.showStep(0);
213
+ this.applyFlowConditions();
214
+ this.syncAllFieldState();
215
+ }
216
+ bindEvents() {
217
+ const markStarted = () => {
218
+ if (!this.isFormStarted) {
219
+ this.isFormStarted = true;
220
+ this.startAbandonmentCheck();
221
+ window.posthog?.capture("form_started", {
222
+ fields: this.getFormStateJSON()
223
+ });
224
+ }
225
+ };
226
+ this.form.addEventListener("input", markStarted);
227
+ this.form.addEventListener("change", markStarted);
228
+ this.form.addEventListener("click", (e) => {
229
+ const target = e.target;
230
+ if (!target) return;
231
+ const btn = target.closest("[data-action]");
232
+ if (!btn) return;
233
+ const action = btn.dataset.action;
234
+ if (action === "next") {
235
+ e.preventDefault();
236
+ this.next();
237
+ }
238
+ if (action === "back") {
239
+ e.preventDefault();
240
+ this.back();
241
+ }
242
+ });
243
+ this.form.addEventListener("submit", (e) => {
244
+ e.preventDefault();
245
+ });
246
+ this.form.addEventListener("input", (e) => {
247
+ const target = e.target;
248
+ if (!target) return;
249
+ if (!(target instanceof HTMLInputElement) && !(target instanceof HTMLTextAreaElement) && !(target instanceof HTMLSelectElement)) return;
250
+ this.handleLiveValidation();
251
+ });
252
+ this.itiInstances.forEach((_iti, input) => {
253
+ input.addEventListener("countrychange", () => {
254
+ if (!this.stepHasBeenValidated) return;
255
+ this.handleLiveValidation();
256
+ });
257
+ });
258
+ this.form.addEventListener("change", (e) => {
259
+ const target = e.target;
260
+ if (!target) return;
261
+ if (target instanceof HTMLInputElement && target.type === "radio" && target.name === "flow-type") {
262
+ this.applyFlowConditions();
263
+ }
264
+ });
265
+ this.form.addEventListener("input", (e) => {
266
+ const target = e.target;
267
+ if (!target) return;
268
+ const trackable = target.closest("[data-field-key]");
269
+ if (!trackable) return;
270
+ const key = trackable.dataset.fieldKey;
271
+ if (!key) return;
272
+ this.updateFieldState(key);
273
+ });
274
+ this.form.addEventListener("change", (e) => {
275
+ const target = e.target;
276
+ if (!target) return;
277
+ const trackable = target.closest("[data-field-key]");
278
+ if (!trackable) return;
279
+ const key = trackable.dataset.fieldKey;
280
+ if (!key) return;
281
+ this.updateFieldState(key);
282
+ });
283
+ }
284
+ handleLiveValidation() {
285
+ if (!this.stepHasBeenValidated) return;
286
+ const errors = this.validateStep(this.currentStepIndex);
287
+ this.clearErrors();
288
+ if (Object.keys(errors).length > 0) {
289
+ this.showErrors(errors);
290
+ }
291
+ }
292
+ showStep(index) {
293
+ if (index < 0 || index >= this.steps.length) {
294
+ dbgError("showStep", `Invalid step index: ${index} (total steps: ${this.steps.length})`);
295
+ return;
296
+ }
297
+ this.steps.forEach((step, i) => {
298
+ step.style.display = i === index ? "flex" : "none";
299
+ });
300
+ this.currentStepIndex = index;
301
+ this.stepHasBeenValidated = false;
302
+ this.clearErrors();
303
+ const stepNumber = index + 1;
304
+ this.updateStepText(stepNumber);
305
+ this.applyStepStyles(stepNumber);
306
+ }
307
+ next() {
308
+ this.stepHasBeenValidated = true;
309
+ const errors = this.validateStep(this.currentStepIndex);
310
+ if (Object.keys(errors).length > 0) {
311
+ this.clearErrors();
312
+ this.showErrors(errors);
313
+ this.focusFirstError(errors);
314
+ return;
315
+ }
316
+ this.clearErrors();
317
+ this.stepHasBeenValidated = false;
318
+ const nextIndex = this.currentStepIndex + 1;
319
+ if (nextIndex >= this.steps.length) {
320
+ const currentStep = this.steps[this.currentStepIndex];
321
+ const nextButton = currentStep.querySelector('[data-action="next"]');
322
+ if (nextButton) {
323
+ const actionTextEl = nextButton.querySelector("[data-action-text]");
324
+ if (actionTextEl) {
325
+ actionTextEl.textContent = "Submitting...";
326
+ } else {
327
+ dbgWarn("next", "No [data-action-text] element found inside next button");
328
+ }
329
+ } else {
330
+ dbgWarn("next", "No [data-action='next'] button found in current step");
331
+ }
332
+ this.mirrorFieldStateToDOM();
333
+ this.setQualificationStatus();
334
+ this.loadCalendarEmbed();
335
+ const webflowSubmitBtn = document.getElementById("webflow-form-submit");
336
+ const hubspotSubmitBtn = document.getElementById("hubspot-form-submit");
337
+ if (!webflowSubmitBtn) {
338
+ dbgError("submit", "Missing #webflow-form-submit button in DOM!");
339
+ }
340
+ if (!hubspotSubmitBtn) {
341
+ dbgError("submit", "Missing #hubspot-form-submit button in DOM!");
342
+ }
343
+ if (webflowSubmitBtn && hubspotSubmitBtn) {
344
+ this.setSubmissionType("manual");
345
+ webflowSubmitBtn.click();
346
+ hubspotSubmitBtn.click();
347
+ this.isFormSubmitted = true;
348
+ window.posthog?.capture("form_submitted", {
349
+ fields: this.getFormStateJSON()
350
+ });
351
+ } else {
352
+ dbgError("submit", "One or both submit buttons not found \u2014 form NOT submitted");
353
+ }
354
+ return;
355
+ }
356
+ this.showStep(nextIndex);
357
+ }
358
+ showErrors(errors) {
359
+ Object.entries(errors).forEach(([name, message]) => {
360
+ const groupEl = this.form.querySelector(`[data-required-group="${name}"]`) || this.form.querySelector(`[data-required-legal="${name}"]`);
361
+ if (groupEl) {
362
+ groupEl.classList.add("has-error");
363
+ let errorEl2 = groupEl.querySelector(".field-error");
364
+ if (!errorEl2) {
365
+ errorEl2 = document.createElement("div");
366
+ errorEl2.className = "field-error";
367
+ groupEl.appendChild(errorEl2);
368
+ }
369
+ errorEl2.textContent = ERROR_MESSAGES[message];
370
+ errorEl2.setAttribute("data-error-code", message);
371
+ return;
372
+ }
373
+ const field = this.form.querySelector(`[name="${name}"]`);
374
+ if (!field) {
375
+ dbgWarn("showErrors", `Cannot find field or group for error key: "${name}"`);
376
+ return;
377
+ }
378
+ field.classList.add("has-error");
379
+ let errorEl = field.parentElement?.querySelector(".field-error");
380
+ if (!errorEl) {
381
+ errorEl = document.createElement("div");
382
+ errorEl.className = "field-error";
383
+ field.parentElement?.appendChild(errorEl);
384
+ }
385
+ errorEl.textContent = ERROR_MESSAGES[message];
386
+ errorEl.setAttribute("data-error-code", message);
387
+ });
388
+ }
389
+ clearErrors() {
390
+ const errorEls = this.form.querySelectorAll(".field-error");
391
+ const hasErrorEls = this.form.querySelectorAll(".has-error");
392
+ errorEls.forEach((el) => el.remove());
393
+ hasErrorEls.forEach(
394
+ (el) => el.classList.remove("has-error")
395
+ );
396
+ }
397
+ back() {
398
+ const prevIndex = this.currentStepIndex - 1;
399
+ if (prevIndex < 0) {
400
+ return;
401
+ }
402
+ this.showStep(prevIndex);
403
+ }
404
+ getFieldsForStep(index) {
405
+ const step = this.steps[index];
406
+ if (!step) {
407
+ dbgError("getFieldsForStep", `Step at index ${index} does not exist`);
408
+ return [];
409
+ }
410
+ const fields = Array.from(
411
+ step.querySelectorAll(
412
+ "input, select, textarea"
413
+ )
414
+ );
415
+ return fields;
416
+ }
417
+ validateStep(index) {
418
+ const errors = {};
419
+ const fields = this.getFieldsForStep(index);
420
+ fields.forEach((field) => {
421
+ const name = field.name;
422
+ if (!name) {
423
+ return;
424
+ }
425
+ if (field.type === "checkbox" || field.type === "radio") return;
426
+ const value = field.value.trim();
427
+ const isRequired = field.hasAttribute("required");
428
+ if (isRequired && !value) {
429
+ errors[name] = "required";
430
+ return;
431
+ }
432
+ if (field.type === "email" && value) {
433
+ if (!this.isValidEmailFormat(value)) {
434
+ errors[name] = "email_invalid";
435
+ return;
436
+ }
437
+ if (!this.isCompanyEmail(value)) {
438
+ errors[name] = "email_company";
439
+ return;
440
+ }
441
+ }
442
+ if (field.type === "tel" && value) {
443
+ const phoneError = this.validatePhoneField(field);
444
+ if (phoneError) {
445
+ errors[name] = "phone_invalid";
446
+ return;
447
+ }
448
+ }
449
+ });
450
+ const selectionGroupErrors = this.validateRequiredSelectionGroups(index);
451
+ const legalErrors = this.validateLegalGroups(index);
452
+ const allErrors = {
453
+ ...errors,
454
+ ...selectionGroupErrors,
455
+ ...legalErrors
456
+ };
457
+ return allErrors;
458
+ }
459
+ validateRequiredSelectionGroups(index) {
460
+ const step = this.steps[index];
461
+ const errors = {};
462
+ const groups = step.querySelectorAll("[data-required-group]");
463
+ groups.forEach((groupEl) => {
464
+ const groupName = groupEl.dataset.requiredGroup;
465
+ if (!groupName) return;
466
+ const inputs = Array.from(
467
+ groupEl.querySelectorAll(
468
+ 'input[type="checkbox"], input[type="radio"]'
469
+ )
470
+ );
471
+ const enabledInputs = inputs.filter((input) => !input.disabled);
472
+ if (enabledInputs.length === 0) {
473
+ return;
474
+ }
475
+ const isChecked = enabledInputs.some((input) => input.checked);
476
+ if (!isChecked) {
477
+ errors[groupName] = "selection_required";
478
+ }
479
+ });
480
+ return errors;
481
+ }
482
+ validateLegalGroups(index) {
483
+ const step = this.steps[index];
484
+ const errors = {};
485
+ const legalGroups = step.querySelectorAll("[data-required-legal]");
486
+ legalGroups.forEach((groupEl) => {
487
+ const groupName = groupEl.dataset.requiredLegal;
488
+ if (!groupName) return;
489
+ const checkbox = groupEl.querySelector(
490
+ 'input[type="checkbox"]'
491
+ );
492
+ if (!checkbox || checkbox.disabled) {
493
+ return;
494
+ }
495
+ if (!checkbox.checked) {
496
+ errors[groupName] = "legal_required";
497
+ }
498
+ });
499
+ return errors;
500
+ }
501
+ startAbandonmentCheck() {
502
+ setTimeout(() => {
503
+ if (this.isFormSubmitted) return;
504
+ const emailField = this.getFormStateJSON().find(
505
+ (f) => f["field-name"] === "email"
506
+ );
507
+ const firstNameField = this.getFormStateJSON().find(
508
+ (f) => f["field-name"] === "first_name"
509
+ );
510
+ const lastNameField = this.getFormStateJSON().find(
511
+ (f) => f["field-name"] === "last_name"
512
+ );
513
+ const hasValidEmail = emailField && emailField.value && this.isValidEmailFormat(emailField.value);
514
+ const hasFirstName = firstNameField && firstNameField.value.trim().length > 0;
515
+ const hasLastName = lastNameField && lastNameField.value.trim().length > 0;
516
+ if (hasValidEmail && hasFirstName && hasLastName) {
517
+ console.warn(
518
+ "[MSF] User is likely to skip the form submission \u2014 losing a lead. Email:",
519
+ emailField.value
520
+ );
521
+ this.mirrorFieldStateToDOM();
522
+ const hubspotSubmitBtn = document.getElementById("hubspot-form-submit");
523
+ if (hubspotSubmitBtn) {
524
+ this.setSubmissionType("automated");
525
+ window.posthog?.capture("form_abandoned", {
526
+ fields: this.getFormStateJSON()
527
+ });
528
+ hubspotSubmitBtn.click();
529
+ } else {
530
+ dbgError("abandonCheck", "Missing #hubspot-form-submit button in DOM!");
531
+ }
532
+ }
533
+ }, 30 * 60 * 1e3);
534
+ }
535
+ setSubmissionType(type) {
536
+ const el = document.getElementById("submission_type");
537
+ if (el) {
538
+ el.value = type;
539
+ } else {
540
+ dbgWarn("setSubmissionType", "No element found with id 'submission_type'");
541
+ }
542
+ }
543
+ isValidEmailFormat(email) {
544
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
545
+ return emailRegex.test(email);
546
+ }
547
+ isCompanyEmail(email) {
548
+ const publicDomains = [
549
+ "gmail.com",
550
+ "yahoo.com",
551
+ "hotmail.com",
552
+ "outlook.com",
553
+ "icloud.com",
554
+ "aol.com"
555
+ ];
556
+ const domain = email.split("@")[1]?.toLowerCase();
557
+ if (!domain) return false;
558
+ return !publicDomains.includes(domain);
559
+ }
560
+ validatePhoneField(field) {
561
+ const iti = this.itiInstances.get(field);
562
+ if (!iti) {
563
+ dbgWarn("phoneValidation", `No ITI instance found for field "${field.name}" \u2014 skipping phone validation`);
564
+ return null;
565
+ }
566
+ const value = field.value.trim();
567
+ if (!value) return null;
568
+ if (!iti.isValidNumber()) {
569
+ return "phone_invalid";
570
+ }
571
+ return null;
572
+ }
573
+ focusFirstError(errors) {
574
+ const firstErrorName = Object.keys(errors)[0];
575
+ if (!firstErrorName) return;
576
+ const groupEl = this.form.querySelector(
577
+ `[data-required-group="${firstErrorName}"]`
578
+ ) || this.form.querySelector(
579
+ `[data-required-legal="${firstErrorName}"]`
580
+ );
581
+ if (groupEl) {
582
+ const firstInput = groupEl.querySelector("input, select, textarea");
583
+ if (firstInput) {
584
+ firstInput.focus();
585
+ }
586
+ return;
587
+ }
588
+ const field = this.form.querySelector(`[name="${firstErrorName}"]`);
589
+ if (field) {
590
+ field.focus();
591
+ }
592
+ }
593
+ getFlowType() {
594
+ const flowWrapper = this.form.querySelector(
595
+ '[data-required-group="flow-type"]'
596
+ );
597
+ if (!flowWrapper) {
598
+ dbgWarn("getFlowType", 'No [data-required-group="flow-type"] element found');
599
+ return null;
600
+ }
601
+ const checked = flowWrapper.querySelector(
602
+ 'input[type="radio"]:checked'
603
+ );
604
+ const value = checked?.value ?? null;
605
+ return value;
606
+ }
607
+ applyFlowConditions() {
608
+ const flowType = this.getFlowType();
609
+ if (!flowType) {
610
+ return;
611
+ }
612
+ const visibleKeys = FLOW_CONDITIONS[flowType] || [];
613
+ if (visibleKeys.length === 0) {
614
+ dbgWarn("flowConditions", `No FLOW_CONDITIONS entry for flow type: "${flowType}"`);
615
+ }
616
+ const conditionalBlocks = this.form.querySelectorAll(
617
+ "[data-conditional]"
618
+ );
619
+ conditionalBlocks.forEach((block) => {
620
+ const key = block.dataset.conditional;
621
+ if (!key) return;
622
+ const shouldShow = visibleKeys.includes(key);
623
+ const inputs = block.querySelectorAll("input, select, textarea");
624
+ if (shouldShow) {
625
+ block.style.display = "";
626
+ inputs.forEach((input) => {
627
+ input.disabled = false;
628
+ const wasRequired = this.originalRequired.get(input);
629
+ if (wasRequired) {
630
+ input.setAttribute("required", "true");
631
+ }
632
+ });
633
+ } else {
634
+ block.style.display = "none";
635
+ inputs.forEach((input) => {
636
+ input.disabled = true;
637
+ input.removeAttribute("required");
638
+ if (input instanceof HTMLInputElement) {
639
+ if (input.type === "checkbox" || input.type === "radio") {
640
+ input.checked = false;
641
+ } else {
642
+ input.value = "";
643
+ }
644
+ } else if (input instanceof HTMLSelectElement) {
645
+ input.selectedIndex = 0;
646
+ } else if (input instanceof HTMLTextAreaElement) {
647
+ input.value = "";
648
+ }
649
+ const trackable = input.closest("[data-field-key]");
650
+ if (!trackable) return;
651
+ const fieldKey = trackable.dataset.fieldKey;
652
+ if (!fieldKey) return;
653
+ const state = this.fieldState.get(fieldKey);
654
+ if (!state) return;
655
+ state.required = false;
656
+ state.valid = true;
657
+ state.value = "";
658
+ this.fieldState.set(fieldKey, state);
659
+ });
660
+ const wrapperKey = block.dataset.fieldKey;
661
+ if (wrapperKey) {
662
+ const state = this.fieldState.get(wrapperKey);
663
+ if (state) {
664
+ state.required = false;
665
+ state.valid = true;
666
+ state.value = "";
667
+ this.fieldState.set(wrapperKey, state);
668
+ }
669
+ }
670
+ this.clearErrorsInBlock(block);
671
+ }
672
+ });
673
+ this.updateValidityForStep(this.currentStepIndex + 1);
674
+ }
675
+ cacheOriginalRequiredState() {
676
+ const inputs = this.form.querySelectorAll("input, select, textarea");
677
+ inputs.forEach((input) => {
678
+ const isReq = input.hasAttribute("required");
679
+ this.originalRequired.set(input, isReq);
680
+ });
681
+ }
682
+ clearErrorsInBlock(block) {
683
+ block.querySelectorAll(".field-error").forEach((el) => el.remove());
684
+ block.querySelectorAll(".has-error").forEach(
685
+ (el) => el.classList.remove("has-error")
686
+ );
687
+ }
688
+ initializeFieldState() {
689
+ const trackables = this.form.querySelectorAll(
690
+ "[data-field-key]"
691
+ );
692
+ trackables.forEach((el) => {
693
+ const key = el.dataset.fieldKey;
694
+ if (!key) return;
695
+ const stepWrapper = el.closest("[data-msf='step']");
696
+ const stepNumber = stepWrapper ? Number(stepWrapper.dataset.step) : this.currentStepIndex + 1;
697
+ if (!stepWrapper) {
698
+ dbgWarn("initFieldState", `Field "${key}" is not inside a [data-msf="step"] element \u2014 defaulting to step ${stepNumber}`);
699
+ }
700
+ this.fieldState.set(key, {
701
+ "field-name": key,
702
+ value: "",
703
+ required: false,
704
+ valid: true,
705
+ "step-number": stepNumber
706
+ });
707
+ });
708
+ }
709
+ updateFieldState(key) {
710
+ const element = this.form.querySelector(
711
+ `[data-field-key="${key}"]`
712
+ );
713
+ if (!element) {
714
+ dbgWarn("updateFieldState", `No element found for field key: "${key}"`);
715
+ return;
716
+ }
717
+ let value = "";
718
+ let required = false;
719
+ if (element.hasAttribute("data-group")) {
720
+ const inputs = Array.from(
721
+ element.querySelectorAll(
722
+ "input[type='radio'], input[type='checkbox']"
723
+ )
724
+ ).filter((i) => !i.disabled);
725
+ required = element.hasAttribute("data-required-group");
726
+ if (inputs.some((i) => i.type === "radio")) {
727
+ const checked = inputs.find((i) => i.checked);
728
+ if (checked) {
729
+ const span = checked.closest("label")?.querySelector("span");
730
+ value = span?.textContent?.trim() ?? checked.value ?? "";
731
+ } else {
732
+ value = "";
733
+ }
734
+ } else {
735
+ const checkedValues = inputs.filter((i) => i.checked).map((i) => {
736
+ const span = i.closest("label")?.querySelector("span");
737
+ return span?.textContent?.trim() ?? i.value ?? "";
738
+ });
739
+ value = checkedValues.join(",");
740
+ }
741
+ } else if (element.hasAttribute("data-required-legal")) {
742
+ const checkbox = element.querySelector(
743
+ "input[type='checkbox']"
744
+ );
745
+ if (checkbox && !checkbox.disabled) {
746
+ required = true;
747
+ value = checkbox.checked ? "true" : "false";
748
+ }
749
+ } else if (element instanceof HTMLInputElement || element instanceof HTMLSelectElement || element instanceof HTMLTextAreaElement) {
750
+ required = element.hasAttribute("required") && !element.disabled;
751
+ if (element instanceof HTMLInputElement && element.type === "checkbox") {
752
+ value = element.checked ? "true" : "false";
753
+ } else {
754
+ value = element.value.trim();
755
+ }
756
+ }
757
+ const stepWrapper = element.closest("[data-msf='step']");
758
+ const stepNumber = stepWrapper ? Number(stepWrapper.dataset.step) : this.currentStepIndex + 1;
759
+ const state = this.fieldState.get(key);
760
+ if (!state) {
761
+ dbgWarn("updateFieldState", `No state entry for key "${key}" \u2014 was it initialized?`);
762
+ return;
763
+ }
764
+ state.value = value;
765
+ state.required = required;
766
+ state["step-number"] = stepNumber;
767
+ this.fieldState.set(key, state);
768
+ this.updateValidityForStep(stepNumber);
769
+ }
770
+ updateValidityForStep(stepNumber) {
771
+ const stepIndex = this.steps.findIndex(
772
+ (step) => Number(step.dataset.step) === stepNumber
773
+ );
774
+ if (stepIndex === -1) {
775
+ dbgWarn("updateValidity", `No step element found with data-step="${stepNumber}"`);
776
+ return;
777
+ }
778
+ const errors = this.validateStep(stepIndex);
779
+ const keysInStep = Array.from(this.fieldState.values()).filter(
780
+ (f) => f["step-number"] === stepNumber
781
+ );
782
+ keysInStep.forEach((field) => {
783
+ field.valid = !errors[field["field-name"]];
784
+ });
785
+ }
786
+ getFormStateJSON() {
787
+ return Array.from(this.fieldState.values());
788
+ }
789
+ updateStepText(stepNumber) {
790
+ const config = STEP_TEXT[stepNumber];
791
+ if (!config) {
792
+ dbgWarn("updateStepText", `No STEP_TEXT config for step ${stepNumber}`);
793
+ return;
794
+ }
795
+ if (config.heading) {
796
+ const headingEl = this.form.querySelector(
797
+ '[data-dynamic-text="heading"]'
798
+ );
799
+ if (headingEl) {
800
+ headingEl.textContent = config.heading;
801
+ } else {
802
+ dbgWarn("updateStepText", 'Missing [data-dynamic-text="heading"] element');
803
+ }
804
+ }
805
+ if (config.subheading) {
806
+ const subheadingEl = this.form.querySelector(
807
+ '[data-dynamic-text="subheading"]'
808
+ );
809
+ if (subheadingEl) {
810
+ subheadingEl.textContent = config.subheading;
811
+ } else {
812
+ dbgWarn("updateStepText", 'Missing [data-dynamic-text="subheading"] element');
813
+ }
814
+ }
815
+ if (config.counter) {
816
+ const counterEl = this.form.querySelector(
817
+ '[data-dynamic-text="counter"]'
818
+ );
819
+ if (counterEl) {
820
+ counterEl.textContent = config.counter;
821
+ } else {
822
+ dbgWarn("updateStepText", 'Missing [data-dynamic-text="counter"] element');
823
+ }
824
+ }
825
+ }
826
+ syncAllFieldState() {
827
+ this.fieldState.forEach((_state, key) => {
828
+ this.updateFieldState(key);
829
+ });
830
+ }
831
+ mirrorFieldStateToDOM() {
832
+ const allFields = this.getFormStateJSON();
833
+ const hubspotForm = document.getElementById("form-hubspot-book-a-demo");
834
+ if (!hubspotForm) {
835
+ dbgError("mirror", "HubSpot form #form-hubspot-book-a-demo NOT FOUND in DOM!");
836
+ return;
837
+ }
838
+ allFields.forEach((field) => {
839
+ const mirrorEl = hubspotForm?.querySelector(`[data-mirror="${field["field-name"]}"]`);
840
+ if (!mirrorEl) {
841
+ dbgWarn("mirror", `No mirror element for data-mirror="${field["field-name"]}"`);
842
+ return;
843
+ }
844
+ if (mirrorEl instanceof HTMLInputElement && mirrorEl.disabled) {
845
+ return;
846
+ }
847
+ if (mirrorEl instanceof HTMLInputElement) {
848
+ if (mirrorEl.type === "checkbox") {
849
+ mirrorEl.checked = field.value === "true";
850
+ } else if (mirrorEl.type === "radio") {
851
+ mirrorEl.checked = mirrorEl.value === field.value;
852
+ } else {
853
+ mirrorEl.value = field.value;
854
+ }
855
+ } else {
856
+ mirrorEl.value = field.value;
857
+ }
858
+ });
859
+ }
860
+ resolveCalendarEntry() {
861
+ const companyType = this.fieldState.get("company_type")?.value ?? "";
862
+ const industry = this.fieldState.get("industry")?.value ?? "";
863
+ return CALENDAR_ENTRIES.find(
864
+ (entry) => entry.type === "company_type" && entry.name === companyType
865
+ ) ?? CALENDAR_ENTRIES.find(
866
+ (entry) => entry.type === "industry" && entry.name === industry
867
+ ) ?? null;
868
+ }
869
+ loadCalendarEmbed() {
870
+ const container = document.querySelector("[hs-calender-block]");
871
+ if (!container) {
872
+ dbgError("calendar", "No [hs-calender-block] element found in DOM!");
873
+ return;
874
+ }
875
+ const entry = this.resolveCalendarEntry();
876
+ if (!entry) {
877
+ container.setAttribute("hs-calender-block-active", "false");
878
+ container.innerHTML = "";
879
+ const tyEls2 = document.querySelectorAll("[hs-thankyou-block-active]");
880
+ tyEls2.forEach((el) => el.setAttribute("hs-thankyou-block-active", "true"));
881
+ return;
882
+ }
883
+ container.setAttribute("hs-calender-block-active", "true");
884
+ container.innerHTML = "";
885
+ const tyEls = document.querySelectorAll("[hs-thankyou-block-active]");
886
+ tyEls.forEach((el) => el.setAttribute("hs-thankyou-block-active", "false"));
887
+ const firstName = this.fieldState.get("first_name")?.value ?? "";
888
+ const lastName = this.fieldState.get("last_name")?.value ?? "";
889
+ const email = this.fieldState.get("email")?.value ?? "";
890
+ const prefillParams = new URLSearchParams();
891
+ if (firstName) prefillParams.set("firstName", firstName);
892
+ if (lastName) prefillParams.set("lastName", lastName);
893
+ if (email) prefillParams.set("email", email);
894
+ const separator = entry["embed-url"].includes("?") ? "&" : "?";
895
+ const embedUrl = prefillParams.toString() ? `${entry["embed-url"]}${separator}${prefillParams.toString()}` : entry["embed-url"];
896
+ const meetingsDiv = document.createElement("div");
897
+ meetingsDiv.className = "meetings-iframe-container";
898
+ meetingsDiv.setAttribute("data-src", embedUrl);
899
+ container.appendChild(meetingsDiv);
900
+ const scriptSrc = "https://static.hsappstatic.net/MeetingsEmbed/ex/MeetingsEmbedCode.js";
901
+ const existingScript = document.querySelector(
902
+ `script[src="${scriptSrc}"]`
903
+ );
904
+ if (existingScript) {
905
+ existingScript.remove();
906
+ }
907
+ const script = document.createElement("script");
908
+ script.type = "text/javascript";
909
+ script.src = scriptSrc;
910
+ script.addEventListener("error", (err) => {
911
+ dbgError("calendar", "HubSpot meetings script FAILED to load:", err);
912
+ });
913
+ container.appendChild(script);
914
+ }
915
+ applyStepStyles(stepNumber) {
916
+ const styles = STEP_STYLES[stepNumber];
917
+ if (!styles) {
918
+ dbgWarn("applyStepStyles", `No STEP_STYLES config for step ${stepNumber}`);
919
+ return;
920
+ }
921
+ styles.forEach(({ selector, property, value }) => {
922
+ const els = document.querySelectorAll(selector);
923
+ if (els.length === 0) {
924
+ dbgWarn("applyStepStyles", `Selector "${selector}" matched 0 elements`);
925
+ }
926
+ els.forEach((el) => {
927
+ el.style.setProperty(property, value);
928
+ });
929
+ });
930
+ }
931
+ setQualificationStatus() {
932
+ const companyType = this.fieldState.get("company_type")?.value ?? "";
933
+ const el = document.getElementById("qualified_unqualified");
934
+ if (!el) {
935
+ dbgWarn("qualification", "No element found with id 'qualified_unqualified'");
936
+ return;
937
+ }
938
+ el.value = companyType === "Record Label / Music Distributor" ? "qualified" : "unqualified";
939
+ }
940
+ };
941
+ document.addEventListener("DOMContentLoaded", () => {
942
+ const form = document.querySelector('[data-msf="form"]');
943
+ if (!form) {
944
+ dbgError("boot", 'No form element found with [data-msf="form"] \u2014 MultiStepForm NOT initialized');
945
+ return;
946
+ }
947
+ let itiInstances;
948
+ try {
949
+ itiInstances = initIntlTelInput({ root: form });
950
+ } catch (err) {
951
+ dbgError("boot", "intl-tel-input initialization FAILED:", err);
952
+ itiInstances = /* @__PURE__ */ new Map();
953
+ }
954
+ try {
955
+ const msf = new MultiStepForm(form, itiInstances);
956
+ window.msf = msf;
957
+ } catch (err) {
958
+ dbgError("boot", "MultiStepForm constructor THREW:", err);
959
+ }
960
+ });
961
+ })();
962
+ //# sourceMappingURL=index.js.map