@authhero/widget 0.32.42 → 0.34.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.
@@ -4,5 +4,5 @@
4
4
  * Re-exported from @authhero/adapter-interfaces for consistency.
5
5
  * @see https://auth0.com/docs/customize/forms/forms-schema
6
6
  */
7
- export type { ComponentMessage, FormNodeComponent as FormComponent, RuntimeComponent, BlockComponent, WidgetComponent, FieldComponent, DividerComponent, HtmlComponent, ImageComponent, JumpButtonComponent, ResendButtonComponent, NextButtonComponent, PreviousButtonComponent, RichTextComponent, VerifiableCredentialsWidget, GmapsAddressWidget, RecaptchaWidget, BooleanField, CardsField, ChoiceField, CountryField, CustomField, DateField, DropdownField, EmailField, FileField, LegalField, NumberField, PasswordField, PaymentField, SocialField, TelField, TextField, UrlField, ScreenLink, UiScreen, } from "@authhero/adapter-interfaces";
7
+ export type { ComponentMessage, FormNodeComponent as FormComponent, RuntimeComponent, BlockComponent, WidgetComponent, FieldComponent, DividerComponent, HtmlComponent, ImageComponent, JumpButtonComponent, ResendButtonComponent, NextButtonComponent, PreviousButtonComponent, RichTextComponent, VerifiableCredentialsWidget, GmapsAddressWidget, RecaptchaWidget, BooleanField, CardsField, ChoiceField, CodeField, CountryField, CustomField, DateField, DropdownField, EmailField, FileField, LegalField, NumberField, PasswordField, PaymentField, SocialField, TelField, TextField, UrlField, ScreenLink, UiScreen, } from "@authhero/adapter-interfaces";
8
8
  export { isBlockComponent, isWidgetComponent, isFieldComponent, } from "@authhero/adapter-interfaces";
package/hydrate/index.js CHANGED
@@ -5500,7 +5500,7 @@ function getCountryByCode(code) {
5500
5500
  countries.find((c) => c.code === "US"));
5501
5501
  }
5502
5502
 
5503
- const authheroNodeCss = () => `:host{display:block}.input-wrapper{display:flex;flex-direction:column;position:relative;margin-top:8px;margin-bottom:16px}.input-container{position:relative;width:100%}.input-label{position:absolute;left:16px;top:50%;transform:translateY(-50%);font-size:var(--ah-font-size-label, 16px);font-weight:var(--ah-font-weight-label, 400);color:var(--ah-color-text-muted, #65676e);pointer-events:none;transition:all 0.15s ease-out;background-color:transparent;padding:0;z-index:1}.input-label.floating,.input-field:focus+.input-label,.input-field:not(:placeholder-shown)+.input-label,select.input-field+.input-label,input[type="date"].input-field+.input-label{top:-8px;transform:translateY(0);font-size:12px;background-color:var(--ah-color-bg, #ffffff);padding:0 4px;left:12px;color:var(--ah-color-text-muted, #65676e)}.input-field:focus+.input-label{color:var(--ah-color-primary, #635dff)}.required{color:var(--ah-color-error, #d03c38);margin-left:2px}.input-field{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;transition:border-color 0.15s ease-out, box-shadow 0.15s ease-out;box-sizing:border-box}.input-field::placeholder{color:transparent}.input-field:hover{border-color:var(--ah-color-border-hover, #65676e)}.input-field:focus{border-color:var(--ah-color-primary, #635dff);box-shadow:inset 0 0 0 1px var(--ah-color-primary, #635dff)}.input-field.has-error{border-color:var(--ah-color-error, #d03c38)}.input-field.has-error:focus{box-shadow:inset 0 0 0 1px var(--ah-color-error, #d03c38)}.input-field:disabled{background-color:var(--ah-color-bg-disabled, #f5f5f5);border-color:var(--ah-color-border-disabled, #e0e1e3);cursor:not-allowed;opacity:0.7}.password-container{position:relative;display:flex;align-items:center}.password-container .input-field{padding-right:48px}.password-toggle{position:absolute;right:12px;top:50%;transform:translateY(-50%);background:none;border:none;cursor:pointer;padding:4px;display:flex;align-items:center;justify-content:center;color:var(--ah-color-icon, var(--ah-color-text-muted, #65676e));transition:color 0.15s ease}.password-toggle:hover{color:var(--ah-color-icon, var(--ah-color-text, #1e212a))}.password-toggle svg{width:20px;height:20px}.error-text{font-size:12px;color:var(--ah-color-error, #d03c38);margin-top:4px;line-height:1.4}.helper-text{font-size:12px;color:var(--ah-color-text-muted, #65676e);margin-top:4px;line-height:1.4}.field-link{display:block;text-align:left;margin-top:8px;margin-bottom:16px}.field-link a{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)}.field-link a:hover{text-decoration:underline}.checkbox-wrapper{display:flex;align-items:flex-start;gap:10px;cursor:pointer;margin-bottom:16px}.checkbox-wrapper input[type="checkbox"]{width:18px;height:18px;margin:0;accent-color:var(--ah-color-primary, #635dff);cursor:pointer;flex-shrink:0}.checkbox-label{font-size:var(--ah-font-size-body, 14px);font-weight:var(--ah-font-weight-body, 400);color:var(--ah-color-text, #1e212a);line-height:1.5}.btn{display:inline-flex;align-items:center;justify-content:center;gap:10px;width:100%;padding:14px 20px;font-size:var(--ah-font-size-btn, 16px);font-weight:var(--ah-font-weight-btn, 400);font-family:inherit;line-height:1.25;text-align:center;text-decoration:none;border:none;border-radius:var(--ah-btn-radius, 3px);cursor:pointer;transition:background-color 0.15s ease, border-color 0.15s ease, transform 0.1s ease;box-sizing:border-box}.btn:disabled{opacity:0.6;cursor:not-allowed}.btn:not(:disabled):active{transform:scale(0.98)}.btn:focus-visible{outline:2px solid var(--ah-color-focus-ring, var(--ah-color-primary, #635dff));outline-offset:2px}.btn-primary{background-color:var(--ah-color-primary, #635dff);color:var(--ah-color-text-on-primary, #ffffff);margin-top:12px}.btn-primary:not(:disabled):hover{background-color:var(--ah-color-primary-hover, color-mix(in srgb, var(--ah-color-primary, #635dff) 85%, black))}.btn-secondary{background-color:var(--ah-color-bg, #ffffff);color:var(--ah-btn-secondary-text, var(--ah-color-text, #1e212a));border:var(--ah-btn-border-width, 1px) solid var(--ah-btn-secondary-border, var(--ah-color-border, #c9cace))}.btn-secondary:not(:disabled):hover{background-color:var(--ah-color-bg-hover, #f5f5f5);border-color:var(--ah-color-border-hover, #65676e)}.btn-link{background:none;border:none;color:var(--ah-color-link, #635dff);padding:8px 0;font-weight:var(--ah-font-weight-link, 400);text-decoration:none}.btn-link:hover{text-decoration:underline}.phone-input-wrapper{display:flex;align-items:stretch;gap:0;width:100%}.country-select{flex-shrink:0;width:auto;padding:12px 8px;font-size:var(--ah-font-size-body, 16px);font-family:var(--ah-font-family, inherit);border:var(--ah-input-border-width, 1px) solid var(--ah-color-border, #c9cace);border-right:none;border-radius:var(--ah-input-radius, 4px) 0 0 var(--ah-input-radius, 4px);background-color:var(--ah-color-input-bg, var(--ah-color-surface, #fff));color:var(--ah-color-input-text, var(--ah-color-text, #1e212a));cursor:pointer;appearance:none;-webkit-appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 6px center;padding-right:22px}.country-select:focus{outline:none;border-color:var(--ah-color-primary, #635dff);box-shadow:0 0 0 1px var(--ah-color-primary, #635dff)}.country-select:disabled{opacity:0.5;cursor:not-allowed}.phone-input-wrapper .input-container{flex:1;min-width:0}.phone-input-wrapper .input-field{border-radius:0 var(--ah-input-radius, 4px) var(--ah-input-radius, 4px) 0}.phone-input-wrapper .input-label.floating,.phone-input-wrapper .input-field:focus+.input-label,.phone-input-wrapper .input-field:not(:placeholder-shown)+.input-label{left:8px}.social-buttons{display:flex;flex-direction:column;gap:12px}.btn-social{display:flex;align-items:center;justify-content:center;gap:12px}.btn-social-content{display:flex;flex-direction:column;align-items:center;text-align:center}.btn-social-subtitle{font-size:12px;font-style:italic;opacity:0.8;margin-top:2px}.btn-social-subtitle:empty{display:none}.social-icon{width:20px;height:20px;flex-shrink:0}@media (max-width: 480px){.social-buttons:has(.btn-social:nth-child(3)){flex-direction:row;flex-wrap:nowrap;justify-content:stretch;gap:8px}.social-buttons:has(.btn-social:nth-child(3)) .btn-social{width:auto;min-width:0;padding:12px;flex:1 1 0}.social-buttons:has(.btn-social:nth-child(3)) .btn-social span{display:none}.social-buttons:has(.btn-social:nth-child(3)) .social-icon{width:24px;height:24px}}.btn-icon{width:20px;height:20px;flex-shrink:0}.btn-icon img{width:100%;height:100%;object-fit:contain}.text-title{font-size:var(--ah-font-size-title, 20px);font-weight:var(--ah-font-weight-title, 400);color:var(--ah-color-text-header, var(--ah-color-header, #1e212a));margin:8px 0;line-height:1.3}.text-title.text-success{color:var(--ah-color-success, #13a769)}.text-description{font-size:var(--ah-font-size-subtitle, 14px);font-weight:var(--ah-font-weight-subtitle, 400);color:var(--ah-color-text-muted, #65676e);margin:4px 0;line-height:1.5}.image{display:block;max-width:100%;height:auto;border-radius:4px}.image-centered{margin:0 auto 16px;width:52px;height:52px;object-fit:contain}.link{color:var(--ah-color-link, #635dff);text-decoration:var(--ah-link-decoration, none);font-size:var(--ah-font-size-link, 14px);transition:color 0.15s 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}.node-error{padding:12px 16px;background-color:var(--ah-color-error-bg, #ffeaea);color:var(--ah-color-error, #d03c38);border-left:3px solid var(--ah-color-error, #d03c38);border-radius:0;font-size:14px;margin-bottom:16px}.node-success{padding:12px 16px;background-color:var(--ah-color-success-bg, #e6f9f1);color:var(--ah-color-success, #13a769);border-left:3px solid var(--ah-color-success, #13a769);border-radius:0;font-size:14px;margin-bottom:16px}.divider{display:flex;align-items:center;text-align:center;margin:16px 0}.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.5px}.rich-text{font-size:var(--ah-font-size-body, 14px);font-weight:var(--ah-font-weight-body, 400);line-height:1.5;color:var(--ah-color-text, #1e212a)}.rich-text a{color:var(--ah-color-link, #635dff);text-decoration:var(--ah-link-decoration, none);transition:color 0.15s ease}.rich-text a:hover{text-decoration:underline}.rich-text .terms-text{margin-top:16px;text-align:center;font-size:12px;color:var(--ah-color-text-muted, #65676e)}.rich-text .terms-text a{font-size:12px}.rich-text .forgot-password-link{text-align:right;font-size:13px;margin-top:4px}.rich-text .forgot-password-link a{font-size:13px;color:var(--ah-color-link, #635dff)}.rich-text .passwordless-link{margin-top:16px;text-align:center;font-size:14px}.rich-text .passwordless-link a{color:var(--ah-color-link, #635dff);text-decoration:var(--ah-link-decoration, none)}.rich-text .passwordless-link a:hover{text-decoration:underline}.rich-text .signup-link{margin-top:16px;text-align:center;font-size:14px;color:var(--ah-color-text, #1e212a)}`;
5503
+ const authheroNodeCss = () => `:host{display:block}.input-wrapper{display:flex;flex-direction:column;position:relative;margin-top:8px;margin-bottom:16px}.input-container{position:relative;width:100%}.input-label{position:absolute;left:16px;top:50%;transform:translateY(-50%);font-size:var(--ah-font-size-label, 16px);font-weight:var(--ah-font-weight-label, 400);color:var(--ah-color-text-muted, #65676e);pointer-events:none;transition:all 0.15s ease-out;background-color:transparent;padding:0;z-index:1}.input-label.floating,.input-field:focus+.input-label,.input-field:not(:placeholder-shown)+.input-label,select.input-field+.input-label,input[type="date"].input-field+.input-label{top:-8px;transform:translateY(0);font-size:12px;background-color:var(--ah-color-bg, #ffffff);padding:0 4px;left:12px;color:var(--ah-color-text-muted, #65676e)}.input-field:focus+.input-label{color:var(--ah-color-primary, #635dff)}.required{color:var(--ah-color-error, #d03c38);margin-left:2px}.input-field{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;transition:border-color 0.15s ease-out, box-shadow 0.15s ease-out;box-sizing:border-box}.input-field::placeholder{color:transparent}.input-field:hover{border-color:var(--ah-color-border-hover, #65676e)}.input-field:focus{border-color:var(--ah-color-primary, #635dff);box-shadow:inset 0 0 0 1px var(--ah-color-primary, #635dff)}.input-field.has-error{border-color:var(--ah-color-error, #d03c38)}.input-field.has-error:focus{box-shadow:inset 0 0 0 1px var(--ah-color-error, #d03c38)}.input-field:disabled{background-color:var(--ah-color-bg-disabled, #f5f5f5);border-color:var(--ah-color-border-disabled, #e0e1e3);cursor:not-allowed;opacity:0.7}.password-container{position:relative;display:flex;align-items:center}.password-container .input-field{padding-right:48px}.password-toggle{position:absolute;right:12px;top:50%;transform:translateY(-50%);background:none;border:none;cursor:pointer;padding:4px;display:flex;align-items:center;justify-content:center;color:var(--ah-color-icon, var(--ah-color-text-muted, #65676e));transition:color 0.15s ease}.password-toggle:hover{color:var(--ah-color-icon, var(--ah-color-text, #1e212a))}.password-toggle svg{width:20px;height:20px}.error-text{font-size:12px;color:var(--ah-color-error, #d03c38);margin-top:4px;line-height:1.4}.helper-text{font-size:12px;color:var(--ah-color-text-muted, #65676e);margin-top:4px;line-height:1.4}.field-link{display:block;text-align:left;margin-top:8px;margin-bottom:16px}.field-link a{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)}.field-link a:hover{text-decoration:underline}.checkbox-wrapper{display:flex;align-items:flex-start;gap:10px;cursor:pointer;margin-bottom:16px}.checkbox-wrapper input[type="checkbox"]{width:18px;height:18px;margin:0;accent-color:var(--ah-color-primary, #635dff);cursor:pointer;flex-shrink:0}.checkbox-label{font-size:var(--ah-font-size-body, 14px);font-weight:var(--ah-font-weight-body, 400);color:var(--ah-color-text, #1e212a);line-height:1.5}.btn{display:inline-flex;align-items:center;justify-content:center;gap:10px;width:100%;padding:14px 20px;font-size:var(--ah-font-size-btn, 16px);font-weight:var(--ah-font-weight-btn, 400);font-family:inherit;line-height:1.25;text-align:center;text-decoration:none;border:none;border-radius:var(--ah-btn-radius, 3px);cursor:pointer;transition:background-color 0.15s ease, border-color 0.15s ease, transform 0.1s ease;box-sizing:border-box}.btn:disabled{opacity:0.6;cursor:not-allowed}.btn:not(:disabled):active{transform:scale(0.98)}.btn:focus-visible{outline:2px solid var(--ah-color-focus-ring, var(--ah-color-primary, #635dff));outline-offset:2px}.btn-primary{background-color:var(--ah-color-primary, #635dff);color:var(--ah-color-text-on-primary, #ffffff);margin-top:12px}.btn-primary:not(:disabled):hover{background-color:var(--ah-color-primary-hover, color-mix(in srgb, var(--ah-color-primary, #635dff) 85%, black))}.btn-secondary{background-color:var(--ah-color-bg, #ffffff);color:var(--ah-btn-secondary-text, var(--ah-color-text, #1e212a));border:var(--ah-btn-border-width, 1px) solid var(--ah-btn-secondary-border, var(--ah-color-border, #c9cace))}.btn-secondary:not(:disabled):hover{background-color:var(--ah-color-bg-hover, #f5f5f5);border-color:var(--ah-color-border-hover, #65676e)}.btn-link{background:none;border:none;color:var(--ah-color-link, #635dff);padding:8px 0;font-weight:var(--ah-font-weight-link, 400);text-decoration:none}.btn-link:hover{text-decoration:underline}.phone-input-wrapper{display:flex;align-items:stretch;gap:0;width:100%}.country-select{flex-shrink:0;width:auto;padding:12px 8px;font-size:var(--ah-font-size-body, 16px);font-family:var(--ah-font-family, inherit);border:var(--ah-input-border-width, 1px) solid var(--ah-color-border, #c9cace);border-right:none;border-radius:var(--ah-input-radius, 4px) 0 0 var(--ah-input-radius, 4px);background-color:var(--ah-color-input-bg, var(--ah-color-surface, #fff));color:var(--ah-color-input-text, var(--ah-color-text, #1e212a));cursor:pointer;appearance:none;-webkit-appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 6px center;padding-right:22px}.country-select:focus{outline:none;border-color:var(--ah-color-primary, #635dff);box-shadow:0 0 0 1px var(--ah-color-primary, #635dff)}.country-select:disabled{opacity:0.5;cursor:not-allowed}.phone-input-wrapper .input-container{flex:1;min-width:0}.phone-input-wrapper .input-field{border-radius:0 var(--ah-input-radius, 4px) var(--ah-input-radius, 4px) 0}.phone-input-wrapper .input-label.floating,.phone-input-wrapper .input-field:focus+.input-label,.phone-input-wrapper .input-field:not(:placeholder-shown)+.input-label{left:8px}.social-buttons{display:flex;flex-direction:column;gap:12px}.btn-social{display:flex;align-items:center;justify-content:center;gap:12px}.btn-social-content{display:flex;flex-direction:column;align-items:center;text-align:center}.btn-social-subtitle{font-size:12px;font-style:italic;opacity:0.8;margin-top:2px}.btn-social-subtitle:empty{display:none}.social-icon{width:20px;height:20px;flex-shrink:0}@media (max-width: 480px){.social-buttons:has(.btn-social:nth-child(3)){flex-direction:row;flex-wrap:nowrap;justify-content:stretch;gap:8px}.social-buttons:has(.btn-social:nth-child(3)) .btn-social{width:auto;min-width:0;padding:12px;flex:1 1 0}.social-buttons:has(.btn-social:nth-child(3)) .btn-social span{display:none}.social-buttons:has(.btn-social:nth-child(3)) .social-icon{width:24px;height:24px}}.btn-icon{width:20px;height:20px;flex-shrink:0}.btn-icon img{width:100%;height:100%;object-fit:contain}.text-title{font-size:var(--ah-font-size-title, 20px);font-weight:var(--ah-font-weight-title, 400);color:var(--ah-color-text-header, var(--ah-color-header, #1e212a));margin:8px 0;line-height:1.3}.text-title.text-success{color:var(--ah-color-success, #13a769)}.text-description{font-size:var(--ah-font-size-subtitle, 14px);font-weight:var(--ah-font-weight-subtitle, 400);color:var(--ah-color-text-muted, #65676e);margin:4px 0;line-height:1.5}.image{display:block;max-width:100%;height:auto;border-radius:4px}.image-centered{margin:0 auto 16px;width:52px;height:52px;object-fit:contain}.link{color:var(--ah-color-link, #635dff);text-decoration:var(--ah-link-decoration, none);font-size:var(--ah-font-size-link, 14px);transition:color 0.15s 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}.node-error{padding:12px 16px;background-color:var(--ah-color-error-bg, #ffeaea);color:var(--ah-color-error, #d03c38);border-left:3px solid var(--ah-color-error, #d03c38);border-radius:0;font-size:14px;margin-bottom:16px}.node-success{padding:12px 16px;background-color:var(--ah-color-success-bg, #e6f9f1);color:var(--ah-color-success, #13a769);border-left:3px solid var(--ah-color-success, #13a769);border-radius:0;font-size:14px;margin-bottom:16px}.divider{display:flex;align-items:center;text-align:center;margin:16px 0}.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.5px}.rich-text{font-size:var(--ah-font-size-body, 14px);font-weight:var(--ah-font-weight-body, 400);line-height:1.5;color:var(--ah-color-text, #1e212a)}.rich-text a{color:var(--ah-color-link, #635dff);text-decoration:var(--ah-link-decoration, none);transition:color 0.15s ease}.rich-text a:hover{text-decoration:underline}.rich-text .terms-text{margin-top:16px;text-align:center;font-size:12px;color:var(--ah-color-text-muted, #65676e)}.rich-text .terms-text a{font-size:12px}.rich-text .forgot-password-link{text-align:right;font-size:13px;margin-top:4px}.rich-text .forgot-password-link a{font-size:13px;color:var(--ah-color-link, #635dff)}.rich-text .passwordless-link{margin-top:16px;text-align:center;font-size:14px}.rich-text .passwordless-link a{color:var(--ah-color-link, #635dff);text-decoration:var(--ah-link-decoration, none)}.rich-text .passwordless-link a:hover{text-decoration:underline}.rich-text .signup-link{margin-top:16px;text-align:center;font-size:14px;color:var(--ah-color-text, #1e212a)}.code-field{position:relative}.code-input{position:absolute;inset:0;width:100%;height:100%;margin:0;padding:0;border:none;background:transparent;color:transparent;caret-color:transparent;font-family:inherit;letter-spacing:0;outline:none;cursor:text;-webkit-text-fill-color:transparent}.code-boxes{display:flex;align-items:center;gap:var(--ah-code-group-gap, 12px);justify-content:center}.code-group{display:flex;gap:0}.code-separator{color:var(--ah-color-text-muted, #65676e);font-size:var(--ah-code-font-size, 24px);user-select:none}.code-box-placeholder{color:var(--ah-color-text-muted, #65676e);opacity:0.4}.code-box{position:relative;flex:0 0 auto;width:var(--ah-code-box-width, 48px);height:var(--ah-code-box-height, 56px);display:flex;align-items:center;justify-content:center;font-size:var(--ah-code-font-size, 24px);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:0;transition:border-color 0.15s ease-out, box-shadow 0.15s ease-out;box-sizing:border-box}.code-box+.code-box{margin-left:calc(-1 * var(--ah-input-border-width, 1px))}.code-group .code-box:first-child{border-top-left-radius:var(--ah-input-radius, 3px);border-bottom-left-radius:var(--ah-input-radius, 3px)}.code-group .code-box:last-child{border-top-right-radius:var(--ah-input-radius, 3px);border-bottom-right-radius:var(--ah-input-radius, 3px)}.code-field:focus-within .code-box.is-active{z-index:1;border-color:var(--ah-color-primary, #635dff);box-shadow:inset 0 0 0 1px var(--ah-color-primary, #635dff)}.code-field.has-error .code-box{border-color:var(--ah-color-error, #d03c38)}.code-input:disabled{cursor:not-allowed}.code-input:disabled~.code-boxes .code-box{background-color:var(--ah-color-bg-disabled, #f5f5f5);border-color:var(--ah-color-border-disabled, #e0e1e3)}`;
5504
5504
 
5505
5505
  class AuthheroNode {
5506
5506
  constructor(hostRef) {
@@ -5508,10 +5508,7 @@ class AuthheroNode {
5508
5508
  this.fieldChange = createEvent(this, "fieldChange");
5509
5509
  this.buttonClick = createEvent(this, "buttonClick");
5510
5510
  }
5511
- /**
5512
- * The component configuration to render.
5513
- * Follows Auth0 Forms component schema.
5514
- */
5511
+ get host() { return getElement(this); }
5515
5512
  component;
5516
5513
  /**
5517
5514
  * Current value for field components.
@@ -5561,6 +5558,16 @@ class AuthheroNode {
5561
5558
  this.initCountryFromConfig();
5562
5559
  this.initTelValue();
5563
5560
  }
5561
+ componentDidLoad() {
5562
+ // Auto-focus a code field so the caret starts in the first (leftmost) box.
5563
+ if (this.component?.type === "CODE" && !this.disabled) {
5564
+ const value = this.getEffectiveValue() ?? "";
5565
+ if (value.length === 0) {
5566
+ const input = this.host.shadowRoot?.querySelector("input.code-input");
5567
+ input?.focus();
5568
+ }
5569
+ }
5570
+ }
5564
5571
  initCountryFromConfig() {
5565
5572
  if (this.component?.type === "TEL") {
5566
5573
  const config = this.component.config;
@@ -5719,6 +5726,20 @@ class AuthheroNode {
5719
5726
  }
5720
5727
  }
5721
5728
  };
5729
+ handleCodeInput = (e, length, mode, autoSubmit) => {
5730
+ const target = e.target;
5731
+ const disallowed = mode === "alphanumeric" ? /[^a-zA-Z0-9]/g : /\D/g;
5732
+ const cleaned = target.value.replace(disallowed, "").slice(0, length);
5733
+ // Reflect the sanitized value back so the visible boxes never show
5734
+ // characters we stripped (e.g. a pasted "123-456").
5735
+ if (cleaned !== target.value) {
5736
+ target.value = cleaned;
5737
+ }
5738
+ this.fieldChange.emit({ id: this.component.id, value: cleaned });
5739
+ if (autoSubmit && cleaned.length === length) {
5740
+ this.buttonClick.emit({ id: "submit", type: "submit", value: "next" });
5741
+ }
5742
+ };
5722
5743
  handleCheckbox = (e) => {
5723
5744
  const target = e.target;
5724
5745
  this.fieldChange.emit({
@@ -5865,6 +5886,60 @@ class AuthheroNode {
5865
5886
  }
5866
5887
  return (hAsync("div", { class: "input-wrapper", part: "input-wrapper" }, hAsync("div", { class: "input-container" }, hAsync("input", { id: inputId, class: this.getInputFieldClass(errors.length > 0), part: "input", type: component.sensitive ? "password" : "text", name: component.id, "data-input-name": component.id, value: effectiveValue ?? "", placeholder: " ", required: component.required, disabled: this.disabled, maxLength: max_length, autoComplete: autocomplete, onInput: this.handleInput, onKeyDown: this.handleKeyDown }), this.renderFloatingLabel(component.label, inputId, component.required, hasValue)), this.renderErrors(), errors.length === 0 && this.renderHint(component.hint)));
5867
5888
  }
5889
+ /**
5890
+ * Segmented one-time-code input (e.g. SMS/email verification codes).
5891
+ *
5892
+ * Rendered as a SINGLE real <input> overlaid (transparent) on a row of
5893
+ * presentational boxes. This keeps native paste, iOS/Android SMS autofill
5894
+ * (`autocomplete="one-time-code"`) and screen-reader behaviour working —
5895
+ * all of which break when using one <input> per digit.
5896
+ */
5897
+ renderCodeField(component) {
5898
+ const inputId = `input-${component.id}`;
5899
+ const errors = this.getErrors();
5900
+ const hasError = errors.length > 0;
5901
+ const config = (component.config ?? {});
5902
+ const length = config.length ?? 6;
5903
+ const mode = config.mode ?? "numeric";
5904
+ const autoSubmit = config.auto_submit !== false;
5905
+ const groupSize = config.group_size ?? 3;
5906
+ const separator = config.separator ?? "-";
5907
+ const placeholder = config.placeholder;
5908
+ // Apply the same mode sanitization used on input (handleCodeInput) so a
5909
+ // persisted/default value with invalid characters (e.g. "12-3a" in numeric
5910
+ // mode) doesn't render until edited.
5911
+ const disallowed = mode === "alphanumeric" ? /[^a-zA-Z0-9]/g : /\D/g;
5912
+ const value = (this.getEffectiveValue() ?? "")
5913
+ .replace(disallowed, "")
5914
+ .slice(0, length);
5915
+ const boxClass = (i) => {
5916
+ let cls = "code-box";
5917
+ if (i < value.length)
5918
+ cls += " is-filled";
5919
+ // Highlight the next empty box as the "caret" position while focused.
5920
+ if (!this.disabled && i === value.length)
5921
+ cls += " is-active";
5922
+ return cls;
5923
+ };
5924
+ const renderBox = (i) => (hAsync("div", { class: boxClass(i), part: "code-box" }, value[i] ??
5925
+ (placeholder ? (hAsync("span", { class: "code-box-placeholder" }, placeholder)) : (""))));
5926
+ // Split into groups of `groupSize` (e.g. 3 → "123 - 456"); a non-positive
5927
+ // or >= length size means a single ungrouped row.
5928
+ const useGroups = groupSize > 0 && groupSize < length;
5929
+ const groups = [];
5930
+ if (useGroups) {
5931
+ for (let start = 0; start < length; start += groupSize) {
5932
+ groups.push(Array.from({ length: Math.min(groupSize, length - start) }, (_, j) => start + j));
5933
+ }
5934
+ }
5935
+ else {
5936
+ groups.push(Array.from({ length }, (_, i) => i));
5937
+ }
5938
+ return (hAsync("div", { class: "input-wrapper", part: "input-wrapper" }, hAsync("div", { class: hasError ? "code-field has-error" : "code-field", part: "code-field" }, hAsync("input", { id: inputId, class: "code-input", part: "input code-input", type: "text", name: component.id, "data-input-name": component.id, value: value, inputMode: mode === "numeric" ? "numeric" : "text", autoComplete: "one-time-code", autoCapitalize: "off", autoCorrect: "off", spellcheck: false, maxLength: length, required: component.required, disabled: this.disabled, "aria-label": component.label, "aria-invalid": hasError ? "true" : "false", onInput: (e) => this.handleCodeInput(e, length, mode, autoSubmit), onKeyDown: this.handleKeyDown }), hAsync("div", { class: "code-boxes", part: "code-boxes", "aria-hidden": "true" }, groups.map((group, gi) => [
5939
+ gi > 0 && separator ? (hAsync("span", { class: "code-separator", part: "code-separator" }, separator)) : null,
5940
+ hAsync("div", { class: "code-group", part: "code-group" }, group.map((i) => renderBox(i))),
5941
+ ]))), this.renderErrors(), errors.length === 0 && this.renderHint(component.hint)));
5942
+ }
5868
5943
  renderEmailField(component) {
5869
5944
  const inputId = `input-${component.id}`;
5870
5945
  const errors = this.getErrors();
@@ -6037,6 +6112,8 @@ class AuthheroNode {
6037
6112
  return this.renderTextField(this.component);
6038
6113
  case "EMAIL":
6039
6114
  return this.renderEmailField(this.component);
6115
+ case "CODE":
6116
+ return this.renderCodeField(this.component);
6040
6117
  case "PASSWORD":
6041
6118
  return this.renderPasswordField(this.component);
6042
6119
  case "NUMBER":
@@ -6958,6 +7035,94 @@ class AuthheroWidget {
6958
7035
  }
6959
7036
  });
6960
7037
  }
7038
+ /**
7039
+ * Pending resolvers awaiting the next render, flushed by
7040
+ * `componentDidRender`. Lets `swapScreen` wait until the new screen is
7041
+ * actually in the DOM before measuring its height.
7042
+ */
7043
+ pendingRenderResolvers = [];
7044
+ componentDidRender() {
7045
+ if (this.pendingRenderResolvers.length === 0)
7046
+ return;
7047
+ const resolvers = this.pendingRenderResolvers;
7048
+ this.pendingRenderResolvers = [];
7049
+ resolvers.forEach((resolve) => resolve());
7050
+ }
7051
+ /**
7052
+ * Resolves after Stencil flushes the next render, so `swapScreen` waits for
7053
+ * the new screen to be in the DOM before measuring its height.
7054
+ */
7055
+ nextRender() {
7056
+ return new Promise((resolve) => {
7057
+ let settled = false;
7058
+ const done = () => {
7059
+ if (settled)
7060
+ return;
7061
+ settled = true;
7062
+ resolve();
7063
+ };
7064
+ this.pendingRenderResolvers.push(done);
7065
+ // Safety net: a screen swap always triggers a render here, but never
7066
+ // hang the swap if one somehow doesn't fire — resolve after a couple of
7067
+ // frames at the latest.
7068
+ requestAnimationFrame(() => requestAnimationFrame(done));
7069
+ });
7070
+ }
7071
+ /**
7072
+ * Apply a screen swap, animating the widget card's height to the next
7073
+ * screen's size (Stripe-style): lock the current height, swap the content,
7074
+ * measure the new natural height, then animate between them. The content
7075
+ * itself doesn't fade — the card just resizes.
7076
+ *
7077
+ * The card (.widget-container) is animated rather than the host because it
7078
+ * carries the background, so its resize is visible; clipping its content
7079
+ * (not the host) also keeps the card's drop-shadow intact.
7080
+ *
7081
+ * Degrades to an immediate swap when the Web Animations API is unavailable
7082
+ * or the user prefers reduced motion.
7083
+ */
7084
+ async swapScreen(apply) {
7085
+ const card = this.el.shadowRoot?.querySelector(".widget-container");
7086
+ const prefersReducedMotion = typeof window.matchMedia === "function" &&
7087
+ window.matchMedia("(prefers-reduced-motion: reduce)").matches;
7088
+ if (!card || typeof card.animate !== "function" || prefersReducedMotion) {
7089
+ apply();
7090
+ return;
7091
+ }
7092
+ // Lock the current height and clip, so swapping the content doesn't jump
7093
+ // before the animation runs.
7094
+ const startHeight = card.getBoundingClientRect().height;
7095
+ card.style.height = `${startHeight}px`;
7096
+ card.style.overflow = "hidden";
7097
+ apply();
7098
+ // Wait for the new screen to render before measuring its height.
7099
+ await this.nextRender();
7100
+ const cleanup = () => {
7101
+ card.style.height = "";
7102
+ card.style.overflow = "";
7103
+ };
7104
+ // Measure the new content's natural height without painting: toggle to
7105
+ // auto, read, restore — all synchronous, so there's no visible jump.
7106
+ card.style.height = "auto";
7107
+ const endHeight = card.getBoundingClientRect().height;
7108
+ card.style.height = `${startHeight}px`;
7109
+ card.getBoundingClientRect(); // force reflow from startHeight
7110
+ if (Math.abs(endHeight - startHeight) < 1) {
7111
+ cleanup();
7112
+ return;
7113
+ }
7114
+ const animation = card.animate([{ height: `${startHeight}px` }, { height: `${endHeight}px` }], { duration: 520, easing: "cubic-bezier(0.22, 1, 0.36, 1)" });
7115
+ try {
7116
+ await animation.finished;
7117
+ }
7118
+ catch {
7119
+ // Animation cancelled (e.g. superseded by a newer swap); the final
7120
+ // DOM state is already correct, so just fall through to cleanup.
7121
+ }
7122
+ finally {
7123
+ cleanup();
7124
+ }
7125
+ }
6961
7126
  /**
6962
7127
  * Get the effective autoNavigate value (defaults to autoSubmit if not set)
6963
7128
  */
@@ -7260,45 +7425,55 @@ class AuthheroWidget {
7260
7425
  }
7261
7426
  else if (!response.ok && result.screen) {
7262
7427
  // Handle validation errors (400 response) — preserve user input
7263
- this._screen = result.screen;
7264
- this.initFormDataFromDefaults(result.screen);
7265
- this.screenChange.emit(result.screen);
7266
- this.updateDataScreenAttribute();
7267
- this.focusFirstInput();
7428
+ await this.swapScreen(() => {
7429
+ // Clear loading first so the captured "after" snapshot doesn't
7430
+ // freeze a disabled button into the cross-fade.
7431
+ this.loading = false;
7432
+ this._screen = result.screen;
7433
+ this.initFormDataFromDefaults(result.screen);
7434
+ this.screenChange.emit(result.screen);
7435
+ this.updateDataScreenAttribute();
7436
+ this.focusFirstInput();
7437
+ });
7268
7438
  }
7269
7439
  else if (result.screen) {
7270
7440
  // Next screen (success)
7271
- this._screen = result.screen;
7272
- this.formData = {};
7273
- this.initFormDataFromDefaults(result.screen);
7274
- this.screenChange.emit(result.screen);
7275
- this.updateDataScreenAttribute();
7276
- // Update screenId if returned in response
7277
- if (result.screenId) {
7278
- this.screenId = result.screenId;
7279
- }
7280
- // Persist state (especially for session storage mode)
7281
- this.persistState();
7282
- // Update URL path if navigateUrl is provided (client-side navigation)
7283
- if (result.navigateUrl && this.shouldAutoNavigate) {
7284
- window.history.pushState({ screen: result.screenId, state: this.state }, "", result.navigateUrl);
7285
- }
7286
- // Apply branding if included
7287
- if (result.branding) {
7288
- this._branding = result.branding;
7289
- this.applyThemeStyles();
7290
- }
7291
- // Update state if returned
7292
- if (result.state) {
7293
- this.state = result.state;
7441
+ await this.swapScreen(() => {
7442
+ // Clear loading first so the captured "after" snapshot doesn't
7443
+ // freeze a disabled button into the cross-fade.
7444
+ this.loading = false;
7445
+ this._screen = result.screen;
7446
+ this.formData = {};
7447
+ this.initFormDataFromDefaults(result.screen);
7448
+ this.screenChange.emit(result.screen);
7449
+ this.updateDataScreenAttribute();
7450
+ // Update screenId if returned in response
7451
+ if (result.screenId) {
7452
+ this.screenId = result.screenId;
7453
+ }
7454
+ // Persist state (especially for session storage mode)
7294
7455
  this.persistState();
7295
- }
7296
- // Perform WebAuthn ceremony if present (structured data, not script)
7297
- if (result.ceremony) {
7298
- this.performWebAuthnCeremony(result.ceremony);
7299
- }
7300
- // Focus first input on new screen
7301
- this.focusFirstInput();
7456
+ // Update URL path if navigateUrl is provided (client-side navigation)
7457
+ if (result.navigateUrl && this.shouldAutoNavigate) {
7458
+ window.history.pushState({ screen: result.screenId, state: this.state }, "", result.navigateUrl);
7459
+ }
7460
+ // Apply branding if included
7461
+ if (result.branding) {
7462
+ this._branding = result.branding;
7463
+ this.applyThemeStyles();
7464
+ }
7465
+ // Update state if returned
7466
+ if (result.state) {
7467
+ this.state = result.state;
7468
+ this.persistState();
7469
+ }
7470
+ // Perform WebAuthn ceremony if present (structured data, not script)
7471
+ if (result.ceremony) {
7472
+ this.performWebAuthnCeremony(result.ceremony);
7473
+ }
7474
+ // Focus first input on new screen
7475
+ this.focusFirstInput();
7476
+ });
7302
7477
  }
7303
7478
  else if (result.complete) {
7304
7479
  // Flow complete without redirect