@authhero/widget 0.4.1 → 0.6.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.
Files changed (39) hide show
  1. package/README.md +21 -1
  2. package/dist/authhero-widget/authhero-widget.esm.js +1 -1
  3. package/dist/authhero-widget/index.esm.js +1 -1
  4. package/dist/authhero-widget/p-7989dabd.entry.js +1 -0
  5. package/dist/authhero-widget/{p-Doiemx6o.js → p-bMtPc5Dm.js} +1 -1
  6. package/dist/authhero-widget/p-fa60ab6e.entry.js +1 -0
  7. package/dist/cjs/authhero-node.cjs.entry.js +97 -9
  8. package/dist/cjs/authhero-widget.cjs.entry.js +82 -18
  9. package/dist/cjs/authhero-widget.cjs.js +2 -2
  10. package/dist/cjs/{index-D0xitTOL.js → index-Db4bZu99.js} +28 -3
  11. package/dist/cjs/index.cjs.js +1 -1
  12. package/dist/cjs/loader.cjs.js +2 -2
  13. package/dist/collection/components/authhero-node/authhero-node.css +237 -94
  14. package/dist/collection/components/authhero-node/authhero-node.js +101 -8
  15. package/dist/collection/components/authhero-widget/authhero-widget.css +128 -70
  16. package/dist/collection/components/authhero-widget/authhero-widget.js +30 -5
  17. package/dist/collection/utils/branding.js +52 -13
  18. package/dist/components/authhero-node.js +1 -1
  19. package/dist/components/authhero-widget.js +1 -1
  20. package/dist/components/index.js +1 -1
  21. package/dist/components/p-pupmqprs.js +1 -0
  22. package/dist/components/p-uIy4ySa4.js +1 -0
  23. package/dist/esm/authhero-node.entry.js +97 -9
  24. package/dist/esm/authhero-widget.entry.js +82 -18
  25. package/dist/esm/authhero-widget.js +3 -3
  26. package/dist/esm/{index-Doiemx6o.js → index-bMtPc5Dm.js} +28 -3
  27. package/dist/esm/index.js +1 -1
  28. package/dist/esm/loader.js +3 -3
  29. package/dist/types/components/authhero-node/authhero-node.d.ts +14 -1
  30. package/dist/types/components/authhero-widget/authhero-widget.d.ts +8 -0
  31. package/hydrate/index.js +207 -29
  32. package/hydrate/index.mjs +207 -29
  33. package/package.json +10 -4
  34. package/dist/authhero-widget/p-2e93c814.entry.js +0 -1
  35. package/dist/authhero-widget/p-539fc666.entry.js +0 -1
  36. package/dist/collection/server/index.js +0 -453
  37. package/dist/components/p-086EZrPM.js +0 -1
  38. package/dist/components/p-DS6y_iDJ.js +0 -1
  39. package/dist/types/server/index.d.ts +0 -85
package/hydrate/index.js CHANGED
@@ -470,6 +470,10 @@ var require_brace_expansion = __commonJS({
470
470
  }
471
471
  }
472
472
  });
473
+
474
+ // src/utils/constants.ts
475
+ var SVG_NS = "http://www.w3.org/2000/svg";
476
+ var HTML_NS = "http://www.w3.org/1999/xhtml";
473
477
  var PrimitiveType = /* @__PURE__ */ ((PrimitiveType2) => {
474
478
  PrimitiveType2["Undefined"] = "undefined";
475
479
  PrimitiveType2["Null"] = "null";
@@ -3293,7 +3297,7 @@ var setAccessor = (elm, memberName, oldValue, newValue, isSvg, flags, initialRen
3293
3297
  }
3294
3298
  } else {
3295
3299
  const isComplex = isComplexType(newValue);
3296
- if ((isProp || isComplex && newValue !== null) && true) {
3300
+ if ((isProp || isComplex && newValue !== null) && !isSvg) {
3297
3301
  try {
3298
3302
  if (!elm.tagName.includes("-")) {
3299
3303
  const n = newValue == null ? "" : newValue;
@@ -3419,14 +3423,21 @@ var createElm = (oldParentVNode, newParentVNode, childIndex) => {
3419
3423
  updateElement(null, newVNode2, isSvgMode);
3420
3424
  }
3421
3425
  } else {
3426
+ if (!isSvgMode) {
3427
+ isSvgMode = newVNode2.$tag$ === "svg";
3428
+ }
3422
3429
  if (!win.document) {
3423
3430
  throw new Error(
3424
3431
  "You are trying to render a Stencil component in an environment that doesn't support the DOM. Make sure to populate the [`window`](https://developer.mozilla.org/en-US/docs/Web/API/Window/window) object before rendering a component."
3425
3432
  );
3426
3433
  }
3427
- elm = newVNode2.$elm$ = win.document.createElement(
3434
+ elm = newVNode2.$elm$ = win.document.createElementNS(
3435
+ isSvgMode ? SVG_NS : HTML_NS,
3428
3436
  !useNativeShadowDom && BUILD.slotRelocation && newVNode2.$flags$ & 2 /* isSlotFallback */ ? "slot-fb" : newVNode2.$tag$
3429
- );
3437
+ ) ;
3438
+ if (isSvgMode && newVNode2.$tag$ === "foreignObject") {
3439
+ isSvgMode = false;
3440
+ }
3430
3441
  {
3431
3442
  updateElement(null, newVNode2, isSvgMode);
3432
3443
  }
@@ -3442,6 +3453,13 @@ var createElm = (oldParentVNode, newParentVNode, childIndex) => {
3442
3453
  }
3443
3454
  }
3444
3455
  }
3456
+ {
3457
+ if (newVNode2.$tag$ === "svg") {
3458
+ isSvgMode = false;
3459
+ } else if (elm.tagName === "foreignObject") {
3460
+ isSvgMode = true;
3461
+ }
3462
+ }
3445
3463
  }
3446
3464
  elm["s-hn"] = hostTagName;
3447
3465
  {
@@ -3661,9 +3679,13 @@ var patch = (oldVNode, newVNode2, isInitialRender = false) => {
3661
3679
  const elm = newVNode2.$elm$ = oldVNode.$elm$;
3662
3680
  const oldChildren = oldVNode.$children$;
3663
3681
  const newChildren = newVNode2.$children$;
3682
+ const tag = newVNode2.$tag$;
3664
3683
  const text = newVNode2.$text$;
3665
3684
  let defaultHolder;
3666
3685
  if (text === null) {
3686
+ {
3687
+ isSvgMode = tag === "svg" ? true : tag === "foreignObject" ? false : isSvgMode;
3688
+ }
3667
3689
  {
3668
3690
  updateElement(oldVNode, newVNode2, isSvgMode, isInitialRender);
3669
3691
  }
@@ -3682,6 +3704,9 @@ var patch = (oldVNode, newVNode2, isInitialRender = false) => {
3682
3704
  } else if (isInitialRender && BUILD.updatable && oldChildren !== null && newChildren === null) {
3683
3705
  newVNode2.$children$ = oldChildren;
3684
3706
  }
3707
+ if (isSvgMode && tag === "svg") {
3708
+ isSvgMode = false;
3709
+ }
3685
3710
  } else if ((defaultHolder = elm["s-cr"])) {
3686
3711
  defaultHolder.parentNode.textContent = text;
3687
3712
  } else if (oldVNode.$text$ !== text) {
@@ -5009,7 +5034,7 @@ var setScopedSSR = (opts) => {
5009
5034
  var needsScopedSSR = () => scopedSSR;
5010
5035
  var scopedSSR = false;
5011
5036
 
5012
- const authheroNodeCss = () => `:host{display:block}.input-wrapper{display:flex;flex-direction:column;gap:var(--ah-space-1, 0.25rem)}.input-label{font-size:var(--ah-font-size-sm, 0.875rem);font-weight:var(--ah-font-weight-medium, 500);color:var(--ah-color-text-label, #374151);line-height:var(--ah-line-height-normal, 1.5)}.required{color:var(--ah-color-error, #dc2626);margin-left:var(--ah-space-1, 0.25rem)}.input-field{padding:var(--ah-input-padding-y, 0.75rem) var(--ah-input-padding-x, 1rem);font-size:var(--ah-font-size-base, 1rem);font-family:inherit;color:var(--ah-color-text, #1f2937);background-color:var(--ah-color-bg, #ffffff);border:var(--ah-input-border-width, 1px) solid var(--ah-color-border, #d1d5db);border-radius:var(--ah-input-radius, 6px);outline:none;transition:border-color var(--ah-transition-base, 200ms ease), box-shadow var(--ah-transition-base, 200ms ease)}.input-field::placeholder{color:var(--ah-color-text-muted, #9ca3af)}.input-field:focus{border-color:var(--ah-color-primary, #0066cc);box-shadow:0 0 0 3px var(--ah-color-primary-focus-ring, rgba(0, 102, 204, 0.1))}.input-field.has-error{border-color:var(--ah-color-error, #dc2626)}.input-field.has-error:focus{box-shadow:0 0 0 3px rgba(220, 38, 38, 0.1)}.input-field:disabled{background-color:var(--ah-color-bg-disabled, #f3f4f6);cursor:not-allowed;opacity:0.7}.error-text{font-size:var(--ah-font-size-xs, 0.75rem);color:var(--ah-color-error, #dc2626);margin-top:var(--ah-space-1, 0.25rem)}.helper-text{font-size:var(--ah-font-size-xs, 0.75rem);color:var(--ah-color-text-muted, #6b7280);margin-top:var(--ah-space-1, 0.25rem)}.checkbox-wrapper{display:flex;align-items:flex-start;gap:var(--ah-space-2, 0.5rem);cursor:pointer}.checkbox-wrapper input[type='checkbox']{width:1rem;height:1rem;margin-top:0.125rem;accent-color:var(--ah-color-primary, #0066cc);cursor:pointer}.checkbox-label{font-size:var(--ah-font-size-sm, 0.875rem);color:var(--ah-color-text-label, #374151);line-height:var(--ah-line-height-normal, 1.5)}.btn{display:inline-flex;align-items:center;justify-content:center;gap:var(--ah-space-2, 0.5rem);width:100%;padding:var(--ah-btn-padding-y, 0.875rem) var(--ah-btn-padding-x, 1.5rem);font-size:var(--ah-font-size-base, 1rem);font-weight:var(--ah-btn-font-weight, 500);font-family:inherit;line-height:var(--ah-line-height-tight, 1.25);text-align:center;text-decoration:none;border:none;border-radius:var(--ah-btn-radius, 8px);cursor:pointer;transition:background-color var(--ah-transition-base, 200ms ease), transform var(--ah-transition-fast, 150ms ease), box-shadow var(--ah-transition-base, 200ms ease)}.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-primary, #0066cc);outline-offset:2px}.btn-primary{background-color:var(--ah-color-primary, #0066cc);color:var(--ah-color-text-on-primary, #ffffff)}.btn-primary:not(:disabled):hover{background-color:var(--ah-color-primary-hover, #0052a3)}.btn-secondary{background-color:var(--ah-color-bg, #ffffff);color:var(--ah-color-text, #374151);border:1px solid var(--ah-color-border-muted, #e5e7eb)}.btn-secondary:not(:disabled):hover{background-color:var(--ah-color-bg-muted, #f9fafb);border-color:var(--ah-color-border, #d1d5db)}.text-title{font-size:var(--ah-font-size-xl, 1.25rem);font-weight:var(--ah-font-weight-semibold, 600);color:var(--ah-color-text, #1f2937);margin:var(--ah-space-2, 0.5rem) 0;line-height:var(--ah-line-height-tight, 1.25)}.text-title.text-success{color:var(--ah-color-success, #16a34a)}.text-description{font-size:var(--ah-font-size-sm, 0.875rem);color:var(--ah-color-text-muted, #6b7280);margin:var(--ah-space-1, 0.25rem) 0;line-height:var(--ah-line-height-normal, 1.5)}.image{display:block;max-width:100%;height:auto;border-radius:var(--ah-radius-lg, 8px)}.image-centered{margin:0 auto var(--ah-space-4, 1rem);width:var(--ah-logo-size, 48px);height:var(--ah-logo-size, 48px);object-fit:contain}.link{color:var(--ah-color-primary, #0066cc);text-decoration:none;font-size:var(--ah-font-size-sm, 0.875rem);transition:color var(--ah-transition-fast, 150ms ease)}.link:hover{text-decoration:underline}.link:focus-visible{outline:2px solid var(--ah-color-primary, #0066cc);outline-offset:2px}.node-error{padding:var(--ah-space-3, 0.75rem) var(--ah-space-4, 1rem);background-color:var(--ah-color-error-bg, #fee2e2);color:var(--ah-color-error, #dc2626);border:1px solid var(--ah-color-error-border, #fecaca);border-radius:var(--ah-radius-md, 6px);font-size:var(--ah-font-size-sm, 0.875rem)}.node-success{padding:var(--ah-space-3, 0.75rem) var(--ah-space-4, 1rem);background-color:var(--ah-color-success-bg, #dcfce7);color:var(--ah-color-success, #16a34a);border:1px solid var(--ah-color-success-border, #bbf7d0);border-radius:var(--ah-radius-md, 6px);font-size:var(--ah-font-size-sm, 0.875rem)}.divider{display:flex;align-items:center;text-align:center;margin:var(--ah-space-4, 1rem) 0}.divider::before,.divider::after{content:'';flex:1;border-bottom:1px solid var(--ah-color-border-muted, #e5e7eb)}.divider-text{padding:0 var(--ah-space-4, 1rem);font-size:var(--ah-font-size-sm, 0.875rem);color:var(--ah-color-text-muted, #9ca3af);text-transform:uppercase;letter-spacing:0.05em}`;
5037
+ const authheroNodeCss = () => `:host{display:block}.input-wrapper{display:flex;flex-direction:column;position:relative;margin-bottom:16px}.input-container{position:relative;width:100%}.input-label{position:absolute;left:16px;top:50%;transform:translateY(-50%);font-size: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{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-text, #1e212a);background-color:var(--ah-color-input-bg, #ffffff);border: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-text-muted, #65676e);transition:color 0.15s ease}.password-toggle:hover{color: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: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:14px;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: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-primary, #635dff);outline-offset:2px}.btn-primary{background-color:var(--ah-color-primary, #635dff);color:var(--ah-color-text-on-primary, #ffffff);margin-top:8px}.btn-primary:not(:disabled):hover{background-color:var(--ah-color-primary-hover);filter:brightness(0.9)}.btn-secondary{background-color:var(--ah-color-bg, #ffffff);color:var(--ah-color-text, #1e212a);border:1px solid 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}.btn-social{display:flex;align-items:center;justify-content:center;gap:12px}.social-icon{width:20px;height:20px;flex-shrink:0}.btn-icon{width:20px;height:20px;flex-shrink:0}.btn-icon img{width:100%;height:100%;object-fit:contain}.text-title{font-size:20px;font-weight:400;color:var(--ah-color-text, #1e212a);margin:8px 0;line-height:1.3}.text-title.text-success{color:var(--ah-color-success, #13a769)}.text-description{font-size:14px;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:14px;transition:color 0.15s ease}.link:hover{text-decoration:underline}.link:focus-visible{outline:2px solid 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}`;
5013
5038
 
5014
5039
  class AuthheroNode {
5015
5040
  constructor(hostRef) {
@@ -5030,6 +5055,10 @@ class AuthheroNode {
5030
5055
  * Whether the component is disabled.
5031
5056
  */
5032
5057
  disabled = false;
5058
+ /**
5059
+ * Whether the password field is visible.
5060
+ */
5061
+ passwordVisible = false;
5033
5062
  /**
5034
5063
  * Emitted when a field value changes.
5035
5064
  */
@@ -5055,6 +5084,9 @@ class AuthheroNode {
5055
5084
  }
5056
5085
  this.buttonClick.emit({ id: this.component.id, type, value });
5057
5086
  };
5087
+ togglePasswordVisibility = () => {
5088
+ this.passwordVisible = !this.passwordVisible;
5089
+ };
5058
5090
  /**
5059
5091
  * Get error messages from the component.
5060
5092
  */
@@ -5063,13 +5095,32 @@ class AuthheroNode {
5063
5095
  return (runtimeComp.messages?.filter((m) => m.type === "error") || []);
5064
5096
  }
5065
5097
  /**
5066
- * Render a label for a field.
5098
+ * Render a floating label for a field.
5099
+ */
5100
+ renderFloatingLabel(text, inputId, required, hasValue) {
5101
+ if (!text)
5102
+ return null;
5103
+ return (hAsync("label", { class: { "input-label": true, floating: !!hasValue }, part: "label", htmlFor: inputId }, text, required && hAsync("span", { class: "required" }, "*")));
5104
+ }
5105
+ /**
5106
+ * Render a label for a field (non-floating version for checkboxes etc).
5067
5107
  */
5068
5108
  renderLabel(text, inputId, required) {
5069
5109
  if (!text)
5070
5110
  return null;
5071
5111
  return (hAsync("label", { class: "input-label", part: "label", htmlFor: inputId }, text, required && hAsync("span", { class: "required" }, "*")));
5072
5112
  }
5113
+ /**
5114
+ * Render the eye icon for password visibility toggle.
5115
+ */
5116
+ renderPasswordToggle() {
5117
+ if (this.passwordVisible) {
5118
+ // Eye-off icon (password is visible, click to hide)
5119
+ return (hAsync("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, hAsync("path", { d: "M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24" }), hAsync("line", { x1: "1", y1: "1", x2: "23", y2: "23" })));
5120
+ }
5121
+ // Eye icon (password is hidden, click to show)
5122
+ return (hAsync("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, hAsync("path", { d: "M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" }), hAsync("circle", { cx: "12", cy: "12", r: "3" })));
5123
+ }
5073
5124
  /**
5074
5125
  * Render error messages.
5075
5126
  */
@@ -5121,21 +5172,25 @@ class AuthheroNode {
5121
5172
  renderTextField(component) {
5122
5173
  const inputId = `input-${component.id}`;
5123
5174
  const errors = this.getErrors();
5124
- const { placeholder, multiline, max_length } = component.config ?? {};
5175
+ const { multiline, max_length } = component.config ?? {};
5176
+ const hasValue = !!(this.value && this.value.length > 0);
5125
5177
  if (multiline) {
5126
- return (hAsync("div", { class: "input-wrapper", part: "input-wrapper" }, this.renderLabel(component.label, inputId, component.required), hAsync("textarea", { id: inputId, class: { "input-field": true, "has-error": errors.length > 0 }, part: "input textarea", name: component.id, placeholder: placeholder, required: component.required, disabled: this.disabled, maxLength: max_length, onInput: this.handleInput }, this.value ?? ""), this.renderErrors(), errors.length === 0 && this.renderHint(component.hint)));
5178
+ return (hAsync("div", { class: "input-wrapper", part: "input-wrapper" }, this.renderLabel(component.label, inputId, component.required), hAsync("textarea", { id: inputId, class: { "input-field": true, "has-error": errors.length > 0 }, part: "input textarea", name: component.id, placeholder: " ", required: component.required, disabled: this.disabled, maxLength: max_length, onInput: this.handleInput }, this.value ?? ""), this.renderErrors(), errors.length === 0 && this.renderHint(component.hint)));
5127
5179
  }
5128
- return (hAsync("div", { class: "input-wrapper", part: "input-wrapper" }, this.renderLabel(component.label, inputId, component.required), hAsync("input", { id: inputId, class: { "input-field": true, "has-error": errors.length > 0 }, part: "input", type: component.sensitive ? "password" : "text", name: component.id, value: this.value ?? "", placeholder: placeholder, required: component.required, disabled: this.disabled, maxLength: max_length, onInput: this.handleInput }), this.renderErrors(), errors.length === 0 && this.renderHint(component.hint)));
5180
+ return (hAsync("div", { class: "input-wrapper", part: "input-wrapper" }, hAsync("div", { class: "input-container" }, hAsync("input", { id: inputId, class: { "input-field": true, "has-error": errors.length > 0 }, part: "input", type: component.sensitive ? "password" : "text", name: component.id, value: this.value ?? "", placeholder: " ", required: component.required, disabled: this.disabled, maxLength: max_length, onInput: this.handleInput }), this.renderFloatingLabel(component.label, inputId, component.required, hasValue)), this.renderErrors(), errors.length === 0 && this.renderHint(component.hint)));
5129
5181
  }
5130
5182
  renderEmailField(component) {
5131
5183
  const inputId = `input-${component.id}`;
5132
5184
  const errors = this.getErrors();
5133
- return (hAsync("div", { class: "input-wrapper", part: "input-wrapper" }, this.renderLabel(component.label, inputId, component.required), hAsync("input", { id: inputId, class: { "input-field": true, "has-error": errors.length > 0 }, part: "input", type: "email", name: component.id, value: this.value ?? "", placeholder: component.config?.placeholder, required: component.required, disabled: this.disabled, autocomplete: "email", onInput: this.handleInput }), this.renderErrors(), errors.length === 0 && this.renderHint(component.hint)));
5185
+ const hasValue = !!(this.value && this.value.length > 0);
5186
+ return (hAsync("div", { class: "input-wrapper", part: "input-wrapper" }, hAsync("div", { class: "input-container" }, hAsync("input", { id: inputId, class: { "input-field": true, "has-error": errors.length > 0 }, part: "input", type: "email", name: component.id, value: this.value ?? "", placeholder: " ", required: component.required, disabled: this.disabled, autocomplete: "email", onInput: this.handleInput }), this.renderFloatingLabel(component.label, inputId, component.required, hasValue)), this.renderErrors(), errors.length === 0 && this.renderHint(component.hint)));
5134
5187
  }
5135
5188
  renderPasswordField(component) {
5136
5189
  const inputId = `input-${component.id}`;
5137
5190
  const errors = this.getErrors();
5138
- return (hAsync("div", { class: "input-wrapper", part: "input-wrapper" }, this.renderLabel(component.label, inputId, component.required), hAsync("input", { id: inputId, class: { "input-field": true, "has-error": errors.length > 0 }, part: "input", type: "password", name: component.id, value: this.value ?? "", placeholder: component.config?.placeholder, required: component.required, disabled: this.disabled, minLength: component.config?.min_length, autocomplete: "current-password", onInput: this.handleInput }), this.renderErrors(), errors.length === 0 && this.renderHint(component.hint)));
5191
+ const hasValue = !!(this.value && this.value.length > 0);
5192
+ const forgotPasswordLink = component.config?.forgot_password_link;
5193
+ return (hAsync("div", { class: "input-wrapper", part: "input-wrapper" }, hAsync("div", { class: "input-container password-container" }, hAsync("input", { id: inputId, class: { "input-field": true, "has-error": errors.length > 0 }, part: "input", type: this.passwordVisible ? "text" : "password", name: component.id, value: this.value ?? "", placeholder: " ", required: component.required, disabled: this.disabled, minLength: component.config?.min_length, autocomplete: "current-password", onInput: this.handleInput }), this.renderFloatingLabel(component.label, inputId, component.required, hasValue), hAsync("button", { type: "button", class: "password-toggle", part: "password-toggle", onClick: this.togglePasswordVisibility, "aria-label": "Toggle password visibility", "aria-pressed": this.passwordVisible ? "true" : "false" }, this.renderPasswordToggle())), this.renderErrors(), errors.length === 0 && this.renderHint(component.hint), forgotPasswordLink && (hAsync("div", { class: "field-link", part: "field-link" }, hAsync("a", { href: forgotPasswordLink, class: "link", part: "link" }, "Forgot password?")))));
5139
5194
  }
5140
5195
  renderNumberField(component) {
5141
5196
  const inputId = `input-${component.id}`;
@@ -5182,7 +5237,65 @@ class AuthheroNode {
5182
5237
  }
5183
5238
  renderSocialField(component) {
5184
5239
  const providers = component.config?.providers ?? [];
5185
- return (hAsync("div", { class: "social-buttons", part: "social-buttons" }, providers.map((provider) => (hAsync("button", { type: "button", class: "btn btn-secondary btn-social", part: "button button-secondary button-social", "data-provider": provider, disabled: this.disabled, onClick: (e) => this.handleButtonClick(e, "social", provider), key: provider }, "Continue with ", provider.charAt(0).toUpperCase() + provider.slice(1))))));
5240
+ // Map provider IDs to display names
5241
+ const getProviderDisplayName = (provider) => {
5242
+ const displayNames = {
5243
+ "google-oauth2": "Google",
5244
+ facebook: "Facebook",
5245
+ twitter: "Twitter",
5246
+ github: "GitHub",
5247
+ linkedin: "LinkedIn",
5248
+ apple: "Apple",
5249
+ microsoft: "Microsoft",
5250
+ windowslive: "Microsoft",
5251
+ amazon: "Amazon",
5252
+ dropbox: "Dropbox",
5253
+ bitbucket: "Bitbucket",
5254
+ spotify: "Spotify",
5255
+ slack: "Slack",
5256
+ discord: "Discord",
5257
+ twitch: "Twitch",
5258
+ line: "LINE",
5259
+ shopify: "Shopify",
5260
+ paypal: "PayPal",
5261
+ "paypal-sandbox": "PayPal",
5262
+ box: "Box",
5263
+ salesforce: "Salesforce",
5264
+ "salesforce-sandbox": "Salesforce",
5265
+ yahoo: "Yahoo",
5266
+ auth0: "Auth0",
5267
+ };
5268
+ return (displayNames[provider.toLowerCase()] ||
5269
+ provider
5270
+ .split("-")
5271
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
5272
+ .join(" "));
5273
+ };
5274
+ // Get provider icon SVG
5275
+ const getProviderIcon = (provider) => {
5276
+ const p = provider.toLowerCase();
5277
+ if (p === "google-oauth2" || p === "google") {
5278
+ return (hAsync("svg", { class: "social-icon", viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg" }, hAsync("path", { d: "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z", fill: "#4285F4" }), hAsync("path", { d: "M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z", fill: "#34A853" }), hAsync("path", { d: "M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z", fill: "#FBBC05" }), hAsync("path", { d: "M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z", fill: "#EA4335" })));
5279
+ }
5280
+ if (p === "facebook") {
5281
+ return (hAsync("svg", { class: "social-icon", viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg" }, hAsync("path", { d: "M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z", fill: "#1877F2" })));
5282
+ }
5283
+ if (p === "apple") {
5284
+ return (hAsync("svg", { class: "social-icon", viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg" }, hAsync("path", { d: "M17.05 20.28c-.98.95-2.05.8-3.08.35-1.09-.46-2.09-.48-3.24 0-1.44.62-2.2.44-3.06-.35C2.79 15.25 3.51 7.59 9.05 7.31c1.35.07 2.29.74 3.08.8 1.18-.24 2.31-.93 3.57-.84 1.51.12 2.65.72 3.4 1.8-3.12 1.87-2.38 5.98.48 7.13-.57 1.5-1.31 2.99-2.54 4.09l.01-.01zM12.03 7.25c-.15-2.23 1.66-4.07 3.74-4.25.29 2.58-2.34 4.5-3.74 4.25z", fill: "#000000" })));
5285
+ }
5286
+ if (p === "github") {
5287
+ return (hAsync("svg", { class: "social-icon", viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg" }, hAsync("path", { d: "M12 0C5.374 0 0 5.373 0 12c0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23A11.509 11.509 0 0112 5.803c1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576C20.566 21.797 24 17.3 24 12c0-6.627-5.373-12-12-12z", fill: "#181717" })));
5288
+ }
5289
+ if (p === "microsoft" || p === "windowslive") {
5290
+ return (hAsync("svg", { class: "social-icon", viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg" }, hAsync("path", { d: "M0 0h11.377v11.372H0V0z", fill: "#f25022" }), hAsync("path", { d: "M12.623 0H24v11.372H12.623V0z", fill: "#7fba00" }), hAsync("path", { d: "M0 12.623h11.377V24H0v-11.377z", fill: "#00a4ef" }), hAsync("path", { d: "M12.623 12.623H24V24H12.623v-11.377z", fill: "#ffb900" })));
5291
+ }
5292
+ if (p === "linkedin") {
5293
+ return (hAsync("svg", { class: "social-icon", viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg" }, hAsync("path", { d: "M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z", fill: "#0A66C2" })));
5294
+ }
5295
+ // Default: no icon
5296
+ return null;
5297
+ };
5298
+ return (hAsync("div", { class: "social-buttons", part: "social-buttons" }, providers.map((provider) => (hAsync("button", { type: "button", class: "btn btn-secondary btn-social", part: "button button-secondary button-social", "data-provider": provider, disabled: this.disabled, onClick: (e) => this.handleButtonClick(e, "social", provider), key: provider }, getProviderIcon(provider), hAsync("span", null, "Continue with ", getProviderDisplayName(provider)))))));
5186
5299
  }
5187
5300
  // ===========================================================================
5188
5301
  // Main Render
@@ -5263,7 +5376,8 @@ class AuthheroNode {
5263
5376
  "$members$": {
5264
5377
  "component": [16],
5265
5378
  "value": [1],
5266
- "disabled": [4]
5379
+ "disabled": [4],
5380
+ "passwordVisible": [32]
5267
5381
  },
5268
5382
  "$listeners$": undefined,
5269
5383
  "$lazyBundleId$": "-",
@@ -5436,39 +5550,60 @@ function themeToCssVars(theme) {
5436
5550
  // Fonts
5437
5551
  if (theme.fonts) {
5438
5552
  const f = theme.fonts;
5553
+ // reference_text_size is the base font size in pixels (default 16px)
5554
+ const baseSize = f.reference_text_size || 16;
5439
5555
  if (f.font_url) {
5440
5556
  vars['--ah-font-url'] = f.font_url;
5441
5557
  }
5442
5558
  if (f.reference_text_size) {
5443
5559
  vars['--ah-font-size-base'] = `${f.reference_text_size}px`;
5444
5560
  }
5561
+ // Title, subtitle, etc. sizes are percentages of the base size
5445
5562
  if (f.title?.size) {
5446
- vars['--ah-font-size-title'] = `${f.title.size}px`;
5563
+ const titlePx = Math.round((f.title.size / 100) * baseSize);
5564
+ vars['--ah-font-size-title'] = `${titlePx}px`;
5447
5565
  }
5448
5566
  if (f.subtitle?.size) {
5449
- vars['--ah-font-size-subtitle'] = `${f.subtitle.size}px`;
5567
+ const subtitlePx = Math.round((f.subtitle.size / 100) * baseSize);
5568
+ vars['--ah-font-size-subtitle'] = `${subtitlePx}px`;
5450
5569
  }
5451
5570
  if (f.body_text?.size) {
5452
- vars['--ah-font-size-body'] = `${f.body_text.size}px`;
5571
+ const bodyPx = Math.round((f.body_text.size / 100) * baseSize);
5572
+ vars['--ah-font-size-body'] = `${bodyPx}px`;
5453
5573
  }
5454
5574
  if (f.input_labels?.size) {
5455
- vars['--ah-font-size-label'] = `${f.input_labels.size}px`;
5575
+ const labelPx = Math.round((f.input_labels.size / 100) * baseSize);
5576
+ vars['--ah-font-size-label'] = `${labelPx}px`;
5456
5577
  }
5457
5578
  if (f.buttons_text?.size) {
5458
- vars['--ah-font-size-btn'] = `${f.buttons_text.size}px`;
5579
+ const btnPx = Math.round((f.buttons_text.size / 100) * baseSize);
5580
+ vars['--ah-font-size-btn'] = `${btnPx}px`;
5459
5581
  }
5460
5582
  if (f.links?.size) {
5461
- vars['--ah-font-size-link'] = `${f.links.size}px`;
5583
+ const linkPx = Math.round((f.links.size / 100) * baseSize);
5584
+ vars['--ah-font-size-link'] = `${linkPx}px`;
5462
5585
  }
5463
5586
  if (f.links_style === 'underlined') {
5464
5587
  vars['--ah-link-decoration'] = 'underline';
5465
5588
  }
5466
- // Font weights
5467
- if (f.title?.bold) {
5468
- vars['--ah-font-weight-title'] = '700';
5589
+ // Font weights - bold option sets font-weight to 700
5590
+ if (f.title?.bold !== undefined) {
5591
+ vars['--ah-font-weight-title'] = f.title.bold ? '700' : '400';
5592
+ }
5593
+ if (f.subtitle?.bold !== undefined) {
5594
+ vars['--ah-font-weight-subtitle'] = f.subtitle.bold ? '700' : '400';
5595
+ }
5596
+ if (f.body_text?.bold !== undefined) {
5597
+ vars['--ah-font-weight-body'] = f.body_text.bold ? '700' : '400';
5469
5598
  }
5470
- if (f.buttons_text?.bold) {
5471
- vars['--ah-font-weight-btn'] = '600';
5599
+ if (f.input_labels?.bold !== undefined) {
5600
+ vars['--ah-font-weight-label'] = f.input_labels.bold ? '700' : '400';
5601
+ }
5602
+ if (f.buttons_text?.bold !== undefined) {
5603
+ vars['--ah-font-weight-btn'] = f.buttons_text.bold ? '600' : '400';
5604
+ }
5605
+ if (f.links?.bold !== undefined) {
5606
+ vars['--ah-font-weight-link'] = f.links.bold ? '700' : '400';
5472
5607
  }
5473
5608
  }
5474
5609
  // Widget settings
@@ -5485,9 +5620,27 @@ function themeToCssVars(theme) {
5485
5620
  center: 'center',
5486
5621
  left: 'flex-start',
5487
5622
  right: 'flex-end',
5488
- none: 'none',
5489
5623
  };
5490
- vars['--ah-logo-align'] = positionMap[w.logo_position] ?? 'center';
5624
+ if (w.logo_position === 'none') {
5625
+ vars['--ah-logo-display'] = 'none';
5626
+ }
5627
+ else {
5628
+ vars['--ah-logo-align'] = positionMap[w.logo_position] ?? 'center';
5629
+ }
5630
+ }
5631
+ if (w.social_buttons_layout) {
5632
+ // 'top' means social buttons above fields, 'bottom' means below
5633
+ // Divider is always order 1 (middle)
5634
+ if (w.social_buttons_layout === 'top') {
5635
+ vars['--ah-social-order'] = '0';
5636
+ vars['--ah-divider-order'] = '1';
5637
+ vars['--ah-fields-order'] = '2';
5638
+ }
5639
+ else {
5640
+ vars['--ah-social-order'] = '2';
5641
+ vars['--ah-divider-order'] = '1';
5642
+ vars['--ah-fields-order'] = '0';
5643
+ }
5491
5644
  }
5492
5645
  }
5493
5646
  // Page background
@@ -5520,7 +5673,7 @@ function applyCssVars(element, vars) {
5520
5673
  });
5521
5674
  }
5522
5675
 
5523
- const authheroWidgetCss = () => `:host{display:block;font-family:var(--ah-font-family, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif)}.widget-container{max-width:var(--ah-widget-max-width, 400px);margin:0 auto;padding:var(--ah-widget-padding, 2rem);background-color:var(--ah-color-bg, #ffffff);border-radius:var(--ah-widget-radius, 8px);box-shadow:var(--ah-widget-shadow, 0 2px 10px rgba(0, 0, 0, 0.1))}.logo{display:block;width:var(--ah-logo-size, 48px);height:var(--ah-logo-size, 48px);margin:0 auto var(--ah-space-6, 1.5rem);object-fit:contain;border-radius:var(--ah-logo-radius, 8px)}.title{font-size:var(--ah-font-size-2xl, 1.5rem);font-weight:var(--ah-font-weight-semibold, 600);text-align:center;margin:0 0 var(--ah-space-8, 2rem);color:var(--ah-color-text, #111827);line-height:var(--ah-line-height-tight, 1.25)}.message{padding:var(--ah-space-3, 0.75rem) var(--ah-space-4, 1rem);border-radius:var(--ah-radius-md, 4px);margin-bottom:var(--ah-space-4, 1rem);font-size:var(--ah-font-size-sm, 0.875rem);line-height:var(--ah-line-height-normal, 1.5)}.message-error{background-color:var(--ah-color-error-bg, #fee2e2);color:var(--ah-color-error, #dc2626);border:1px solid var(--ah-color-error-border, #fecaca)}.message-success{background-color:var(--ah-color-success-bg, #dcfce7);color:var(--ah-color-success, #16a34a);border:1px solid var(--ah-color-success-border, #bbf7d0)}form{display:flex;flex-direction:column;gap:var(--ah-space-4, 1rem)}.links{display:flex;flex-direction:column;align-items:center;gap:var(--ah-space-2, 0.5rem);margin-top:var(--ah-space-6, 1.5rem);padding-top:var(--ah-space-4, 1rem)}.link-wrapper{font-size:var(--ah-font-size-sm, 0.875rem);color:var(--ah-color-text-muted, #6b7280)}.link{color:var(--ah-color-primary, #0066cc);text-decoration:none;font-size:var(--ah-font-size-sm, 0.875rem);transition:color var(--ah-transition-fast, 150ms ease)}.link:hover{text-decoration:underline}.link:focus-visible{outline:2px solid var(--ah-color-primary, #0066cc);outline-offset:2px}.divider{display:flex;align-items:center;text-align:center;margin:var(--ah-space-2, 0.5rem) 0}.divider::before,.divider::after{content:'';flex:1;border-bottom:1px solid var(--ah-color-border-muted, #e5e7eb)}.divider-text{padding:0 var(--ah-space-4, 1rem);font-size:var(--ah-font-size-sm, 0.875rem);color:var(--ah-color-text-muted, #9ca3af);text-transform:uppercase;letter-spacing:0.05em}.loading-spinner{width:40px;height:40px;margin:var(--ah-space-8, 2rem) auto;border:3px solid var(--ah-color-border-muted, #f3f3f3);border-top:3px solid var(--ah-color-primary, #0066cc);border-radius:50%;animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}.error-message{text-align:center;color:var(--ah-color-error, #dc2626);padding:var(--ah-space-4, 1rem)}`;
5676
+ 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, 14px);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{max-width:var(--ah-widget-max-width, 400px);width:100%;margin:0 auto;background-color:var(--ah-color-bg, #ffffff);border-radius:var(--ah-widget-radius, 5px);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 40px 24px)}.widget-body{padding:var(--ah-body-padding, 0 40px 40px)}.logo-wrapper{display:var(--ah-logo-display, flex);justify-content:var(--ah-logo-align, center)}.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 16px);color:var(--ah-color-header, #1e212a);line-height:1.2}.description{font-size:var(--ah-font-size-description, 14px);text-align:var(--ah-title-align, center);margin:var(--ah-description-margin, 0);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)}.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:14px;color:var(--ah-color-text, #1e212a)}.link{color:var(--ah-color-link, #635dff);text-decoration:var(--ah-link-decoration, none);font-size: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-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}`;
5524
5677
 
5525
5678
  class AuthheroWidget {
5526
5679
  constructor(hostRef) {
@@ -5778,6 +5931,13 @@ class AuthheroWidget {
5778
5931
  }
5779
5932
  };
5780
5933
  handleButtonClick = (detail) => {
5934
+ // If this is a submit button click, trigger form submission
5935
+ if (detail.type === 'submit') {
5936
+ // Create a synthetic submit event and call handleSubmit
5937
+ const syntheticEvent = { preventDefault: () => { } };
5938
+ this.handleSubmit(syntheticEvent);
5939
+ return;
5940
+ }
5781
5941
  this.buttonClick.emit(detail);
5782
5942
  };
5783
5943
  handleLinkClick = (e, link) => {
@@ -5815,6 +5975,20 @@ class AuthheroWidget {
5815
5975
  .filter((c) => c.visible !== false)
5816
5976
  .sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
5817
5977
  }
5978
+ /**
5979
+ * Check if a component is a social button.
5980
+ */
5981
+ isSocialComponent(component) {
5982
+ // Check the type property directly - FormComponent has a 'type' field
5983
+ // SocialField has type 'SOCIAL'
5984
+ return component.type === 'SOCIAL';
5985
+ }
5986
+ /**
5987
+ * Check if a component is a divider.
5988
+ */
5989
+ isDividerComponent(component) {
5990
+ return component.type === 'DIVIDER';
5991
+ }
5818
5992
  render() {
5819
5993
  if (this.loading && !this._screen) {
5820
5994
  return (hAsync("div", { class: "widget-container" }, hAsync("div", { class: "loading-spinner" })));
@@ -5825,9 +5999,13 @@ class AuthheroWidget {
5825
5999
  const screenErrors = this.getScreenErrors();
5826
6000
  const screenSuccesses = this.getScreenSuccesses();
5827
6001
  const components = this.getOrderedComponents();
5828
- // Get logo URL from branding props
5829
- const logoUrl = this._branding?.logo_url;
5830
- return (hAsync("div", { class: "widget-container", part: "container" }, logoUrl && hAsync("img", { class: "logo", part: "logo", src: logoUrl, alt: "Logo" }), this._screen.title && (hAsync("h1", { class: "title", part: "title" }, this._screen.title)), this._screen.description && (hAsync("p", { class: "description", part: "description" }, this._screen.description)), screenErrors.map((err) => (hAsync("div", { class: "message message-error", part: "message message-error", key: err.id ?? err.text }, err.text))), screenSuccesses.map((msg) => (hAsync("div", { class: "message message-success", part: "message message-success", key: msg.id ?? msg.text }, msg.text))), hAsync("form", { onSubmit: this.handleSubmit, part: "form" }, components.map((component) => (hAsync("authhero-node", { key: component.id, component: component, value: this.formData[component.id], onFieldChange: (e) => this.handleInputChange(e.detail.id, e.detail.value), onButtonClick: (e) => this.handleButtonClick(e.detail), disabled: this.loading })))), this._screen.links && this._screen.links.length > 0 && (hAsync("div", { class: "links", part: "links" }, this._screen.links.map((link) => (hAsync("span", { class: "link-wrapper", part: "link-wrapper", key: link.id ?? link.href }, link.linkText ? (hAsync("span", null, link.text, ' ', hAsync("a", { href: link.href, class: "link", part: "link", onClick: (e) => this.handleLinkClick(e, { id: link.id, href: link.href, text: link.linkText || link.text }) }, link.linkText))) : (hAsync("a", { href: link.href, class: "link", part: "link", onClick: (e) => this.handleLinkClick(e, { id: link.id, href: link.href, text: link.text }) }, link.text)))))))));
6002
+ // Separate social, divider, and field components for layout ordering
6003
+ const socialComponents = components.filter(c => this.isSocialComponent(c));
6004
+ const fieldComponents = components.filter(c => !this.isSocialComponent(c) && !this.isDividerComponent(c));
6005
+ const hasDivider = components.some(c => this.isDividerComponent(c));
6006
+ // Get logo URL from theme.widget (takes precedence) or branding
6007
+ const logoUrl = this._theme?.widget?.logo_url || this._branding?.logo_url;
6008
+ return (hAsync("div", { class: "widget-container", part: "container" }, hAsync("header", { class: "widget-header", part: "header" }, logoUrl && (hAsync("div", { class: "logo-wrapper", part: "logo-wrapper" }, hAsync("img", { class: "logo", part: "logo", src: logoUrl, alt: "Logo" }))), this._screen.title && (hAsync("h1", { class: "title", part: "title" }, this._screen.title)), this._screen.description && (hAsync("p", { class: "description", part: "description" }, this._screen.description))), hAsync("div", { class: "widget-body", part: "body" }, screenErrors.map((err) => (hAsync("div", { class: "message message-error", part: "message message-error", key: err.id ?? err.text }, err.text))), screenSuccesses.map((msg) => (hAsync("div", { class: "message message-success", part: "message message-success", key: msg.id ?? msg.text }, msg.text))), hAsync("form", { onSubmit: this.handleSubmit, part: "form" }, hAsync("div", { class: "form-content" }, socialComponents.length > 0 && (hAsync("div", { class: "social-section", part: "social-section" }, socialComponents.map((component) => (hAsync("authhero-node", { key: component.id, component: component, value: this.formData[component.id], onFieldChange: (e) => this.handleInputChange(e.detail.id, e.detail.value), onButtonClick: (e) => this.handleButtonClick(e.detail), disabled: this.loading }))))), socialComponents.length > 0 && fieldComponents.length > 0 && hasDivider && (hAsync("div", { class: "divider", part: "divider" }, hAsync("span", { class: "divider-text" }, "Or"))), hAsync("div", { class: "fields-section", part: "fields-section" }, fieldComponents.map((component) => (hAsync("authhero-node", { key: component.id, component: component, value: this.formData[component.id], onFieldChange: (e) => this.handleInputChange(e.detail.id, e.detail.value), onButtonClick: (e) => this.handleButtonClick(e.detail), disabled: this.loading })))))), this._screen.links && this._screen.links.length > 0 && (hAsync("div", { class: "links", part: "links" }, this._screen.links.map((link) => (hAsync("span", { class: "link-wrapper", part: "link-wrapper", key: link.id ?? link.href }, link.linkText ? (hAsync("span", null, link.text, ' ', hAsync("a", { href: link.href, class: "link", part: "link", onClick: (e) => this.handleLinkClick(e, { id: link.id, href: link.href, text: link.linkText || link.text }) }, link.linkText))) : (hAsync("a", { href: link.href, class: "link", part: "link", onClick: (e) => this.handleLinkClick(e, { id: link.id, href: link.href, text: link.text }) }, link.text))))))))));
5831
6009
  }
5832
6010
  static get watchers() { return {
5833
6011
  "screen": [{