@authhero/widget 0.40.2 → 0.41.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.
@@ -0,0 +1 @@
1
+ import{r as t,c as e,g as i,h as o}from"./p-FUW5zvoZ.js";import{s as r}from"./p-Che3Wd7J.js";function n(t){const e=t.match(/^#([0-9a-f]{3})$/i)||t.match(/^#([0-9a-f]{6})$/i);if(!e)return null;let i=e[1];3===i.length&&(i=i[0]+i[0]+i[1]+i[1]+i[2]+i[2]);const o=parseInt(i,16);return[o>>16&255,o>>8&255,255&o]}function a(t){const e=n(t);if(!e)return NaN;const[i,o,r]=e.map((t=>{const e=t/255;return e<=.04045?e/12.92:Math.pow((e+.055)/1.055,2.4)}));return.2126*i+.7152*o+.0722*r}function s(t,e){const i=a(t),o=a(e);return isNaN(i)||isNaN(o)?NaN:(Math.max(i,o)+.05)/(Math.min(i,o)+.05)}function c(t,e="light"){const i=s(t,"#000000"),o=s(t,"#ffffff");return"light"===e?i>1.35*o?"#000000":"#ffffff":1.35*i>o?"#000000":"#ffffff"}function l(t,e){const i=n(t);if(!i)return t;const[o,r,a]=i,s=t=>Math.max(0,Math.round(t*(1-e))).toString(16).padStart(2,"0");return`#${s(o)}${s(r)}${s(a)}`}function h(t,e){const i=n(t);if(!i)return t;const[o,r,a]=i,s=t=>Math.min(255,Math.round(t+(255-t)*e)).toString(16).padStart(2,"0");return`#${s(o)}${s(r)}${s(a)}`}function d(t,e,i=4.5){if(s(t,e)>=i)return t;const o=a(e)>.5;let r=t;for(let n=1;n<=10;n++)if(r=o?l(t,.1*n):h(t,.1*n),s(r,e)>=i)return r;return o?"#000000":"#ffffff"}function p(t,e){if(void 0!==e)return`${e}px`;switch(t){case"pill":return"9999px";case"rounded":return"8px";case"sharp":return"0";default:return}}function f(t){if(!t)return{};const e={};if(t.colors?.primary&&(e["--ah-color-primary"]=t.colors.primary),t.colors?.page_background){const i=t.colors.page_background;"solid"===i.type&&i.start?e["--ah-page-bg"]=i.start:"gradient"===i.type&&i.start&&i.end&&(e["--ah-page-bg"]=`linear-gradient(${i.angle_deg??180}deg, ${i.start}, ${i.end})`)}return t.logo_url&&(e["--ah-logo-url"]=`url(${t.logo_url})`),t.font?.url&&(e["--ah-font-url"]=t.font.url),e}function u(t){if(!t)return{};const e={};if(t.borders){const i=t.borders;void 0!==i.widget_corner_radius&&(e["--ah-widget-radius"]=`${i.widget_corner_radius}px`),void 0!==i.widget_border_weight&&(e["--ah-widget-border-width"]=`${i.widget_border_weight}px`),!1===i.show_widget_shadow&&(e["--ah-widget-shadow"]="none");const o=p(i.buttons_style,i.button_border_radius);o&&(e["--ah-btn-radius"]=o),void 0!==i.button_border_weight&&(e["--ah-btn-border-width"]=`${i.button_border_weight}px`);const r=p(i.inputs_style,i.input_border_radius);r&&(e["--ah-input-radius"]=r),void 0!==i.input_border_weight&&(e["--ah-input-border-width"]=`${i.input_border_weight}px`)}if(t.colors){const i=t.colors;if(i.primary_button)if(e["--ah-color-primary"]=i.primary_button,i.primary_button_label)e["--ah-color-text-on-primary"]=i.primary_button_label;else{e["--ah-color-text-on-primary"]=c(i.primary_button,"light");const t=c(i.primary_button,"dark");t!==e["--ah-color-text-on-primary"]&&(e["--ah-color-text-on-primary-dark"]=t)}else i.primary_button_label&&(e["--ah-color-text-on-primary"]=i.primary_button_label);i.secondary_button_border&&(e["--ah-btn-secondary-border"]=i.secondary_button_border),i.secondary_button_label&&(e["--ah-btn-secondary-text"]=i.secondary_button_label),i.body_text&&(e["--ah-color-text"]=i.body_text),i.header&&(e["--ah-color-text-header"]=i.header),i.input_labels_placeholders&&(e["--ah-color-text-label"]=i.input_labels_placeholders,e["--ah-color-text-muted"]=i.input_labels_placeholders),i.input_filled_text&&(e["--ah-color-input-text"]=i.input_filled_text),i.widget_background&&(e["--ah-color-bg"]=i.widget_background),i.input_background&&(e["--ah-color-input-bg"]=i.input_background),i.widget_border&&(e["--ah-widget-border-color"]=i.widget_border),i.input_border&&(e["--ah-color-border"]=i.input_border),i.links_focused_components&&(e["--ah-color-link"]=d(i.links_focused_components,i.widget_background||"#ffffff")),i.base_focus_color&&(e["--ah-color-focus-ring"]=i.base_focus_color),i.base_hover_color&&(e["--ah-color-primary-hover"]=i.base_hover_color),i.error&&(e["--ah-color-error"]=i.error),i.success&&(e["--ah-color-success"]=i.success),i.icons&&(e["--ah-color-icon"]=i.icons);const o=i.widget_background||"#ffffff",r=i.input_background||o,n=e["--ah-color-border"]||i.input_border||"#c9cace",a=s(n,o),l=s(n,r);Math.min(a,l)<3&&(e["--ah-color-border"]=d(n,a<l?o:r,3))}if(t.fonts){const i=t.fonts,o=i.reference_text_size||16,r=t=>t>=50?Math.round(t/100*o):t;i.font_url&&(e["--ah-font-url"]=i.font_url),i.reference_text_size&&(e["--ah-font-size-base"]=`${i.reference_text_size}px`),i.title?.size&&(e["--ah-font-size-title"]=`${r(i.title.size)}px`),i.subtitle?.size&&(e["--ah-font-size-subtitle"]=`${r(i.subtitle.size)}px`),i.body_text?.size&&(e["--ah-font-size-body"]=`${r(i.body_text.size)}px`),i.input_labels?.size&&(e["--ah-font-size-label"]=`${r(i.input_labels.size)}px`),i.buttons_text?.size&&(e["--ah-font-size-btn"]=`${r(i.buttons_text.size)}px`),i.links?.size&&(e["--ah-font-size-link"]=`${r(i.links.size)}px`),"underlined"===i.links_style&&(e["--ah-link-decoration"]="underline"),void 0!==i.title?.bold&&(e["--ah-font-weight-title"]=i.title.bold?"700":"400"),void 0!==i.subtitle?.bold&&(e["--ah-font-weight-subtitle"]=i.subtitle.bold?"700":"400"),void 0!==i.body_text?.bold&&(e["--ah-font-weight-body"]=i.body_text.bold?"700":"400"),void 0!==i.input_labels?.bold&&(e["--ah-font-weight-label"]=i.input_labels.bold?"700":"400"),void 0!==i.buttons_text?.bold&&(e["--ah-font-weight-btn"]=i.buttons_text.bold?"600":"400"),void 0!==i.links?.bold&&(e["--ah-font-weight-link"]=i.links.bold?"700":"400")}if(t.widget){const i=t.widget;if(i.header_text_alignment&&(e["--ah-title-align"]=i.header_text_alignment),i.logo_height&&(e["--ah-logo-height"]=`${i.logo_height}px`),i.logo_position){const t={center:"center",left:"flex-start",right:"flex-end"};"none"===i.logo_position?e["--ah-logo-display"]="none":e["--ah-logo-align"]=t[i.logo_position]??"center"}i.social_buttons_layout&&("top"===i.social_buttons_layout?(e["--ah-social-order"]="0",e["--ah-divider-order"]="1",e["--ah-fields-order"]="2"):(e["--ah-social-order"]="2",e["--ah-divider-order"]="1",e["--ah-fields-order"]="0"))}if(t.page_background){const i=t.page_background;i.background_color&&(e["--ah-page-bg"]=i.background_color),i.background_image_url&&(e["--ah-page-bg-image"]=`url(${i.background_image_url})`)}return e}const g={br:[],em:[],i:[],strong:[],b:[],u:[],span:["class"],a:["href","class"]};function m(t){if(!t)return"";if(!t.includes("<"))return t;let e=t;e=e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;");for(const[t,i]of Object.entries(g)){if("br"===t){e=e.replace(/&lt;br\s*\/?&gt;/gi,"<br>");continue}const o=new RegExp(`&lt;${t}((?:\\s+[a-z-]+(?:=&quot;[^&]*&quot;|=&#39;[^&]*&#39;)?)*)\\s*&gt;`,"gi");e=e.replace(o,((e,o)=>{const r=[];if(o){const t=o.replace(/&quot;/g,'"').replace(/&#39;/g,"'").replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">"),e=/([a-z-]+)=["']([^"']*)["']/gi;let n;for(;null!==(n=e.exec(t));){const[,t,e]=n;t&&i.includes(t.toLowerCase())&&("href"===t.toLowerCase()?b(e||"")&&r.push(`${t}="${x(e||"")}"`):r.push(`${t}="${x(e||"")}"`))}}"a"===t&&(r.push('target="_blank"'),r.push('rel="noopener noreferrer"'));const n=r.length?" "+r.join(" "):"";return`<${t}${n}>`}));const r=new RegExp(`&lt;/${t}&gt;`,"gi");e=e.replace(r,`</${t}>`)}return e}function b(t){if(!t)return!1;if(t.startsWith("/")||t.startsWith("#")||t.startsWith("?"))return!0;try{const e=new URL(t,"https://example.com");return"http:"===e.protocol||"https:"===e.protocol}catch{return!1}}function x(t){return t.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}const v=new Set(["TEXT","EMAIL","CODE","PASSWORD","NUMBER","URL"]),w=new Set(["TEXT","EMAIL","CODE","PASSWORD","NUMBER","TEL","URL","DATE","BOOLEAN","LEGAL","COUNTRY","DROPDOWN","CHOICE"]),y=class{constructor(i){t(this,i),this.formSubmit=e(this,"formSubmit"),this.buttonClick=e(this,"buttonClick"),this.linkClick=e(this,"linkClick"),this.navigate=e(this,"navigate"),this.flowComplete=e(this,"flowComplete"),this.flowError=e(this,"flowError"),this.screenChange=e(this,"screenChange")}get el(){return i(this)}screen;apiUrl;baseUrl;state;screenId;watchScreenId(){this.updateDataScreenAttribute()}authParams;statePersistence="memory";storageKey="authhero_widget";branding;theme;loading=!1;autoSubmit=!1;autoNavigate;locale;_screen;_authParams;_branding;_theme;formData={};listFilter="";conditionalMediationAbort;loadedFontUrl;formSubmit;buttonClick;linkClick;navigate;flowComplete;flowError;screenChange;watchScreen(t){if(this.conditionalMediationAbort?.abort(),this.conditionalMediationAbort=void 0,"string"==typeof t)try{this._screen=JSON.parse(t)}catch{console.error("Failed to parse screen JSON")}else this._screen=t;this._screen&&(this.formData={},this.listFilter="",this.initFormDataFromDefaults(this._screen),this.screenChange.emit(this._screen),this.updateDataScreenAttribute())}initFormDataFromDefaults(t){const e={};for(const i of t.components||[]){if(!("config"in i)||!i.config)continue;if(!("default_value"in i.config))continue;const t=i.config.default_value;"string"==typeof t&&""!==t?e[i.id]=t:"boolean"==typeof t&&(e[i.id]=t?"true":"false")}Object.keys(e).length>0&&(this.formData={...e,...this.formData})}updateDataScreenAttribute(){const t=this._screen?.name||this.screenId;t?this.el.setAttribute("data-screen",t):this.el.removeAttribute("data-screen");const e=this.el.closest("[data-authhero-widget-container]");e&&(t?e.setAttribute("data-screen",t):e.removeAttribute("data-screen"))}watchBranding(t){if("string"==typeof t)try{this._branding=JSON.parse(t)}catch{console.error("Failed to parse branding JSON")}else this._branding=t;this.applyThemeStyles()}watchTheme(t){if("string"==typeof t)try{this._theme=JSON.parse(t)}catch{console.error("Failed to parse theme JSON")}else this._theme=t;this.applyThemeStyles()}watchAuthParams(t){if("string"==typeof t)try{this._authParams=JSON.parse(t)}catch{console.error("Failed to parse authParams JSON")}else this._authParams=t}applyThemeStyles(){const t=(e=this._theme,{...f(this._branding),...u(e)});var e;!function(t,e){Object.entries(e).forEach((([e,i])=>{t.style.setProperty(e,i)}))}(this.el,t),this.loadCustomFont()}loadCustomFont(){if("undefined"==typeof document)return;const t=this._theme?.fonts?.font_url||this._branding?.font?.url;if(t===this.loadedFontUrl)return;for(const t of Array.from(document.head.querySelectorAll("link[data-authhero-font]")))t.remove();if(this.loadedFontUrl=void 0,!t)return;const e=document.createElement("link");e.rel="stylesheet",e.href=t,e.setAttribute("data-authhero-font",t),document.head.appendChild(e),this.loadedFontUrl=t}focusFirstInput(){requestAnimationFrame((()=>{const t=this.el.shadowRoot;if(!t)return;const e=t.querySelectorAll("authhero-node");for(const t of Array.from(e)){const e=t.shadowRoot;if(e){const t=e.querySelector('input:not([type="hidden"]):not([type="checkbox"]):not([disabled]), textarea:not([disabled])');if(t)return void t.focus()}}}))}pendingRenderResolvers=[];activeSwaps=0;updateReadyAttribute(){this.el.toggleAttribute("data-ready",!this.loading&&0===this.activeSwaps)}componentDidRender(){if(this.updateReadyAttribute(),0===this.pendingRenderResolvers.length)return;const t=this.pendingRenderResolvers;this.pendingRenderResolvers=[],t.forEach((t=>t()))}nextRender(){return new Promise((t=>{let e=!1;const i=()=>{e||(e=!0,t())};this.pendingRenderResolvers.push(i),requestAnimationFrame((()=>requestAnimationFrame(i)))}))}async swapScreen(t){const e=this.el.shadowRoot?.querySelector(".widget-container"),i="function"==typeof window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches;if(e&&"function"==typeof e.animate&&!i){this.activeSwaps++;try{await this.animateSwap(e,t)}finally{this.activeSwaps--,this.updateReadyAttribute()}}else t()}async animateSwap(t,e){const i=t.getBoundingClientRect().height;t.style.height=`${i}px`,t.style.overflow="hidden",e(),await this.nextRender();const o=()=>{t.style.height="",t.style.overflow=""};t.style.height="auto";const r=t.getBoundingClientRect().height;if(t.style.height=`${i}px`,t.getBoundingClientRect(),Math.abs(r-i)<1)return void o();const n=t.animate([{height:`${i}px`},{height:`${r}px`}],{duration:520,easing:"cubic-bezier(0.22, 1, 0.36, 1)"});try{await n.finished}catch{}finally{o()}}get shouldAutoNavigate(){return this.autoNavigate??this.autoSubmit}buildUrl(t){return this.baseUrl?new URL(t,this.baseUrl).toString():t}loadPersistedState(){if("url"===this.statePersistence){const t=new URL(window.location.href).searchParams.get("state");t&&!this.state&&(this.state=t)}else if("session"===this.statePersistence)try{const t=sessionStorage.getItem(`${this.storageKey}_state`);t&&!this.state&&(this.state=t);const e=sessionStorage.getItem(`${this.storageKey}_screenId`);e&&!this.screenId&&(this.screenId=e)}catch{}}persistState(){if("url"===this.statePersistence){const t=new URL(window.location.href);this.state&&t.searchParams.set("state",this.state),this.screenId&&t.searchParams.set("screen",this.screenId),window.history.replaceState({},"",t.toString())}else if("session"===this.statePersistence)try{this.state&&sessionStorage.setItem(`${this.storageKey}_state`,this.state),this.screenId&&sessionStorage.setItem(`${this.storageKey}_screenId`,this.screenId)}catch{}}handlePopState=t=>{if(!this.apiUrl)return;t.state?.state&&(this.state=t.state.state);const e=t.state?.screen??this.extractScreenIdFromHref(location.href);e&&this.fetchScreen(e)};connectedCallback(){window.addEventListener("popstate",this.handlePopState)}disconnectedCallback(){window.removeEventListener("popstate",this.handlePopState),this.conditionalMediationAbort?.abort(),this.conditionalMediationAbort=void 0}readJsonScript(t){if(!this.el)return;const e=this.el.querySelector(`script[type="application/json"][data-authhero="${t}"]`);return e?.textContent??void 0}async componentWillLoad(){if(!this._screen){const t=this.screen||this.readJsonScript("screen")||this.el?.getAttribute("screen");t&&this.watchScreen(t)}this._branding||this.watchBranding(this.branding??this.readJsonScript("branding")),this._theme||this.watchTheme(this.theme??this.readJsonScript("theme")),this._authParams||this.watchAuthParams(this.authParams??this.readJsonScript("auth-params")),this._screen&&this.adoptPrehydrationValues(this._screen),this.loadPersistedState(),this.apiUrl&&!this._screen&&await this.fetchScreen(this.screenId)}adoptPrehydrationValues(t){const e=this.el.shadowRoot;if(!e)return;const i=[e];e.querySelectorAll("authhero-node").forEach((t=>{t.shadowRoot&&i.push(t.shadowRoot)}));const o={};for(const e of t.components??[])if(v.has(e.type))for(const t of i){const i=Array.from(t.querySelectorAll("input[name]")).find((t=>t.name===e.id&&"hidden"!==t.type));if(i){o[e.id]=i.value;break}}Object.keys(o).length>0&&(this.formData={...this.formData,...o})}async fetchScreen(t,e){if(!this.apiUrl)return!1;const i=t||this.screenId;let o=this.apiUrl;i&&o.includes("{screenId}")&&(o=o.replace("{screenId}",encodeURIComponent(i)));const r=new URL(o,this.baseUrl||window.location.origin);this.state&&r.searchParams.set("state",this.state),e&&r.searchParams.set("nodeId",e),this.loading=!0;try{const t=await fetch(this.buildUrl(r.pathname+r.search),{credentials:"include",headers:{Accept:"application/json"}});if(t.ok){const e=await t.json();if(e.screen?(this._screen=e.screen,e.branding&&(this._branding=e.branding,this.applyThemeStyles()),e.state&&(this.state=e.state),e.screenId&&(this.screenId=e.screenId)):this._screen=e,this._screen)return this.listFilter="",i&&i!==this.screenId&&(this.screenId=i),this.initFormDataFromDefaults(this._screen),this.screenChange.emit(this._screen),this.updateDataScreenAttribute(),this.persistState(),this.focusFirstInput(),e.ceremony&&this.performWebAuthnCeremony(e.ceremony),!0}else{const e=await t.json().catch((()=>({message:"Failed to load screen"})));this.flowError.emit({message:e.message||"Failed to load screen"})}}catch(t){console.error("Failed to fetch screen:",t),this.flowError.emit({message:t instanceof Error?t.message:"Failed to fetch screen"})}finally{this.loading=!1}return!1}handleInputChange=(t,e)=>{this.formData={...this.formData,[t]:e}};handleSubmit=async(t,e)=>{if(t.preventDefault(),!this._screen||this.loading)return;const i=this.el.shadowRoot?.querySelector("form");if(this._screen.partials&&i?.reportValidity&&!i.reportValidity())return;const o={...this.formData,...e||{}},r=new Set;if(i&&this._screen.partials){const t={};new FormData(i).forEach(((e,i)=>{"string"==typeof e&&i.startsWith("ulp-")&&(t[i]??=[]).push(e)}));for(const[e,i]of Object.entries(t))r.add(e),o[e]=i.length>1?i:i[0]}if(i&&i.querySelectorAll('input[type="hidden"]').forEach((t=>{t.name&&t.value&&!t.disabled&&!r.has(t.name)&&(o[t.name]=t.value)})),this.formSubmit.emit({screen:this._screen,data:o}),this.autoSubmit)if(this._screen.method&&"GET"!==this._screen.method.toUpperCase()){this.loading=!0;try{const t=await fetch(this.buildUrl(this._screen.action),{method:this._screen.method,credentials:"include",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({data:o})}),e=t.headers.get("content-type");if(e?.includes("text/html")){const e=await t.text();return document.open(),document.write(e),void document.close()}if(e?.includes("application/json")){const e=await t.json();if(e.redirect){this.flowComplete.emit({redirectUrl:e.redirect});const t=this.navigate.emit({url:e.redirect});this.shouldAutoNavigate&&!t.defaultPrevented&&(window.location.href=e.redirect)}else!t.ok&&e.screen?await this.swapScreen((()=>{this.loading=!1,this._screen=e.screen,this.listFilter="",this.initFormDataFromDefaults(e.screen),this.screenChange.emit(e.screen),this.updateDataScreenAttribute(),this.focusFirstInput()})):e.screen?await this.swapScreen((()=>{this.loading=!1,this._screen=e.screen,this.listFilter="",this.formData={},this.initFormDataFromDefaults(e.screen),this.screenChange.emit(e.screen),this.updateDataScreenAttribute(),e.screenId&&(this.screenId=e.screenId),this.persistState(),e.navigateUrl&&this.shouldAutoNavigate&&window.history.pushState({screen:e.screenId,state:this.state},"",e.navigateUrl),e.branding&&(this._branding=e.branding,this.applyThemeStyles()),e.state&&(this.state=e.state,this.persistState()),e.ceremony&&this.performWebAuthnCeremony(e.ceremony),this.focusFirstInput()})):e.complete?this.flowComplete.emit({}):!t.ok&&e.error&&(this._screen&&(this._screen={...this._screen,messages:[...this._screen.messages||[],{text:e.error,type:"error"}]}),this.flowError.emit({message:e.error}))}}catch(t){console.error("Form submission failed:",t),this.flowError.emit({message:t instanceof Error?t.message:"Form submission failed"})}finally{this.loading=!1}}else window.location.href=this.buildUrl(this._screen.action)};overrideFormSubmit(){const t=this.el.shadowRoot;if(!t)return;const e=t.querySelector("form");e&&(e.submit=()=>{if(this._screen?.partials&&e.reportValidity&&!e.reportValidity())return;const t=new FormData(e),i={};t.forEach(((t,e)=>{"string"==typeof t&&(i[e]=t)})),this.handleSubmit({preventDefault:()=>{}},i)})}performWebAuthnCeremony(t){this.isValidWebAuthnCeremony(t)?"webauthn-authentication-conditional"!==t.type?requestAnimationFrame((()=>{this.overrideFormSubmit(),"webauthn-authentication"===t.type?this.executeWebAuthnAuthentication(t):this.executeWebAuthnRegistration(t)})):this.executeWebAuthnConditionalMediation(t):console.error("Invalid WebAuthn ceremony payload",t)}isValidWebAuthnCeremony(t){if("object"!=typeof t||null===t)return!1;const e=t;if("string"!=typeof e.successAction)return!1;const i=e.options;if("object"!=typeof i||null===i)return!1;if("string"!=typeof i.challenge)return!1;if("webauthn-registration"===e.type){const t=i.rp;if("object"!=typeof t||null===t)return!1;if("string"!=typeof t.id||"string"!=typeof t.name)return!1;const e=i.user;return"object"==typeof e&&null!==e&&("string"==typeof e.id&&"string"==typeof e.name&&"string"==typeof e.displayName&&!!Array.isArray(i.pubKeyCredParams))}return"webauthn-authentication"===e.type||"webauthn-authentication-conditional"===e.type}async executeWebAuthnRegistration(t){const e=t.options,i=t=>{for(t=t.replace(/-/g,"+").replace(/_/g,"/");t.length%4;)t+="=";const e=atob(t),i=new Uint8Array(e.length);for(let t=0;t<e.length;t++)i[t]=e.charCodeAt(t);return i.buffer},o=t=>{const e=new Uint8Array(t);let i="";for(let t=0;t<e.length;t++)i+=String.fromCharCode(e[t]);return btoa(i).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")},r=()=>{const t=this.el?.shadowRoot;if(t){const e=t.querySelector("form");if(e)return e}return document.querySelector("form")};try{const n={challenge:i(e.challenge),rp:{id:e.rp.id,name:e.rp.name},user:{id:i(e.user.id),name:e.user.name,displayName:e.user.displayName},pubKeyCredParams:e.pubKeyCredParams.map((t=>({alg:t.alg,type:t.type}))),timeout:e.timeout,attestation:e.attestation||"none",authenticatorSelection:e.authenticatorSelection?{residentKey:e.authenticatorSelection.residentKey||"preferred",userVerification:e.authenticatorSelection.userVerification||"preferred"}:void 0};e.excludeCredentials?.length&&(n.excludeCredentials=e.excludeCredentials.map((t=>({id:i(t.id),type:t.type,transports:t.transports||[]}))));const a=await navigator.credentials.create({publicKey:n}),s=a.response,c={id:a.id,rawId:o(a.rawId),type:a.type,response:{attestationObject:o(s.attestationObject),clientDataJSON:o(s.clientDataJSON)},clientExtensionResults:a.getClientExtensionResults(),authenticatorAttachment:a.authenticatorAttachment||void 0};"function"==typeof s.getTransports&&(c.response.transports=s.getTransports());const l=r();if(l){const e=l.querySelector('[name="credential-field"]')||l.querySelector("#credential-field"),i=l.querySelector('[name="action-field"]')||l.querySelector("#action-field");e&&(e.value=JSON.stringify(c)),i&&(i.value=t.successAction),l.submit()}}catch(t){console.error("WebAuthn registration error:",t);const e=r();if(e){const t=e.querySelector('[name="action-field"]')||e.querySelector("#action-field");t&&(t.value="error"),e.submit()}}}async executeWebAuthnAuthentication(t){const e=t.options,i=t=>{for(t=t.replace(/-/g,"+").replace(/_/g,"/");t.length%4;)t+="=";const e=atob(t),i=new Uint8Array(e.length);for(let t=0;t<e.length;t++)i[t]=e.charCodeAt(t);return i.buffer},o=t=>{const e=new Uint8Array(t);let i="";for(let t=0;t<e.length;t++)i+=String.fromCharCode(e[t]);return btoa(i).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")},r=()=>{const t=this.el?.shadowRoot;if(t){const e=t.querySelector("form");if(e)return e}return document.querySelector("form")};try{const n={challenge:i(e.challenge),rpId:e.rpId,timeout:e.timeout,userVerification:e.userVerification||"preferred"};e.allowCredentials?.length&&(n.allowCredentials=e.allowCredentials.map((t=>({id:i(t.id),type:t.type,transports:t.transports||[]}))));const a=await navigator.credentials.get({publicKey:n}),s=a.response,c={id:a.id,rawId:o(a.rawId),type:a.type,response:{authenticatorData:o(s.authenticatorData),clientDataJSON:o(s.clientDataJSON),signature:o(s.signature)},clientExtensionResults:a.getClientExtensionResults(),authenticatorAttachment:a.authenticatorAttachment||void 0};s.userHandle&&(c.response.userHandle=o(s.userHandle));const l=r();if(l){const e=l.querySelector('[name="credential-field"]')||l.querySelector("#credential-field"),i=l.querySelector('[name="action-field"]')||l.querySelector("#action-field");e&&(e.value=JSON.stringify(c)),i&&(i.value=t.successAction),l.submit()}}catch(t){console.error("WebAuthn authentication error:",t);const e=r();if(e){const t=e.querySelector('[name="action-field"]')||e.querySelector("#action-field");t&&(t.value="error"),e.submit()}}}async executeWebAuthnConditionalMediation(t){if(!window.PublicKeyCredential||!PublicKeyCredential.isConditionalMediationAvailable)return;if(!await PublicKeyCredential.isConditionalMediationAvailable())return;this.conditionalMediationAbort?.abort();const e=new AbortController;this.conditionalMediationAbort=e;const i=t.options,o=t=>{for(t=t.replace(/-/g,"+").replace(/_/g,"/");t.length%4;)t+="=";const e=atob(t),i=new Uint8Array(e.length);for(let t=0;t<e.length;t++)i[t]=e.charCodeAt(t);return i.buffer},r=t=>{const e=new Uint8Array(t);let i="";for(let t=0;t<e.length;t++)i+=String.fromCharCode(e[t]);return btoa(i).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")};try{const n=await navigator.credentials.get({mediation:"conditional",signal:e.signal,publicKey:{challenge:o(i.challenge),rpId:i.rpId,timeout:i.timeout,userVerification:i.userVerification||"preferred"}}),a=n.response,s={id:n.id,rawId:r(n.rawId),type:n.type,response:{authenticatorData:r(a.authenticatorData),clientDataJSON:r(a.clientDataJSON),signature:r(a.signature)},clientExtensionResults:n.getClientExtensionResults(),authenticatorAttachment:n.authenticatorAttachment||void 0};a.userHandle&&(s.response.userHandle=r(a.userHandle)),this.formData["credential-field"]=JSON.stringify(s),this.formData["action-field"]=t.successAction,this.overrideFormSubmit();const c=this.el?.shadowRoot,l=c?.querySelector("form");if(l){const e=l.querySelector('[name="credential-field"]')||l.querySelector("#credential-field"),i=l.querySelector('[name="action-field"]')||l.querySelector("#action-field");e&&(e.value=JSON.stringify(s)),i&&(i.value=t.successAction),l.submit()}}catch(t){if("AbortError"===t?.name||"NotAllowedError"===t?.name)return;console.error("Conditional mediation error:",t)}}handleButtonClick=t=>{if("submit"!==t.type)if(this.buttonClick.emit(t),"SOCIAL"===t.type&&t.value&&this.shouldAutoNavigate){const e=this.getProviderHref(t.value);if(e){const t=this.extractScreenIdFromHref(e);return void(t&&this.apiUrl?this.navigateToScreen(t,e):window.location.href=e)}this.handleSocialLogin(t.value)}else"RESEND_BUTTON"===t.type&&this.shouldAutoNavigate&&this.handleResend();else{const e=this._screen?.components?.find((e=>e.id===t.id));if(this._screen&&("NEXT_BUTTON"!==e?.type||!0!==e.config?.skip_validation)&&this.hasUnfilledRequiredFields(this._screen))return;if((!this._screen?.method||"GET"===this._screen.method.toUpperCase())&&this._screen?.action)return void(window.location.href=this.buildUrl(this._screen.action));const i={...this.formData,[t.id]:"true"};this.formData=i,this.handleSubmit({preventDefault:()=>{}},i)}};handleSocialLogin(t){const e=this._authParams||{},i={connection:t};this.state?i.state=this.state:e.state&&(i.state=e.state),e.client_id&&(i.client_id=e.client_id),e.redirect_uri&&(i.redirect_uri=e.redirect_uri),e.scope&&(i.scope=e.scope),e.audience&&(i.audience=e.audience),e.nonce&&(i.nonce=e.nonce),e.response_type&&(i.response_type=e.response_type);const o=this.buildUrl("/authorize?"+new URLSearchParams(i).toString());this.navigate.emit({url:o}).defaultPrevented||(window.location.href=o)}async handleResend(){if(this._screen?.action)try{const t=this._screen.action+(this._screen.action.includes("?")?"&":"?")+"action=resend";await fetch(this.buildUrl(t),{method:"POST",credentials:"include"})}catch(t){console.error("Resend failed:",t)}}extractScreenIdFromHref(t){try{const e=new URL(t,window.location.origin).pathname,i=e.match(/\/u2\/login\/([^/]+)$/);if(i)return i[1];const o=e.match(/\/u2\/([^/]+)$/);return o&&"login"!==o[1]&&"screen"!==o[1]?o[1]:null}catch{return null}}handleLinkClick=(t,e)=>{if(this.linkClick.emit({id:e.id,href:e.href,text:e.text}),!this.shouldAutoNavigate)return void t.preventDefault();const i=this.extractScreenIdFromHref(e.href);return i&&this.apiUrl?(t.preventDefault(),void this.navigateToScreen(i,e.href)):void 0};async navigateToScreen(t,e){await this.fetchScreen(t)?window.history.pushState({screen:t,state:this.state},"",e):window.location.href=e}getProviderHref(t){if(!this._screen)return null;for(const e of this._screen.components){const i=e;if("SOCIAL"===i.type&&i.config?.provider_details){const e=i.config.provider_details.find((e=>e.name===t));if(e?.href)return e.href}}return null}isSocialComponent(t){return"SOCIAL"===t.type}isDividerComponent(t){return"DIVIDER"===t.type}isRequiredFieldFilled(t){const e=this.formData[t.id];return"BOOLEAN"===t.type||"LEGAL"===t.type?"true"===e:"string"==typeof e&&""!==e.trim()}hasUnfilledRequiredFields(t){return(t.components??[]).some((t=>!1!==t.visible&&"required"in t&&!0===t.required&&w.has(t.type)&&!this.isRequiredFieldFilled(t)))}getChoiceButtonText(t){const e=t.config;return e?.text??""}renderPromptPartial(t,e){const i=t.partials?.[e];return i?o("div",{class:`prompt-partial prompt-partial-${e}`,part:`prompt-partial prompt-partial-${e}`,"data-insertion-point":e,innerHTML:i}):null}renderScreenLinks(t){return t.links?.length?o("div",{class:"links",part:"links"},t.links.map((t=>o("span",{class:"link-wrapper",part:"link-wrapper",key:t.id??t.href},t.linkText?o("span",null,t.text," ",o("a",{href:t.href,class:"link",part:"link",onClick:e=>this.handleLinkClick(e,{id:t.id,href:t.href,text:t.linkText||t.text})},t.linkText)):o("a",{href:t.href,class:"link",part:"link",onClick:e=>this.handleLinkClick(e,{id:t.id,href:t.href,text:t.text})},t.text))))):null}render(){const t=this._screen;if(this.loading&&!t)return o("div",{class:"widget-container"},o("div",{class:"loading-spinner"}));if(!t)return o("div",{class:"widget-container"},o("div",{class:"error-message"},"No screen configuration provided"));const e=t.messages?.filter((t=>"error"===t.type))||[],i=t.messages?.filter((t=>"success"===t.type))||[],n=[...t.components??[]],a=n.filter((t=>!1!==t.visible)).sort(((t,e)=>(t.order??0)-(e.order??0))),s=n.filter((t=>!1===t.visible)),c=a.filter((t=>this.isSocialComponent(t))),l=c.length>0?a.find((t=>this.isDividerComponent(t))):void 0,h=a.filter((t=>!this.isSocialComponent(t)&&t!==l)),d=Object.values(t.partials??{}).some((t=>!!t)),p=d?h.filter((t=>"submit"===t.id&&"NEXT_BUTTON"===t.type)):[],f=d?h.filter((t=>!p.includes(t))):h,u=!!l,g=l?.config?.text||"Or",b=f.filter((t=>"NEXT_BUTTON"===t.type)),x=b.length===f.length&&b.length>5,v=this.hasUnfilledRequiredFields(t),w=this.listFilter.trim().toLowerCase(),y=x&&w?b.filter((t=>this.getChoiceButtonText(t).toLowerCase().includes(w))):b,k=t=>{const e=t.config;return["social-buttons","button","button-secondary","button-social","button-social-content","button-social-text","button-social-text-short","button-social-subtitle","button-social-badge","social-icon",...(e?.providers??[]).flatMap((t=>{const e=r(t);return[`button-social-${e}`,`button-social-content-${e}`,`button-social-text-${e}`,`button-social-text-short-${e}`,`button-social-subtitle-${e}`,`button-social-badge-${e}`,`social-icon-${e}`]}))].join(", ")},S=this._theme?.widget?.logo_url||this._branding?.logo_url;return o("div",{class:"widget-container",part:"container","data-authstack-container":!0},o("header",{class:"widget-header",part:"header"},S&&o("div",{class:"logo-wrapper",part:"logo-wrapper"},o("img",{class:"logo",part:"logo",src:S,alt:"Logo"})),t.title&&o("h1",{class:"title",part:"title",innerHTML:m(t.title)}),t.description&&o("p",{class:"description",part:"description",innerHTML:m(t.description)})),o("div",{class:"widget-body",part:"body"},e.map((t=>o("div",{class:"message message-error",part:"message message-error",key:t.id??t.text},t.text))),i.map((t=>o("div",{class:"message message-success",part:"message message-success",key:t.id??t.text},t.text))),o("form",{onSubmit:this.handleSubmit,action:t.action,method:t.method||"POST",part:"form"},s.map((t=>o("input",{type:"hidden",name:t.id,id:t.id,key:t.id,value:this.formData[t.id]||""}))),o("div",{class:"form-content"},this.renderPromptPartial(t,"form-content-start"),c.length>0&&o("div",{class:"social-section",part:"social-section"},c.map((t=>o("authhero-node",{key:t.id,component:t,locale:this.locale,value:this.formData[t.id],onFieldChange:t=>this.handleInputChange(t.detail.id,t.detail.value),onButtonClick:t=>this.handleButtonClick(t.detail),disabled:this.loading,exportparts:k(t)})))),c.length>0&&h.length>0&&u&&o("div",{class:"divider",part:"divider"},o("span",{class:"divider-text"},g)),o("div",{class:"fields-section",part:"fields-section"},x&&o("input",{type:"text",class:"choice-list-search",part:"choice-list-search",placeholder:"Search","aria-label":"Search",autocomplete:"off",value:this.listFilter,onInput:t=>this.listFilter=t.target.value,onKeyDown:t=>{"Enter"===t.key&&t.preventDefault()}}),o("div",{class:x?"fields-list fields-list-scroll":"fields-list",part:x?"fields-list fields-list-scroll":"fields-list"},(x?y:f).map((t=>o("authhero-node",{key:t.id,component:t,locale:this.locale,value:this.formData[t.id],onFieldChange:t=>this.handleInputChange(t.detail.id,t.detail.value),onButtonClick:t=>this.handleButtonClick(t.detail),disabled:this.loading||"NEXT_BUTTON"===t.type&&!0!==t.config?.skip_validation&&v}))),x&&0===y.length&&o("div",{class:"choice-list-empty",part:"choice-list-empty"},"No matches"))),this.renderPromptPartial(t,"form-content-end"),d&&o("div",{class:"form-footer",part:"form-footer"},this.renderPromptPartial(t,"form-footer-start"),p.map((t=>o("authhero-node",{key:t.id,component:t,locale:this.locale,value:this.formData[t.id],onFieldChange:t=>this.handleInputChange(t.detail.id,t.detail.value),onButtonClick:t=>this.handleButtonClick(t.detail),disabled:this.loading||"NEXT_BUTTON"===t.type&&!0!==t.config?.skip_validation&&v}))),this.renderPromptPartial(t,"form-footer-end"))),d&&o("div",{class:"secondary-actions",part:"secondary-actions"},this.renderPromptPartial(t,"secondary-actions-start"),this.renderScreenLinks(t),this.renderPromptPartial(t,"secondary-actions-end"))),!d&&this.renderScreenLinks(t),t.footer&&o("div",{class:"widget-footer",part:"footer",innerHTML:m(t.footer)})))}static get watchers(){return{screenId:[{watchScreenId:0}],screen:[{watchScreen:0}],branding:[{watchBranding:0}],theme:[{watchTheme:0}],authParams:[{watchAuthParams:0}]}}};y.style=':host{display:block;font-family:var( --ah-font-family, "ulp-font", -apple-system, BlinkMacSystemFont, Roboto, Helvetica, sans-serif );font-size:var(--ah-font-size-base, 16px);line-height:var(--ah-line-height-base, 1.5);color:var(--ah-color-text, #1e212a);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.widget-container{width:var(--ah-widget-max-width, 400px);margin:0 auto;background-color:var(--ah-color-bg, #ffffff);border-radius:var(--ah-widget-radius, 5px);border:var(--ah-widget-border-width, 0) solid var(--ah-widget-border-color, transparent);box-shadow:var(--ah-widget-shadow, 0 4px 22px 0 rgba(0, 0, 0, 0.11));box-sizing:border-box}.widget-header{padding:var(--ah-header-padding, 40px 48px 24px)}.widget-body{padding:var(--ah-body-padding, 0 48px 40px)}.logo-wrapper{display:var(--ah-logo-display, flex);justify-content:var(--ah-logo-align, center);margin-bottom:8px}.logo{display:block;height:var(--ah-logo-height, 52px);max-width:100%;width:auto;object-fit:contain}.title{font-size:var(--ah-font-size-title, 24px);font-weight:var(--ah-font-weight-title, 700);text-align:var(--ah-title-align, center);margin:var(--ah-title-margin, 24px 0 24px);color:var(--ah-color-text-header, var(--ah-color-header, #1e212a));line-height:1.2}.description{font-size:var(--ah-font-size-subtitle, 16px);font-weight:var(--ah-font-weight-subtitle, 400);text-align:var(--ah-title-align, center);margin:var(--ah-description-margin, 0 0 8px);color:var(--ah-color-text, #1e212a);line-height:1.5}.message{padding:12px 16px;border-radius:4px;margin-bottom:16px;font-size:14px;line-height:1.5}.message-error{background-color:var(--ah-color-error-bg, #ffeaea);color:var(--ah-color-error, #d03c38);border-left:3px solid var(--ah-color-error, #d03c38)}.message-success{background-color:var(--ah-color-success-bg, #e6f9f1);color:var(--ah-color-success, #13a769);border-left:3px solid var(--ah-color-success, #13a769)}form{display:flex;flex-direction:column}.form-footer,.secondary-actions,.prompt-partial{display:flex;flex-direction:column}.prompt-partial .ulp-field{display:flex;flex-direction:column;gap:6px;position:relative;margin-top:8px;margin-bottom:16px}.prompt-partial label{font-size:var(--ah-font-size-label, 14px);font-weight:var(--ah-font-weight-label, 400);color:var(--ah-color-text, #1e212a)}.prompt-partial .ulp-error input:not([type="checkbox"]):not([type="radio"]):not([type="hidden"]),.prompt-partial .ulp-error select,.prompt-partial .ulp-error textarea{border-color:var(--ah-color-error, #d03c38)}.prompt-partial .ulp-error input:not([type="checkbox"]):not([type="radio"]):not([type="hidden"]):focus,.prompt-partial .ulp-error select:focus,.prompt-partial .ulp-error textarea:focus{box-shadow:inset 0 0 0 1px var(--ah-color-error, #d03c38)}.prompt-partial .ulp-error-info{font-size:12px;color:var(--ah-color-error, #d03c38);margin-top:-2px;line-height:1.4}.prompt-partial .required{color:var(--ah-color-error, #d03c38);margin-left:2px}.prompt-partial .ulp-field>input+label,.prompt-partial .ulp-field>select+label,.prompt-partial .ulp-field>textarea+label{position:absolute;left:16px;top:50%;z-index:1;padding:0;background-color:transparent;color:var(--ah-color-text-muted, #65676e);pointer-events:none;transform:translateY(-50%);transition:all 0.15s ease-out}.prompt-partial .ulp-field>input:focus+label,.prompt-partial .ulp-field>input:not(:placeholder-shown)+label,.prompt-partial .ulp-field>select+label,.prompt-partial .ulp-field>textarea:focus+label,.prompt-partial .ulp-field>textarea:not(:placeholder-shown)+label{top:-8px;left:12px;padding:0 4px;background-color:var(--ah-color-bg, #ffffff);color:var(--ah-color-text-muted, #65676e);font-size:12px;transform:translateY(0)}.prompt-partial .ulp-field>input:focus+label,.prompt-partial .ulp-field>select:focus+label,.prompt-partial .ulp-field>textarea:focus+label{color:var(--ah-color-primary, #635dff)}.prompt-partial input:not([type="checkbox"]):not([type="radio"]):not([type="hidden"]),.prompt-partial select,.prompt-partial textarea{width:100%;padding:16px;font-size:16px;font-family:inherit;color:var(--ah-color-input-text, var(--ah-color-text, #1e212a));background-color:var(--ah-color-input-bg, #ffffff);border:var(--ah-input-border-width, 1px) solid var(--ah-color-border, #c9cace);border-radius:var(--ah-input-radius, 3px);outline:none;box-sizing:border-box;transition:border-color 0.15s ease-out, box-shadow 0.15s ease-out}.prompt-partial input:not([type="checkbox"]):not([type="radio"]):not([type="hidden"]):hover,.prompt-partial select:hover,.prompt-partial textarea:hover{border-color:var(--ah-color-border-hover, #65676e)}.prompt-partial input:not([type="checkbox"]):not([type="radio"]):not([type="hidden"]):focus,.prompt-partial select:focus,.prompt-partial textarea:focus{border-color:var(--ah-color-primary, #635dff);box-shadow:inset 0 0 0 1px var(--ah-color-primary, #635dff)}.form-content{display:flex;flex-direction:column}.social-section{display:flex;flex-direction:column;gap:8px;order:var(--ah-social-order, 2)}.fields-section{display:flex;flex-direction:column;order:var(--ah-fields-order, 0)}.fields-list{display:flex;flex-direction:column}.fields-list-scroll{max-height:var(--ah-choice-list-max-height, 320px);overflow-y:auto;gap:var(--ah-choice-list-gap, 8px);padding-right:4px}.choice-list-search{width:100%;padding:16px;margin-bottom:12px;font-size:16px;font-family:inherit;color:var(--ah-color-input-text, var(--ah-color-text, #1e212a));background-color:var(--ah-color-input-bg, #ffffff);border:var(--ah-input-border-width, 1px) solid var(--ah-color-border, #c9cace);border-radius:var(--ah-input-radius, 3px);outline:none;box-sizing:border-box;transition:border-color 0.15s ease-out, box-shadow 0.15s ease-out}.choice-list-search:hover{border-color:var(--ah-color-border-hover, #65676e)}.choice-list-search:focus{border-color:var(--ah-color-primary, var(--ah-color-link, #635dff))}.choice-list-empty{padding:16px;text-align:center;font-size:14px;color:var(--ah-color-text-muted, #65676e)}.divider{display:flex;align-items:center;text-align:center;margin:16px 0;order:var(--ah-divider-order, 1)}.divider::before,.divider::after{content:"";flex:1;border-bottom:1px solid var(--ah-color-border-muted, #c9cace)}.divider-text{padding:0 10px;font-size:12px;font-weight:400;color:var(--ah-color-text-muted, #65676e);text-transform:uppercase;letter-spacing:0}.links{display:flex;flex-direction:column;align-items:center;gap:8px;margin-top:16px}.link-wrapper{font-size:var(--ah-font-size-body, 14px);font-weight:var(--ah-font-weight-body, 400);color:var(--ah-color-text, #1e212a)}.link{color:var(--ah-color-link, #635dff);text-decoration:var(--ah-link-decoration, none);font-size:var(--ah-font-size-link, 14px);font-weight:var(--ah-font-weight-link, 400);transition:color 150ms ease}.link:hover{text-decoration:underline}.link:focus-visible{outline:2px solid var(--ah-color-focus-ring, var(--ah-color-link, #635dff));outline-offset:2px;border-radius:2px}.widget-footer{margin-top:16px;text-align:center;font-size:12px;color:var(--ah-color-text-muted, #65676e)}.widget-footer a{color:var(--ah-color-link, #635dff);text-decoration:var(--ah-link-decoration, none);font-size:12px;transition:color 150ms ease}.widget-footer a:hover{text-decoration:underline}.widget-footer a:focus-visible{outline:2px solid var(--ah-color-focus-ring, var(--ah-color-link, #635dff));outline-offset:2px;border-radius:2px}.loading-spinner{width:32px;height:32px;margin:24px auto;border:3px solid var(--ah-color-border-muted, #e0e1e3);border-top-color:var(--ah-color-primary, #635dff);border-radius:50%;animation:spin 0.8s linear infinite}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}.error-message{text-align:center;color:var(--ah-color-error, #d03c38);padding:16px;font-size:14px}@media (max-width: 480px){:host(:not([floating])){display:block;width:100%;min-height:100vh;background-color:var(--ah-color-bg, #ffffff)}:host(:not([floating])) .widget-container{box-shadow:none;border-radius:0;border:0;width:100%;margin:0}:host([floating]) .widget-container{width:100%;margin:0}.widget-header{padding:24px 16px 16px}.widget-body{padding:0 16px 24px}}';export{y as authhero_widget}
@@ -517,7 +517,7 @@ function escapeAttr(value) {
517
517
  .replace(/>/g, "&gt;");
518
518
  }
519
519
 
520
- const authheroWidgetCss = () => `:host{display:block;font-family:var( --ah-font-family, "ulp-font", -apple-system, BlinkMacSystemFont, Roboto, Helvetica, sans-serif );font-size:var(--ah-font-size-base, 16px);line-height:var(--ah-line-height-base, 1.5);color:var(--ah-color-text, #1e212a);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.widget-container{width:var(--ah-widget-max-width, 400px);margin:0 auto;background-color:var(--ah-color-bg, #ffffff);border-radius:var(--ah-widget-radius, 5px);border:var(--ah-widget-border-width, 0) solid var(--ah-widget-border-color, transparent);box-shadow:var(--ah-widget-shadow, 0 4px 22px 0 rgba(0, 0, 0, 0.11));box-sizing:border-box}.widget-header{padding:var(--ah-header-padding, 40px 48px 24px)}.widget-body{padding:var(--ah-body-padding, 0 48px 40px)}.logo-wrapper{display:var(--ah-logo-display, flex);justify-content:var(--ah-logo-align, center);margin-bottom:8px}.logo{display:block;height:var(--ah-logo-height, 52px);max-width:100%;width:auto;object-fit:contain}.title{font-size:var(--ah-font-size-title, 24px);font-weight:var(--ah-font-weight-title, 700);text-align:var(--ah-title-align, center);margin:var(--ah-title-margin, 24px 0 24px);color:var(--ah-color-text-header, var(--ah-color-header, #1e212a));line-height:1.2}.description{font-size:var(--ah-font-size-subtitle, 16px);font-weight:var(--ah-font-weight-subtitle, 400);text-align:var(--ah-title-align, center);margin:var(--ah-description-margin, 0 0 8px);color:var(--ah-color-text, #1e212a);line-height:1.5}.message{padding:12px 16px;border-radius:4px;margin-bottom:16px;font-size:14px;line-height:1.5}.message-error{background-color:var(--ah-color-error-bg, #ffeaea);color:var(--ah-color-error, #d03c38);border-left:3px solid var(--ah-color-error, #d03c38)}.message-success{background-color:var(--ah-color-success-bg, #e6f9f1);color:var(--ah-color-success, #13a769);border-left:3px solid var(--ah-color-success, #13a769)}form{display:flex;flex-direction:column}.form-content{display:flex;flex-direction:column}.social-section{display:flex;flex-direction:column;gap:8px;order:var(--ah-social-order, 2)}.fields-section{display:flex;flex-direction:column;order:var(--ah-fields-order, 0)}.fields-list{display:flex;flex-direction:column}.fields-list-scroll{max-height:var(--ah-choice-list-max-height, 320px);overflow-y:auto;gap:var(--ah-choice-list-gap, 8px);padding-right:4px}.choice-list-search{width:100%;padding:16px;margin-bottom:12px;font-size:16px;font-family:inherit;color:var(--ah-color-input-text, var(--ah-color-text, #1e212a));background-color:var(--ah-color-input-bg, #ffffff);border:var(--ah-input-border-width, 1px) solid var(--ah-color-border, #c9cace);border-radius:var(--ah-input-radius, 3px);outline:none;box-sizing:border-box;transition:border-color 0.15s ease-out, box-shadow 0.15s ease-out}.choice-list-search:hover{border-color:var(--ah-color-border-hover, #65676e)}.choice-list-search:focus{border-color:var(--ah-color-primary, var(--ah-color-link, #635dff))}.choice-list-empty{padding:16px;text-align:center;font-size:14px;color:var(--ah-color-text-muted, #65676e)}.divider{display:flex;align-items:center;text-align:center;margin:16px 0;order:var(--ah-divider-order, 1)}.divider::before,.divider::after{content:"";flex:1;border-bottom:1px solid var(--ah-color-border-muted, #c9cace)}.divider-text{padding:0 10px;font-size:12px;font-weight:400;color:var(--ah-color-text-muted, #65676e);text-transform:uppercase;letter-spacing:0}.links{display:flex;flex-direction:column;align-items:center;gap:8px;margin-top:16px}.link-wrapper{font-size:var(--ah-font-size-body, 14px);font-weight:var(--ah-font-weight-body, 400);color:var(--ah-color-text, #1e212a)}.link{color:var(--ah-color-link, #635dff);text-decoration:var(--ah-link-decoration, none);font-size:var(--ah-font-size-link, 14px);font-weight:var(--ah-font-weight-link, 400);transition:color 150ms ease}.link:hover{text-decoration:underline}.link:focus-visible{outline:2px solid var(--ah-color-focus-ring, var(--ah-color-link, #635dff));outline-offset:2px;border-radius:2px}.widget-footer{margin-top:16px;text-align:center;font-size:12px;color:var(--ah-color-text-muted, #65676e)}.widget-footer a{color:var(--ah-color-link, #635dff);text-decoration:var(--ah-link-decoration, none);font-size:12px;transition:color 150ms ease}.widget-footer a:hover{text-decoration:underline}.widget-footer a:focus-visible{outline:2px solid var(--ah-color-focus-ring, var(--ah-color-link, #635dff));outline-offset:2px;border-radius:2px}.loading-spinner{width:32px;height:32px;margin:24px auto;border:3px solid var(--ah-color-border-muted, #e0e1e3);border-top-color:var(--ah-color-primary, #635dff);border-radius:50%;animation:spin 0.8s linear infinite}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}.error-message{text-align:center;color:var(--ah-color-error, #d03c38);padding:16px;font-size:14px}@media (max-width: 480px){:host(:not([floating])){display:block;width:100%;min-height:100vh;background-color:var(--ah-color-bg, #ffffff)}:host(:not([floating])) .widget-container{box-shadow:none;border-radius:0;border:0;width:100%;margin:0}:host([floating]) .widget-container{width:100%;margin:0}.widget-header{padding:24px 16px 16px}.widget-body{padding:0 16px 24px}}`;
520
+ const authheroWidgetCss = () => `:host{display:block;font-family:var( --ah-font-family, "ulp-font", -apple-system, BlinkMacSystemFont, Roboto, Helvetica, sans-serif );font-size:var(--ah-font-size-base, 16px);line-height:var(--ah-line-height-base, 1.5);color:var(--ah-color-text, #1e212a);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.widget-container{width:var(--ah-widget-max-width, 400px);margin:0 auto;background-color:var(--ah-color-bg, #ffffff);border-radius:var(--ah-widget-radius, 5px);border:var(--ah-widget-border-width, 0) solid var(--ah-widget-border-color, transparent);box-shadow:var(--ah-widget-shadow, 0 4px 22px 0 rgba(0, 0, 0, 0.11));box-sizing:border-box}.widget-header{padding:var(--ah-header-padding, 40px 48px 24px)}.widget-body{padding:var(--ah-body-padding, 0 48px 40px)}.logo-wrapper{display:var(--ah-logo-display, flex);justify-content:var(--ah-logo-align, center);margin-bottom:8px}.logo{display:block;height:var(--ah-logo-height, 52px);max-width:100%;width:auto;object-fit:contain}.title{font-size:var(--ah-font-size-title, 24px);font-weight:var(--ah-font-weight-title, 700);text-align:var(--ah-title-align, center);margin:var(--ah-title-margin, 24px 0 24px);color:var(--ah-color-text-header, var(--ah-color-header, #1e212a));line-height:1.2}.description{font-size:var(--ah-font-size-subtitle, 16px);font-weight:var(--ah-font-weight-subtitle, 400);text-align:var(--ah-title-align, center);margin:var(--ah-description-margin, 0 0 8px);color:var(--ah-color-text, #1e212a);line-height:1.5}.message{padding:12px 16px;border-radius:4px;margin-bottom:16px;font-size:14px;line-height:1.5}.message-error{background-color:var(--ah-color-error-bg, #ffeaea);color:var(--ah-color-error, #d03c38);border-left:3px solid var(--ah-color-error, #d03c38)}.message-success{background-color:var(--ah-color-success-bg, #e6f9f1);color:var(--ah-color-success, #13a769);border-left:3px solid var(--ah-color-success, #13a769)}form{display:flex;flex-direction:column}.form-footer,.secondary-actions,.prompt-partial{display:flex;flex-direction:column}.prompt-partial .ulp-field{display:flex;flex-direction:column;gap:6px;position:relative;margin-top:8px;margin-bottom:16px}.prompt-partial label{font-size:var(--ah-font-size-label, 14px);font-weight:var(--ah-font-weight-label, 400);color:var(--ah-color-text, #1e212a)}.prompt-partial .ulp-error input:not([type="checkbox"]):not([type="radio"]):not([type="hidden"]),.prompt-partial .ulp-error select,.prompt-partial .ulp-error textarea{border-color:var(--ah-color-error, #d03c38)}.prompt-partial .ulp-error input:not([type="checkbox"]):not([type="radio"]):not([type="hidden"]):focus,.prompt-partial .ulp-error select:focus,.prompt-partial .ulp-error textarea:focus{box-shadow:inset 0 0 0 1px var(--ah-color-error, #d03c38)}.prompt-partial .ulp-error-info{font-size:12px;color:var(--ah-color-error, #d03c38);margin-top:-2px;line-height:1.4}.prompt-partial .required{color:var(--ah-color-error, #d03c38);margin-left:2px}.prompt-partial .ulp-field>input+label,.prompt-partial .ulp-field>select+label,.prompt-partial .ulp-field>textarea+label{position:absolute;left:16px;top:50%;z-index:1;padding:0;background-color:transparent;color:var(--ah-color-text-muted, #65676e);pointer-events:none;transform:translateY(-50%);transition:all 0.15s ease-out}.prompt-partial .ulp-field>input:focus+label,.prompt-partial .ulp-field>input:not(:placeholder-shown)+label,.prompt-partial .ulp-field>select+label,.prompt-partial .ulp-field>textarea:focus+label,.prompt-partial .ulp-field>textarea:not(:placeholder-shown)+label{top:-8px;left:12px;padding:0 4px;background-color:var(--ah-color-bg, #ffffff);color:var(--ah-color-text-muted, #65676e);font-size:12px;transform:translateY(0)}.prompt-partial .ulp-field>input:focus+label,.prompt-partial .ulp-field>select:focus+label,.prompt-partial .ulp-field>textarea:focus+label{color:var(--ah-color-primary, #635dff)}.prompt-partial input:not([type="checkbox"]):not([type="radio"]):not([type="hidden"]),.prompt-partial select,.prompt-partial textarea{width:100%;padding:16px;font-size:16px;font-family:inherit;color:var(--ah-color-input-text, var(--ah-color-text, #1e212a));background-color:var(--ah-color-input-bg, #ffffff);border:var(--ah-input-border-width, 1px) solid var(--ah-color-border, #c9cace);border-radius:var(--ah-input-radius, 3px);outline:none;box-sizing:border-box;transition:border-color 0.15s ease-out, box-shadow 0.15s ease-out}.prompt-partial input:not([type="checkbox"]):not([type="radio"]):not([type="hidden"]):hover,.prompt-partial select:hover,.prompt-partial textarea:hover{border-color:var(--ah-color-border-hover, #65676e)}.prompt-partial input:not([type="checkbox"]):not([type="radio"]):not([type="hidden"]):focus,.prompt-partial select:focus,.prompt-partial textarea:focus{border-color:var(--ah-color-primary, #635dff);box-shadow:inset 0 0 0 1px var(--ah-color-primary, #635dff)}.form-content{display:flex;flex-direction:column}.social-section{display:flex;flex-direction:column;gap:8px;order:var(--ah-social-order, 2)}.fields-section{display:flex;flex-direction:column;order:var(--ah-fields-order, 0)}.fields-list{display:flex;flex-direction:column}.fields-list-scroll{max-height:var(--ah-choice-list-max-height, 320px);overflow-y:auto;gap:var(--ah-choice-list-gap, 8px);padding-right:4px}.choice-list-search{width:100%;padding:16px;margin-bottom:12px;font-size:16px;font-family:inherit;color:var(--ah-color-input-text, var(--ah-color-text, #1e212a));background-color:var(--ah-color-input-bg, #ffffff);border:var(--ah-input-border-width, 1px) solid var(--ah-color-border, #c9cace);border-radius:var(--ah-input-radius, 3px);outline:none;box-sizing:border-box;transition:border-color 0.15s ease-out, box-shadow 0.15s ease-out}.choice-list-search:hover{border-color:var(--ah-color-border-hover, #65676e)}.choice-list-search:focus{border-color:var(--ah-color-primary, var(--ah-color-link, #635dff))}.choice-list-empty{padding:16px;text-align:center;font-size:14px;color:var(--ah-color-text-muted, #65676e)}.divider{display:flex;align-items:center;text-align:center;margin:16px 0;order:var(--ah-divider-order, 1)}.divider::before,.divider::after{content:"";flex:1;border-bottom:1px solid var(--ah-color-border-muted, #c9cace)}.divider-text{padding:0 10px;font-size:12px;font-weight:400;color:var(--ah-color-text-muted, #65676e);text-transform:uppercase;letter-spacing:0}.links{display:flex;flex-direction:column;align-items:center;gap:8px;margin-top:16px}.link-wrapper{font-size:var(--ah-font-size-body, 14px);font-weight:var(--ah-font-weight-body, 400);color:var(--ah-color-text, #1e212a)}.link{color:var(--ah-color-link, #635dff);text-decoration:var(--ah-link-decoration, none);font-size:var(--ah-font-size-link, 14px);font-weight:var(--ah-font-weight-link, 400);transition:color 150ms ease}.link:hover{text-decoration:underline}.link:focus-visible{outline:2px solid var(--ah-color-focus-ring, var(--ah-color-link, #635dff));outline-offset:2px;border-radius:2px}.widget-footer{margin-top:16px;text-align:center;font-size:12px;color:var(--ah-color-text-muted, #65676e)}.widget-footer a{color:var(--ah-color-link, #635dff);text-decoration:var(--ah-link-decoration, none);font-size:12px;transition:color 150ms ease}.widget-footer a:hover{text-decoration:underline}.widget-footer a:focus-visible{outline:2px solid var(--ah-color-focus-ring, var(--ah-color-link, #635dff));outline-offset:2px;border-radius:2px}.loading-spinner{width:32px;height:32px;margin:24px auto;border:3px solid var(--ah-color-border-muted, #e0e1e3);border-top-color:var(--ah-color-primary, #635dff);border-radius:50%;animation:spin 0.8s linear infinite}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}.error-message{text-align:center;color:var(--ah-color-error, #d03c38);padding:16px;font-size:14px}@media (max-width: 480px){:host(:not([floating])){display:block;width:100%;min-height:100vh;background-color:var(--ah-color-bg, #ffffff)}:host(:not([floating])) .widget-container{box-shadow:none;border-radius:0;border:0;width:100%;margin:0}:host([floating]) .widget-container{width:100%;margin:0}.widget-header{padding:24px 16px 16px}.widget-body{padding:0 16px 24px}}`;
521
521
 
522
522
  /**
523
523
  * When a screen's field section is made up entirely of choice buttons
@@ -532,6 +532,19 @@ const CHOICE_LIST_SEARCH_THRESHOLD = 5;
532
532
  * (CARDS, FILE, RECAPTCHA, …) can carry `required` in the schema too, and
533
533
  * gating on them would leave Continue disabled with no way to satisfy it.
534
534
  */
535
+ /**
536
+ * Field types rendered as a single plain text input whose value maps 1:1 to
537
+ * formData. Composite fields (TEL, DATE) and choice/checkbox fields keep
538
+ * internal state, so they're not adopted from pre-hydration markup.
539
+ */
540
+ const PREHYDRATION_TEXT_TYPES = new Set([
541
+ "TEXT",
542
+ "EMAIL",
543
+ "CODE",
544
+ "PASSWORD",
545
+ "NUMBER",
546
+ "URL",
547
+ ]);
535
548
  const FILLABLE_FIELD_TYPES = new Set([
536
549
  "TEXT",
537
550
  "EMAIL",
@@ -912,7 +925,24 @@ const AuthheroWidget = class {
912
925
  * actually in the DOM before measuring its height.
913
926
  */
914
927
  pendingRenderResolvers = [];
928
+ /**
929
+ * Number of `swapScreen` calls still running (rendering or animating the
930
+ * card height). A counter rather than a flag because a newer swap can start
931
+ * before a superseded one has settled.
932
+ */
933
+ activeSwaps = 0;
934
+ updateReadyAttribute() {
935
+ {
936
+ this.el.toggleAttribute("data-ready", !this.loading && this.activeSwaps === 0);
937
+ }
938
+ }
915
939
  componentDidRender() {
940
+ // `data-ready` marks the widget as interactive: hydrated in the browser
941
+ // (the SSR markup already carries Stencil's `hydrated` class, so that
942
+ // can't tell server and client apart) and not mid-submit or mid-swap.
943
+ // Stencil defers this hook until child nodes have rendered, so the
944
+ // fields are live too. E2E tests wait on `authhero-widget[data-ready]`.
945
+ this.updateReadyAttribute();
916
946
  if (this.pendingRenderResolvers.length === 0)
917
947
  return;
918
948
  const resolvers = this.pendingRenderResolvers;
@@ -960,6 +990,18 @@ const AuthheroWidget = class {
960
990
  apply();
961
991
  return;
962
992
  }
993
+ // Hold `data-ready` off until the new screen has rendered and the height
994
+ // animation has finished; `apply()` clears `loading` before either.
995
+ this.activeSwaps++;
996
+ try {
997
+ await this.animateSwap(card, apply);
998
+ }
999
+ finally {
1000
+ this.activeSwaps--;
1001
+ this.updateReadyAttribute();
1002
+ }
1003
+ }
1004
+ async animateSwap(card, apply) {
963
1005
  // Lock the current height and clip, so swapping the content doesn't jump
964
1006
  // before the animation runs.
965
1007
  const startHeight = card.getBoundingClientRect().height;
@@ -1124,6 +1166,9 @@ const AuthheroWidget = class {
1124
1166
  if (!this._authParams) {
1125
1167
  this.watchAuthParams(this.authParams ?? this.readJsonScript("auth-params"));
1126
1168
  }
1169
+ if (this._screen) {
1170
+ this.adoptPrehydrationValues(this._screen);
1171
+ }
1127
1172
  // Load persisted state if available
1128
1173
  this.loadPersistedState();
1129
1174
  // Fetch screen from API if URL provided and no screen prop
@@ -1131,6 +1176,41 @@ const AuthheroWidget = class {
1131
1176
  await this.fetchScreen(this.screenId);
1132
1177
  }
1133
1178
  }
1179
+ /**
1180
+ * Carry over text the user (or a password manager, or a test driver) put
1181
+ * into the server-rendered inputs before the client bundle loaded. Those
1182
+ * inputs had no `onInput` handler yet, so `formData` never saw the value:
1183
+ * the first client render would reset them to "" and keep the submit
1184
+ * button disabled. The declarative shadow roots are still the SSR ones
1185
+ * here — `componentWillLoad` runs before the first client render.
1186
+ */
1187
+ adoptPrehydrationValues(screen) {
1188
+ const root = this.el.shadowRoot;
1189
+ if (!root)
1190
+ return;
1191
+ const roots = [root];
1192
+ root.querySelectorAll("authhero-node").forEach((node) => {
1193
+ if (node.shadowRoot)
1194
+ roots.push(node.shadowRoot);
1195
+ });
1196
+ const adopted = {};
1197
+ for (const component of screen.components ?? []) {
1198
+ if (!PREHYDRATION_TEXT_TYPES.has(component.type))
1199
+ continue;
1200
+ for (const r of roots) {
1201
+ const input = Array.from(r.querySelectorAll("input[name]")).find((el) => el.name === component.id && el.type !== "hidden");
1202
+ // Adopt "" too: a prefilled default the user cleared before
1203
+ // hydration must not be restored by the client render.
1204
+ if (input) {
1205
+ adopted[component.id] = input.value;
1206
+ break;
1207
+ }
1208
+ }
1209
+ }
1210
+ if (Object.keys(adopted).length > 0) {
1211
+ this.formData = { ...this.formData, ...adopted };
1212
+ }
1213
+ }
1134
1214
  /**
1135
1215
  * Fetch screen configuration from the API
1136
1216
  * @param screenIdOverride Optional screen ID to fetch (overrides this.screenId)
@@ -1232,14 +1312,44 @@ const AuthheroWidget = class {
1232
1312
  e.preventDefault();
1233
1313
  if (!this._screen || this.loading)
1234
1314
  return;
1235
- let submitData = { ...this.formData, ...(overrideData || {}) };
1236
- // Merge hidden input values from DOM (may have been set programmatically
1237
- // by inline scripts, e.g. passkey management buttons)
1238
1315
  const form = this.el.shadowRoot?.querySelector("form");
1316
+ if (this._screen.partials &&
1317
+ form?.reportValidity &&
1318
+ !form.reportValidity()) {
1319
+ return;
1320
+ }
1321
+ const submitData = {
1322
+ ...this.formData,
1323
+ ...(overrideData || {}),
1324
+ };
1325
+ // Native fields in prompt partials are direct descendants of this form,
1326
+ // unlike authhero-node inputs in nested shadow roots. Read them through
1327
+ // FormData so standard HTML controls and successful-control semantics are
1328
+ // preserved (disabled controls are skipped, repeated names are kept as
1329
+ // arrays). FormData also covers enabled hidden inputs for ulp-* names.
1330
+ const nativeNames = new Set();
1331
+ if (form && this._screen.partials) {
1332
+ const nativeValues = {};
1333
+ new FormData(form).forEach((value, key) => {
1334
+ if (typeof value === "string" && key.startsWith("ulp-")) {
1335
+ (nativeValues[key] ??= []).push(value);
1336
+ }
1337
+ });
1338
+ for (const [key, values] of Object.entries(nativeValues)) {
1339
+ nativeNames.add(key);
1340
+ submitData[key] = values.length > 1 ? values : values[0];
1341
+ }
1342
+ }
1343
+ // Legacy behaviour for inline scripts that fill hidden inputs: merge
1344
+ // enabled ones, but never overwrite what FormData already collected.
1239
1345
  if (form) {
1240
- const hiddenInputs = form.querySelectorAll('input[type="hidden"]');
1241
- hiddenInputs.forEach((input) => {
1242
- if (input.name && input.value) {
1346
+ form
1347
+ .querySelectorAll('input[type="hidden"]')
1348
+ .forEach((input) => {
1349
+ if (input.name &&
1350
+ input.value &&
1351
+ !input.disabled &&
1352
+ !nativeNames.has(input.name)) {
1243
1353
  submitData[input.name] = input.value;
1244
1354
  }
1245
1355
  });
@@ -1393,6 +1503,11 @@ const AuthheroWidget = class {
1393
1503
  if (!form)
1394
1504
  return;
1395
1505
  form.submit = () => {
1506
+ if (this._screen?.partials &&
1507
+ form.reportValidity &&
1508
+ !form.reportValidity()) {
1509
+ return;
1510
+ }
1396
1511
  const formData = new FormData(form);
1397
1512
  const data = {};
1398
1513
  formData.forEach((value, key) => {
@@ -1997,6 +2112,27 @@ const AuthheroWidget = class {
1997
2112
  const config = component.config;
1998
2113
  return config?.text ?? "";
1999
2114
  }
2115
+ renderPromptPartial(screen, insertionPoint) {
2116
+ const html = screen.partials?.[insertionPoint];
2117
+ if (!html)
2118
+ return null;
2119
+ // Prompt partials intentionally contain tenant-authored form controls, so
2120
+ // the widget must keep their input attributes intact.
2121
+ return (index.h("div", { class: `prompt-partial prompt-partial-${insertionPoint}`, part: `prompt-partial prompt-partial-${insertionPoint}`, "data-insertion-point": insertionPoint, innerHTML: html }));
2122
+ }
2123
+ renderScreenLinks(screen) {
2124
+ if (!screen.links?.length)
2125
+ return null;
2126
+ return (index.h("div", { class: "links", part: "links" }, screen.links.map((link) => (index.h("span", { class: "link-wrapper", part: "link-wrapper", key: link.id ?? link.href }, link.linkText ? (index.h("span", null, link.text, " ", index.h("a", { href: link.href, class: "link", part: "link", onClick: (e) => this.handleLinkClick(e, {
2127
+ id: link.id,
2128
+ href: link.href,
2129
+ text: link.linkText || link.text,
2130
+ }) }, link.linkText))) : (index.h("a", { href: link.href, class: "link", part: "link", onClick: (e) => this.handleLinkClick(e, {
2131
+ id: link.id,
2132
+ href: link.href,
2133
+ text: link.text,
2134
+ }) }, link.text)))))));
2135
+ }
2000
2136
  render() {
2001
2137
  const screen = this._screen;
2002
2138
  if (this.loading && !screen) {
@@ -2023,13 +2159,20 @@ const AuthheroWidget = class {
2023
2159
  ? components.find((c) => this.isDividerComponent(c))
2024
2160
  : undefined;
2025
2161
  const fieldComponents = components.filter((c) => !this.isSocialComponent(c) && c !== dividerComponent);
2162
+ const hasPromptPartials = Object.values(screen.partials ?? {}).some((html) => !!html);
2163
+ const footerComponents = hasPromptPartials
2164
+ ? fieldComponents.filter((component) => component.id === "submit" && component.type === "NEXT_BUTTON")
2165
+ : [];
2166
+ const contentFieldComponents = hasPromptPartials
2167
+ ? fieldComponents.filter((component) => !footerComponents.includes(component))
2168
+ : fieldComponents;
2026
2169
  const hasDivider = !!dividerComponent;
2027
2170
  const dividerText = dividerComponent?.config?.text || "Or";
2028
2171
  // A "choice list" screen is one whose entire field section is pick-one
2029
2172
  // buttons (e.g. tenant selection). When the list is long, render it as a
2030
2173
  // searchable, scrollable list instead of a tall column of buttons.
2031
- const choiceButtons = fieldComponents.filter((c) => c.type === "NEXT_BUTTON");
2032
- const isSearchableChoiceList = choiceButtons.length === fieldComponents.length &&
2174
+ const choiceButtons = contentFieldComponents.filter((c) => c.type === "NEXT_BUTTON");
2175
+ const isSearchableChoiceList = choiceButtons.length === contentFieldComponents.length &&
2033
2176
  choiceButtons.length > CHOICE_LIST_SEARCH_THRESHOLD;
2034
2177
  // Hold the primary action button disabled until every required field has
2035
2178
  // a value.
@@ -2070,7 +2213,7 @@ const AuthheroWidget = class {
2070
2213
  };
2071
2214
  // Get logo URL from theme.widget (takes precedence) or branding
2072
2215
  const logoUrl = this._theme?.widget?.logo_url || this._branding?.logo_url;
2073
- return (index.h("div", { class: "widget-container", part: "container", "data-authstack-container": true }, index.h("header", { class: "widget-header", part: "header" }, logoUrl && (index.h("div", { class: "logo-wrapper", part: "logo-wrapper" }, index.h("img", { class: "logo", part: "logo", src: logoUrl, alt: "Logo" }))), screen.title && (index.h("h1", { class: "title", part: "title", innerHTML: sanitizeHtml(screen.title) })), screen.description && (index.h("p", { class: "description", part: "description", innerHTML: sanitizeHtml(screen.description) }))), index.h("div", { class: "widget-body", part: "body" }, screenErrors.map((err) => (index.h("div", { class: "message message-error", part: "message message-error", key: err.id ?? err.text }, err.text))), screenSuccesses.map((msg) => (index.h("div", { class: "message message-success", part: "message message-success", key: msg.id ?? msg.text }, msg.text))), index.h("form", { onSubmit: this.handleSubmit, action: screen.action, method: screen.method || "POST", part: "form" }, hiddenComponents.map((c) => (index.h("input", { type: "hidden", name: c.id, id: c.id, key: c.id, value: this.formData[c.id] || "" }))), index.h("div", { class: "form-content" }, socialComponents.length > 0 && (index.h("div", { class: "social-section", part: "social-section" }, socialComponents.map((component) => (index.h("authhero-node", { key: component.id, component: component, locale: this.locale, value: this.formData[component.id], onFieldChange: (e) => this.handleInputChange(e.detail.id, e.detail.value), onButtonClick: (e) => this.handleButtonClick(e.detail), disabled: this.loading, exportparts: getExportParts(component) }))))), socialComponents.length > 0 &&
2216
+ return (index.h("div", { class: "widget-container", part: "container", "data-authstack-container": true }, index.h("header", { class: "widget-header", part: "header" }, logoUrl && (index.h("div", { class: "logo-wrapper", part: "logo-wrapper" }, index.h("img", { class: "logo", part: "logo", src: logoUrl, alt: "Logo" }))), screen.title && (index.h("h1", { class: "title", part: "title", innerHTML: sanitizeHtml(screen.title) })), screen.description && (index.h("p", { class: "description", part: "description", innerHTML: sanitizeHtml(screen.description) }))), index.h("div", { class: "widget-body", part: "body" }, screenErrors.map((err) => (index.h("div", { class: "message message-error", part: "message message-error", key: err.id ?? err.text }, err.text))), screenSuccesses.map((msg) => (index.h("div", { class: "message message-success", part: "message message-success", key: msg.id ?? msg.text }, msg.text))), index.h("form", { onSubmit: this.handleSubmit, action: screen.action, method: screen.method || "POST", part: "form" }, hiddenComponents.map((c) => (index.h("input", { type: "hidden", name: c.id, id: c.id, key: c.id, value: this.formData[c.id] || "" }))), index.h("div", { class: "form-content" }, this.renderPromptPartial(screen, "form-content-start"), socialComponents.length > 0 && (index.h("div", { class: "social-section", part: "social-section" }, socialComponents.map((component) => (index.h("authhero-node", { key: component.id, component: component, locale: this.locale, value: this.formData[component.id], onFieldChange: (e) => this.handleInputChange(e.detail.id, e.detail.value), onButtonClick: (e) => this.handleButtonClick(e.detail), disabled: this.loading, exportparts: getExportParts(component) }))))), socialComponents.length > 0 &&
2074
2217
  fieldComponents.length > 0 &&
2075
2218
  hasDivider && (index.h("div", { class: "divider", part: "divider" }, index.h("span", { class: "divider-text" }, dividerText))), index.h("div", { class: "fields-section", part: "fields-section" }, isSearchableChoiceList && (index.h("input", { type: "text", class: "choice-list-search", part: "choice-list-search", placeholder: "Search", "aria-label": "Search", autocomplete: "off", value: this.listFilter, onInput: (e) => (this.listFilter = e.target.value), onKeyDown: (e) => {
2076
2219
  // The search box lives inside the form; Enter would
@@ -2083,19 +2226,14 @@ const AuthheroWidget = class {
2083
2226
  ? "fields-list fields-list-scroll"
2084
2227
  : "fields-list" }, (isSearchableChoiceList
2085
2228
  ? visibleChoiceButtons
2086
- : fieldComponents).map((component) => (index.h("authhero-node", { key: component.id, component: component, locale: this.locale, value: this.formData[component.id], onFieldChange: (e) => this.handleInputChange(e.detail.id, e.detail.value), onButtonClick: (e) => this.handleButtonClick(e.detail), disabled: this.loading ||
2229
+ : contentFieldComponents).map((component) => (index.h("authhero-node", { key: component.id, component: component, locale: this.locale, value: this.formData[component.id], onFieldChange: (e) => this.handleInputChange(e.detail.id, e.detail.value), onButtonClick: (e) => this.handleButtonClick(e.detail), disabled: this.loading ||
2087
2230
  (component.type === "NEXT_BUTTON" &&
2088
2231
  component.config?.skip_validation !== true &&
2089
2232
  requiredFieldsMissing) }))), isSearchableChoiceList &&
2090
- visibleChoiceButtons.length === 0 && (index.h("div", { class: "choice-list-empty", part: "choice-list-empty" }, "No matches")))))), screen.links && screen.links.length > 0 && (index.h("div", { class: "links", part: "links" }, screen.links.map((link) => (index.h("span", { class: "link-wrapper", part: "link-wrapper", key: link.id ?? link.href }, link.linkText ? (index.h("span", null, link.text, " ", index.h("a", { href: link.href, class: "link", part: "link", onClick: (e) => this.handleLinkClick(e, {
2091
- id: link.id,
2092
- href: link.href,
2093
- text: link.linkText || link.text,
2094
- }) }, link.linkText))) : (index.h("a", { href: link.href, class: "link", part: "link", onClick: (e) => this.handleLinkClick(e, {
2095
- id: link.id,
2096
- href: link.href,
2097
- text: link.text,
2098
- }) }, link.text))))))), screen.footer && (index.h("div", { class: "widget-footer", part: "footer", innerHTML: sanitizeHtml(screen.footer) })))));
2233
+ visibleChoiceButtons.length === 0 && (index.h("div", { class: "choice-list-empty", part: "choice-list-empty" }, "No matches")))), this.renderPromptPartial(screen, "form-content-end"), hasPromptPartials && (index.h("div", { class: "form-footer", part: "form-footer" }, this.renderPromptPartial(screen, "form-footer-start"), footerComponents.map((component) => (index.h("authhero-node", { key: component.id, component: component, locale: this.locale, value: this.formData[component.id], onFieldChange: (e) => this.handleInputChange(e.detail.id, e.detail.value), onButtonClick: (e) => this.handleButtonClick(e.detail), disabled: this.loading ||
2234
+ (component.type === "NEXT_BUTTON" &&
2235
+ component.config?.skip_validation !== true &&
2236
+ requiredFieldsMissing) }))), this.renderPromptPartial(screen, "form-footer-end")))), hasPromptPartials && (index.h("div", { class: "secondary-actions", part: "secondary-actions" }, this.renderPromptPartial(screen, "secondary-actions-start"), this.renderScreenLinks(screen), this.renderPromptPartial(screen, "secondary-actions-end")))), !hasPromptPartials && this.renderScreenLinks(screen), screen.footer && (index.h("div", { class: "widget-footer", part: "footer", innerHTML: sanitizeHtml(screen.footer) })))));
2099
2237
  }
2100
2238
  static get watchers() { return {
2101
2239
  "screenId": [{