@authhero/widget 0.2.2 → 0.4.1

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 (59) hide show
  1. package/dist/authhero-widget/authhero-widget.esm.js +1 -0
  2. package/dist/authhero-widget/index.esm.js +1 -0
  3. package/dist/authhero-widget/p-2e93c814.entry.js +1 -0
  4. package/dist/authhero-widget/p-539fc666.entry.js +1 -0
  5. package/dist/authhero-widget/p-DQuL1Twl.js +1 -0
  6. package/dist/authhero-widget/p-Doiemx6o.js +2 -0
  7. package/dist/cjs/app-globals-V2Kpy_OQ.js +5 -0
  8. package/dist/cjs/authhero-node.cjs.entry.js +255 -0
  9. package/dist/cjs/authhero-widget.cjs.entry.js +577 -0
  10. package/dist/cjs/authhero-widget.cjs.js +25 -0
  11. package/dist/cjs/index-D0xitTOL.js +3788 -0
  12. package/dist/cjs/index.cjs.js +8123 -0
  13. package/dist/cjs/loader.cjs.js +13 -0
  14. package/dist/collection/collection-manifest.json +13 -0
  15. package/dist/collection/components/authhero-node/authhero-node.css +298 -0
  16. package/dist/collection/components/authhero-node/authhero-node.js +360 -0
  17. package/dist/collection/components/authhero-widget/authhero-widget.css +186 -0
  18. package/dist/collection/components/authhero-widget/authhero-widget.js +628 -0
  19. package/dist/collection/index.js +2 -0
  20. package/dist/collection/server/index.js +453 -0
  21. package/dist/collection/themes/index.js +71 -0
  22. package/dist/collection/types/components.js +8 -0
  23. package/dist/collection/utils/branding.js +248 -0
  24. package/dist/components/authhero-node.d.ts +11 -0
  25. package/dist/components/authhero-node.js +1 -0
  26. package/dist/components/authhero-widget.d.ts +11 -0
  27. package/dist/components/authhero-widget.js +1 -0
  28. package/dist/components/index.d.ts +35 -0
  29. package/dist/components/index.js +1 -0
  30. package/dist/components/p-086EZrPM.js +1 -0
  31. package/dist/components/p-DS6y_iDJ.js +1 -0
  32. package/dist/esm/app-globals-DQuL1Twl.js +3 -0
  33. package/dist/esm/authhero-node.entry.js +253 -0
  34. package/dist/esm/authhero-widget.entry.js +575 -0
  35. package/dist/esm/authhero-widget.js +21 -0
  36. package/dist/esm/index-Doiemx6o.js +3780 -0
  37. package/dist/esm/index.js +8122 -0
  38. package/dist/esm/loader.js +11 -0
  39. package/dist/index.cjs.js +1 -0
  40. package/dist/index.js +1 -0
  41. package/dist/types/components/authhero-node/authhero-node.d.ts +72 -0
  42. package/dist/types/components/authhero-widget/authhero-widget.d.ts +172 -0
  43. package/dist/types/components.d.ts +215 -0
  44. package/dist/types/index.d.ts +1 -0
  45. package/dist/types/server/index.d.ts +85 -0
  46. package/dist/types/stencil-public-runtime.d.ts +1839 -0
  47. package/dist/types/themes/index.d.ts +40 -0
  48. package/dist/types/types/components.d.ts +8 -0
  49. package/dist/types/utils/branding.d.ts +119 -0
  50. package/hydrate/index.d.ts +287 -0
  51. package/hydrate/index.js +23729 -0
  52. package/hydrate/index.mjs +23719 -0
  53. package/hydrate/package.json +12 -0
  54. package/loader/cdn.js +1 -0
  55. package/loader/index.cjs.js +1 -0
  56. package/loader/index.d.ts +24 -0
  57. package/loader/index.es2017.js +1 -0
  58. package/loader/index.js +2 -0
  59. package/package.json +2 -2
@@ -0,0 +1,577 @@
1
+ 'use strict';
2
+
3
+ var index = require('./index-D0xitTOL.js');
4
+
5
+ /**
6
+ * AuthHero Widget - Branding Utilities
7
+ *
8
+ * Converts AuthHero branding and theme configurations to CSS custom properties.
9
+ */
10
+ /**
11
+ * Convert a style enum to border radius value
12
+ */
13
+ function styleToRadius(style, baseRadius) {
14
+ if (baseRadius !== undefined)
15
+ return `${baseRadius}px`;
16
+ switch (style) {
17
+ case 'pill':
18
+ return '9999px';
19
+ case 'rounded':
20
+ return '8px';
21
+ case 'sharp':
22
+ return '0';
23
+ default:
24
+ return undefined;
25
+ }
26
+ }
27
+ /**
28
+ * Convert branding configuration to CSS custom properties
29
+ */
30
+ function brandingToCssVars(branding) {
31
+ if (!branding)
32
+ return {};
33
+ const vars = {};
34
+ // Primary color
35
+ if (branding.colors?.primary) {
36
+ vars['--ah-color-primary'] = branding.colors.primary;
37
+ // Generate hover variant (slightly darker)
38
+ vars['--ah-color-primary-hover'] = branding.colors.primary;
39
+ }
40
+ // Page background
41
+ if (branding.colors?.page_background) {
42
+ const bg = branding.colors.page_background;
43
+ if (bg.type === 'solid' && bg.start) {
44
+ vars['--ah-page-bg'] = bg.start;
45
+ }
46
+ else if (bg.type === 'gradient' && bg.start && bg.end) {
47
+ const angle = bg.angle_deg ?? 180;
48
+ vars['--ah-page-bg'] = `linear-gradient(${angle}deg, ${bg.start}, ${bg.end})`;
49
+ }
50
+ }
51
+ // Logo URL (stored for reference, used via prop)
52
+ if (branding.logo_url) {
53
+ vars['--ah-logo-url'] = `url(${branding.logo_url})`;
54
+ }
55
+ // Font URL
56
+ if (branding.font?.url) {
57
+ vars['--ah-font-url'] = branding.font.url;
58
+ }
59
+ return vars;
60
+ }
61
+ /**
62
+ * Convert theme configuration to CSS custom properties
63
+ */
64
+ function themeToCssVars(theme) {
65
+ if (!theme)
66
+ return {};
67
+ const vars = {};
68
+ // Border radii
69
+ if (theme.borders) {
70
+ const b = theme.borders;
71
+ // Widget
72
+ if (b.widget_corner_radius !== undefined) {
73
+ vars['--ah-widget-radius'] = `${b.widget_corner_radius}px`;
74
+ }
75
+ if (b.widget_border_weight !== undefined) {
76
+ vars['--ah-widget-border-width'] = `${b.widget_border_weight}px`;
77
+ }
78
+ if (b.show_widget_shadow === false) {
79
+ vars['--ah-widget-shadow'] = 'none';
80
+ }
81
+ // Buttons
82
+ const btnRadius = styleToRadius(b.buttons_style, b.button_border_radius);
83
+ if (btnRadius) {
84
+ vars['--ah-btn-radius'] = btnRadius;
85
+ }
86
+ if (b.button_border_weight !== undefined) {
87
+ vars['--ah-btn-border-width'] = `${b.button_border_weight}px`;
88
+ }
89
+ // Inputs
90
+ const inputRadius = styleToRadius(b.inputs_style, b.input_border_radius);
91
+ if (inputRadius) {
92
+ vars['--ah-input-radius'] = inputRadius;
93
+ }
94
+ if (b.input_border_weight !== undefined) {
95
+ vars['--ah-input-border-width'] = `${b.input_border_weight}px`;
96
+ }
97
+ }
98
+ // Colors
99
+ if (theme.colors) {
100
+ const c = theme.colors;
101
+ // Primary button
102
+ if (c.primary_button) {
103
+ vars['--ah-color-primary'] = c.primary_button;
104
+ vars['--ah-color-primary-hover'] = c.primary_button;
105
+ }
106
+ if (c.primary_button_label) {
107
+ vars['--ah-btn-primary-text'] = c.primary_button_label;
108
+ }
109
+ // Secondary button
110
+ if (c.secondary_button_border) {
111
+ vars['--ah-btn-secondary-border'] = c.secondary_button_border;
112
+ }
113
+ if (c.secondary_button_label) {
114
+ vars['--ah-btn-secondary-text'] = c.secondary_button_label;
115
+ }
116
+ // Text colors
117
+ if (c.body_text) {
118
+ vars['--ah-color-text'] = c.body_text;
119
+ }
120
+ if (c.header) {
121
+ vars['--ah-color-text-header'] = c.header;
122
+ }
123
+ if (c.input_labels_placeholders) {
124
+ vars['--ah-color-text-label'] = c.input_labels_placeholders;
125
+ vars['--ah-color-text-muted'] = c.input_labels_placeholders;
126
+ }
127
+ if (c.input_filled_text) {
128
+ vars['--ah-color-input-text'] = c.input_filled_text;
129
+ }
130
+ // Backgrounds
131
+ if (c.widget_background) {
132
+ vars['--ah-color-bg'] = c.widget_background;
133
+ }
134
+ if (c.input_background) {
135
+ vars['--ah-color-input-bg'] = c.input_background;
136
+ }
137
+ // Borders
138
+ if (c.widget_border) {
139
+ vars['--ah-widget-border-color'] = c.widget_border;
140
+ }
141
+ if (c.input_border) {
142
+ vars['--ah-color-border'] = c.input_border;
143
+ }
144
+ // Links
145
+ if (c.links_focused_components) {
146
+ vars['--ah-color-link'] = c.links_focused_components;
147
+ }
148
+ // Focus/hover
149
+ if (c.base_focus_color) {
150
+ vars['--ah-color-focus-ring'] = c.base_focus_color;
151
+ }
152
+ if (c.base_hover_color) {
153
+ vars['--ah-color-primary-hover'] = c.base_hover_color;
154
+ }
155
+ // Semantic colors
156
+ if (c.error) {
157
+ vars['--ah-color-error'] = c.error;
158
+ }
159
+ if (c.success) {
160
+ vars['--ah-color-success'] = c.success;
161
+ }
162
+ // Icons
163
+ if (c.icons) {
164
+ vars['--ah-color-icon'] = c.icons;
165
+ }
166
+ }
167
+ // Fonts
168
+ if (theme.fonts) {
169
+ const f = theme.fonts;
170
+ if (f.font_url) {
171
+ vars['--ah-font-url'] = f.font_url;
172
+ }
173
+ if (f.reference_text_size) {
174
+ vars['--ah-font-size-base'] = `${f.reference_text_size}px`;
175
+ }
176
+ if (f.title?.size) {
177
+ vars['--ah-font-size-title'] = `${f.title.size}px`;
178
+ }
179
+ if (f.subtitle?.size) {
180
+ vars['--ah-font-size-subtitle'] = `${f.subtitle.size}px`;
181
+ }
182
+ if (f.body_text?.size) {
183
+ vars['--ah-font-size-body'] = `${f.body_text.size}px`;
184
+ }
185
+ if (f.input_labels?.size) {
186
+ vars['--ah-font-size-label'] = `${f.input_labels.size}px`;
187
+ }
188
+ if (f.buttons_text?.size) {
189
+ vars['--ah-font-size-btn'] = `${f.buttons_text.size}px`;
190
+ }
191
+ if (f.links?.size) {
192
+ vars['--ah-font-size-link'] = `${f.links.size}px`;
193
+ }
194
+ if (f.links_style === 'underlined') {
195
+ vars['--ah-link-decoration'] = 'underline';
196
+ }
197
+ // Font weights
198
+ if (f.title?.bold) {
199
+ vars['--ah-font-weight-title'] = '700';
200
+ }
201
+ if (f.buttons_text?.bold) {
202
+ vars['--ah-font-weight-btn'] = '600';
203
+ }
204
+ }
205
+ // Widget settings
206
+ if (theme.widget) {
207
+ const w = theme.widget;
208
+ if (w.header_text_alignment) {
209
+ vars['--ah-title-align'] = w.header_text_alignment;
210
+ }
211
+ if (w.logo_height) {
212
+ vars['--ah-logo-height'] = `${w.logo_height}px`;
213
+ }
214
+ if (w.logo_position) {
215
+ const positionMap = {
216
+ center: 'center',
217
+ left: 'flex-start',
218
+ right: 'flex-end',
219
+ none: 'none',
220
+ };
221
+ vars['--ah-logo-align'] = positionMap[w.logo_position] ?? 'center';
222
+ }
223
+ }
224
+ // Page background
225
+ if (theme.page_background) {
226
+ const pb = theme.page_background;
227
+ if (pb.background_color) {
228
+ vars['--ah-page-bg'] = pb.background_color;
229
+ }
230
+ if (pb.background_image_url) {
231
+ vars['--ah-page-bg-image'] = `url(${pb.background_image_url})`;
232
+ }
233
+ }
234
+ return vars;
235
+ }
236
+ /**
237
+ * Merge branding and theme into a single CSS variables object
238
+ */
239
+ function mergeThemeVars(branding, theme) {
240
+ return {
241
+ ...brandingToCssVars(branding),
242
+ ...themeToCssVars(theme),
243
+ };
244
+ }
245
+ /**
246
+ * Apply CSS variables to an element's style
247
+ */
248
+ function applyCssVars(element, vars) {
249
+ Object.entries(vars).forEach(([key, value]) => {
250
+ element.style.setProperty(key, value);
251
+ });
252
+ }
253
+
254
+ 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)}`;
255
+
256
+ const AuthheroWidget = class {
257
+ constructor(hostRef) {
258
+ index.registerInstance(this, hostRef);
259
+ this.formSubmit = index.createEvent(this, "formSubmit");
260
+ this.buttonClick = index.createEvent(this, "buttonClick");
261
+ this.linkClick = index.createEvent(this, "linkClick");
262
+ this.navigate = index.createEvent(this, "navigate");
263
+ this.flowComplete = index.createEvent(this, "flowComplete");
264
+ this.flowError = index.createEvent(this, "flowError");
265
+ this.screenChange = index.createEvent(this, "screenChange");
266
+ }
267
+ get el() { return index.getElement(this); }
268
+ /**
269
+ * The UI screen configuration from the server.
270
+ * Can be passed as a JSON string or object.
271
+ * Follows Auth0 Forms component schema.
272
+ */
273
+ screen;
274
+ /**
275
+ * API endpoint to fetch the initial screen from.
276
+ * If provided, the widget will fetch the screen on load.
277
+ */
278
+ apiUrl;
279
+ /**
280
+ * Branding configuration from AuthHero API.
281
+ * Controls logo, primary color, and page background.
282
+ * Can be passed as a JSON string or object.
283
+ */
284
+ branding;
285
+ /**
286
+ * Theme configuration from AuthHero API.
287
+ * Controls colors, borders, fonts, and layout.
288
+ * Can be passed as a JSON string or object.
289
+ */
290
+ theme;
291
+ /**
292
+ * Whether the widget is in a loading state.
293
+ */
294
+ loading = false;
295
+ /**
296
+ * Whether the widget should automatically submit forms to the action URL.
297
+ * When false (default), the widget only emits events and the consuming
298
+ * application handles all HTTP requests.
299
+ * When true, the widget handles form submission and screen updates.
300
+ * @default false
301
+ */
302
+ autoSubmit = false;
303
+ /**
304
+ * Internal parsed screen state.
305
+ */
306
+ _screen;
307
+ /**
308
+ * Internal parsed branding state.
309
+ */
310
+ _branding;
311
+ /**
312
+ * Internal parsed theme state.
313
+ */
314
+ _theme;
315
+ /**
316
+ * Form data collected from inputs.
317
+ */
318
+ formData = {};
319
+ /**
320
+ * Emitted when the form is submitted.
321
+ * The consuming application should handle the submission unless autoSubmit is true.
322
+ */
323
+ formSubmit;
324
+ /**
325
+ * Emitted when a non-submit button is clicked (social login, back, etc.).
326
+ * The consuming application decides what to do based on id/type/value.
327
+ */
328
+ buttonClick;
329
+ /**
330
+ * Emitted when a link is clicked.
331
+ * The consuming application decides how to handle navigation.
332
+ */
333
+ linkClick;
334
+ /**
335
+ * Emitted when the widget wants to navigate (e.g., after successful auth).
336
+ * The consuming application decides how to handle navigation.
337
+ */
338
+ navigate;
339
+ /**
340
+ * Emitted when auth flow completes with a redirect URL.
341
+ * The consuming application can redirect or extract the code.
342
+ */
343
+ flowComplete;
344
+ /**
345
+ * Emitted when an error occurs.
346
+ */
347
+ flowError;
348
+ /**
349
+ * Emitted when the screen changes.
350
+ */
351
+ screenChange;
352
+ watchScreen(newValue) {
353
+ if (typeof newValue === 'string') {
354
+ try {
355
+ this._screen = JSON.parse(newValue);
356
+ }
357
+ catch {
358
+ console.error('Failed to parse screen JSON');
359
+ }
360
+ }
361
+ else {
362
+ this._screen = newValue;
363
+ }
364
+ if (this._screen) {
365
+ this.screenChange.emit(this._screen);
366
+ }
367
+ }
368
+ watchBranding(newValue) {
369
+ if (typeof newValue === 'string') {
370
+ try {
371
+ this._branding = JSON.parse(newValue);
372
+ }
373
+ catch {
374
+ console.error('Failed to parse branding JSON');
375
+ }
376
+ }
377
+ else {
378
+ this._branding = newValue;
379
+ }
380
+ this.applyThemeStyles();
381
+ }
382
+ watchTheme(newValue) {
383
+ if (typeof newValue === 'string') {
384
+ try {
385
+ this._theme = JSON.parse(newValue);
386
+ }
387
+ catch {
388
+ console.error('Failed to parse theme JSON');
389
+ }
390
+ }
391
+ else {
392
+ this._theme = newValue;
393
+ }
394
+ this.applyThemeStyles();
395
+ }
396
+ /**
397
+ * Apply branding and theme as CSS custom properties
398
+ */
399
+ applyThemeStyles() {
400
+ const vars = mergeThemeVars(this._branding, this._theme);
401
+ applyCssVars(this.el, vars);
402
+ }
403
+ async componentWillLoad() {
404
+ // Parse initial props
405
+ this.watchScreen(this.screen);
406
+ this.watchBranding(this.branding);
407
+ this.watchTheme(this.theme);
408
+ // Fetch screen from API if URL provided and no screen prop
409
+ if (this.apiUrl && !this._screen) {
410
+ await this.fetchScreen();
411
+ }
412
+ }
413
+ async fetchScreen() {
414
+ if (!this.apiUrl)
415
+ return;
416
+ this.loading = true;
417
+ try {
418
+ const response = await fetch(this.apiUrl, {
419
+ credentials: 'include',
420
+ headers: {
421
+ Accept: 'application/json',
422
+ },
423
+ });
424
+ if (response.ok) {
425
+ this._screen = await response.json();
426
+ if (this._screen) {
427
+ this.screenChange.emit(this._screen);
428
+ }
429
+ }
430
+ }
431
+ catch (error) {
432
+ console.error('Failed to fetch screen:', error);
433
+ }
434
+ finally {
435
+ this.loading = false;
436
+ }
437
+ }
438
+ handleInputChange = (name, value) => {
439
+ this.formData = {
440
+ ...this.formData,
441
+ [name]: value,
442
+ };
443
+ };
444
+ handleSubmit = async (e) => {
445
+ e.preventDefault();
446
+ if (!this._screen)
447
+ return;
448
+ // Always emit the submit event
449
+ this.formSubmit.emit({
450
+ screen: this._screen,
451
+ data: this.formData,
452
+ });
453
+ // If autoSubmit is disabled, let the consuming app handle it
454
+ if (!this.autoSubmit) {
455
+ return;
456
+ }
457
+ // Submit to the server
458
+ this.loading = true;
459
+ try {
460
+ const response = await fetch(this._screen.action, {
461
+ method: this._screen.method,
462
+ credentials: 'include',
463
+ headers: {
464
+ 'Content-Type': 'application/json',
465
+ Accept: 'application/json',
466
+ },
467
+ body: JSON.stringify({ data: this.formData }),
468
+ });
469
+ const contentType = response.headers.get('content-type');
470
+ if (contentType?.includes('application/json')) {
471
+ const result = await response.json();
472
+ // Handle different response types
473
+ if (result.redirect) {
474
+ // Auth complete - emit complete event
475
+ this.flowComplete.emit({ redirectUrl: result.redirect });
476
+ // Also emit navigate for backwards compatibility
477
+ this.navigate.emit({ url: result.redirect });
478
+ }
479
+ else if (result.screen) {
480
+ // Next screen
481
+ this._screen = result.screen;
482
+ this.formData = {};
483
+ this.screenChange.emit(result.screen);
484
+ // Apply branding if included
485
+ if (result.branding) {
486
+ this._branding = result.branding;
487
+ this.applyThemeStyles();
488
+ }
489
+ }
490
+ else if (result.complete) {
491
+ // Flow complete without redirect
492
+ this.flowComplete.emit({});
493
+ }
494
+ // Handle validation errors (400 response)
495
+ if (!response.ok && result.screen) {
496
+ this._screen = result.screen;
497
+ this.screenChange.emit(result.screen);
498
+ }
499
+ }
500
+ }
501
+ catch (err) {
502
+ console.error('Form submission failed:', err);
503
+ this.flowError.emit({
504
+ message: err instanceof Error ? err.message : 'Form submission failed',
505
+ });
506
+ }
507
+ finally {
508
+ this.loading = false;
509
+ }
510
+ };
511
+ handleButtonClick = (detail) => {
512
+ this.buttonClick.emit(detail);
513
+ };
514
+ handleLinkClick = (e, link) => {
515
+ // Emit the event so the consuming app can handle it
516
+ this.linkClick.emit({
517
+ id: link.id,
518
+ href: link.href,
519
+ text: link.text,
520
+ });
521
+ // If autoSubmit is enabled, let the browser handle the navigation
522
+ // Otherwise, prevent default and let the app decide
523
+ if (!this.autoSubmit) {
524
+ e.preventDefault();
525
+ }
526
+ };
527
+ /**
528
+ * Get error messages from the screen-level messages array.
529
+ */
530
+ getScreenErrors() {
531
+ return this._screen?.messages?.filter((m) => m.type === 'error') || [];
532
+ }
533
+ /**
534
+ * Get success messages from the screen-level messages array.
535
+ */
536
+ getScreenSuccesses() {
537
+ return this._screen?.messages?.filter((m) => m.type === 'success') || [];
538
+ }
539
+ /**
540
+ * Sort components by order.
541
+ */
542
+ getOrderedComponents() {
543
+ if (!this._screen)
544
+ return [];
545
+ return [...this._screen.components]
546
+ .filter((c) => c.visible !== false)
547
+ .sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
548
+ }
549
+ render() {
550
+ if (this.loading && !this._screen) {
551
+ return (index.h("div", { class: "widget-container" }, index.h("div", { class: "loading-spinner" })));
552
+ }
553
+ if (!this._screen) {
554
+ return (index.h("div", { class: "widget-container" }, index.h("div", { class: "error-message" }, "No screen configuration provided")));
555
+ }
556
+ const screenErrors = this.getScreenErrors();
557
+ const screenSuccesses = this.getScreenSuccesses();
558
+ const components = this.getOrderedComponents();
559
+ // Get logo URL from branding props
560
+ const logoUrl = this._branding?.logo_url;
561
+ return (index.h("div", { class: "widget-container", part: "container" }, logoUrl && index.h("img", { class: "logo", part: "logo", src: logoUrl, alt: "Logo" }), this._screen.title && (index.h("h1", { class: "title", part: "title" }, this._screen.title)), this._screen.description && (index.h("p", { class: "description", part: "description" }, this._screen.description)), 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, part: "form" }, components.map((component) => (index.h("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 && (index.h("div", { class: "links", part: "links" }, this._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, { id: link.id, href: link.href, text: link.linkText || link.text }) }, link.linkText))) : (index.h("a", { href: link.href, class: "link", part: "link", onClick: (e) => this.handleLinkClick(e, { id: link.id, href: link.href, text: link.text }) }, link.text)))))))));
562
+ }
563
+ static get watchers() { return {
564
+ "screen": [{
565
+ "watchScreen": 0
566
+ }],
567
+ "branding": [{
568
+ "watchBranding": 0
569
+ }],
570
+ "theme": [{
571
+ "watchTheme": 0
572
+ }]
573
+ }; }
574
+ };
575
+ AuthheroWidget.style = authheroWidgetCss();
576
+
577
+ exports.authhero_widget = AuthheroWidget;
@@ -0,0 +1,25 @@
1
+ 'use strict';
2
+
3
+ var index = require('./index-D0xitTOL.js');
4
+ var appGlobals = require('./app-globals-V2Kpy_OQ.js');
5
+
6
+ var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
7
+ /*
8
+ Stencil Client Patch Browser v4.41.0 | MIT Licensed | https://stenciljs.com
9
+ */
10
+
11
+ var patchBrowser = () => {
12
+ const importMeta = (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('authhero-widget.cjs.js', document.baseURI).href));
13
+ const opts = {};
14
+ if (importMeta !== "") {
15
+ opts.resourcesUrl = new URL(".", importMeta).href;
16
+ }
17
+ return index.promiseResolve(opts);
18
+ };
19
+
20
+ patchBrowser().then(async (options) => {
21
+ await appGlobals.globalScripts();
22
+ return index.bootstrapLazy([["authhero-node.cjs",[[513,"authhero-node",{"component":[16],"value":[1],"disabled":[4]}]]],["authhero-widget.cjs",[[513,"authhero-widget",{"screen":[1],"apiUrl":[1,"api-url"],"branding":[1],"theme":[1],"loading":[1028],"autoSubmit":[4,"auto-submit"],"_screen":[32],"_branding":[32],"_theme":[32],"formData":[32]},null,{"screen":[{"watchScreen":0}],"branding":[{"watchBranding":0}],"theme":[{"watchTheme":0}]}]]]], options);
23
+ });
24
+
25
+ exports.setNonce = index.setNonce;