@authhero/widget 0.7.2 → 0.8.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.
- package/README.md +118 -66
- package/dist/authhero-widget/authhero-widget.esm.js +1 -1
- package/dist/authhero-widget/p-6e32b31d.entry.js +1 -0
- package/dist/cjs/authhero-widget.cjs.entry.js +311 -32
- package/dist/cjs/authhero-widget.cjs.js +1 -1
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/collection/components/authhero-widget/authhero-widget.js +470 -34
- package/dist/components/authhero-widget.js +1 -1
- package/dist/esm/authhero-widget.entry.js +311 -32
- package/dist/esm/authhero-widget.js +1 -1
- package/dist/esm/loader.js +1 -1
- package/dist/types/components/authhero-widget/authhero-widget.d.ts +96 -4
- package/dist/types/components.d.ts +66 -4
- package/hydrate/index.js +319 -32
- package/hydrate/index.mjs +319 -32
- package/package.json +2 -2
- package/dist/authhero-widget/p-ea2660b2.entry.js +0 -1
package/README.md
CHANGED
|
@@ -23,35 +23,34 @@ pnpm add @authhero/widget
|
|
|
23
23
|
### Browser (CDN)
|
|
24
24
|
|
|
25
25
|
```html
|
|
26
|
-
<script
|
|
26
|
+
<script
|
|
27
|
+
type="module"
|
|
28
|
+
src="https://unpkg.com/@authhero/widget/dist/authhero-widget/authhero-widget.esm.js"
|
|
29
|
+
></script>
|
|
27
30
|
|
|
28
|
-
<authhero-widget
|
|
29
|
-
api-url="/u/flow/screen"
|
|
30
|
-
auto-submit="false">
|
|
31
|
+
<authhero-widget api-url="/u/flow/screen" auto-submit="false">
|
|
31
32
|
</authhero-widget>
|
|
32
33
|
```
|
|
33
34
|
|
|
34
35
|
### With a JavaScript Framework
|
|
35
36
|
|
|
36
37
|
```javascript
|
|
37
|
-
import
|
|
38
|
+
import "@authhero/widget";
|
|
38
39
|
|
|
39
40
|
// Or with the loader for lazy-loading
|
|
40
|
-
import { defineCustomElements } from
|
|
41
|
+
import { defineCustomElements } from "@authhero/widget/loader";
|
|
41
42
|
defineCustomElements();
|
|
42
43
|
```
|
|
43
44
|
|
|
44
45
|
```html
|
|
45
|
-
<authhero-widget
|
|
46
|
-
api-url="/u/flow/screen"
|
|
47
|
-
auto-submit="false">
|
|
46
|
+
<authhero-widget api-url="/u/flow/screen" auto-submit="false">
|
|
48
47
|
</authhero-widget>
|
|
49
48
|
```
|
|
50
49
|
|
|
51
50
|
### Server-Side Rendering (Hono)
|
|
52
51
|
|
|
53
52
|
```typescript
|
|
54
|
-
import { renderToString } from
|
|
53
|
+
import { renderToString } from "@authhero/widget/hydrate";
|
|
55
54
|
|
|
56
55
|
const html = await renderToString(`
|
|
57
56
|
<authhero-widget screen='${JSON.stringify(screenConfig)}'></authhero-widget>
|
|
@@ -66,42 +65,42 @@ The widget renders UI based on Auth0's Forms API schema for universal login flow
|
|
|
66
65
|
|
|
67
66
|
The widget supports [27+ Auth0 component types](https://auth0.com/docs/authenticate/login/auth0-universal-login/new-experience/universal-login-page-templates):
|
|
68
67
|
|
|
69
|
-
| Component
|
|
70
|
-
|
|
71
|
-
| `heading`
|
|
72
|
-
| `description`
|
|
73
|
-
| `text-input`
|
|
74
|
-
| `password-input`
|
|
75
|
-
| `checkbox-input`
|
|
76
|
-
| `select-input`
|
|
77
|
-
| `submit-button`
|
|
78
|
-
| `button`
|
|
79
|
-
| `social-button-group` | Social login buttons
|
|
80
|
-
| `anchor`
|
|
81
|
-
| `separator`
|
|
82
|
-
| `image`
|
|
83
|
-
| And more...
|
|
68
|
+
| Component | Description |
|
|
69
|
+
| --------------------- | ------------------------------------ |
|
|
70
|
+
| `heading` | Page headings and titles |
|
|
71
|
+
| `description` | Descriptive text |
|
|
72
|
+
| `text-input` | Text, email, phone inputs |
|
|
73
|
+
| `password-input` | Password field with show/hide toggle |
|
|
74
|
+
| `checkbox-input` | Checkboxes |
|
|
75
|
+
| `select-input` | Dropdown selects |
|
|
76
|
+
| `submit-button` | Primary action buttons |
|
|
77
|
+
| `button` | Secondary action buttons |
|
|
78
|
+
| `social-button-group` | Social login buttons |
|
|
79
|
+
| `anchor` | Links and navigation |
|
|
80
|
+
| `separator` | Visual dividers |
|
|
81
|
+
| `image` | Logos and images |
|
|
82
|
+
| And more... | Phone input, captcha, MFA, etc. |
|
|
84
83
|
|
|
85
84
|
### Screen Configuration
|
|
86
85
|
|
|
87
86
|
```typescript
|
|
88
87
|
interface UIScreen {
|
|
89
|
-
title?: string;
|
|
90
|
-
description?: string;
|
|
91
|
-
components: UIComponent[];
|
|
88
|
+
title?: string; // Screen title
|
|
89
|
+
description?: string; // Screen description
|
|
90
|
+
components: UIComponent[]; // UI components to render
|
|
92
91
|
branding?: {
|
|
93
92
|
logoUrl?: string;
|
|
94
93
|
primaryColor?: string;
|
|
95
94
|
backgroundColor?: string;
|
|
96
95
|
};
|
|
97
|
-
theme?: string;
|
|
96
|
+
theme?: string; // Theme configuration JSON
|
|
98
97
|
}
|
|
99
98
|
|
|
100
99
|
interface UIComponent {
|
|
101
|
-
component: string;
|
|
102
|
-
id: string;
|
|
103
|
-
label?: string;
|
|
104
|
-
[key: string]: any;
|
|
100
|
+
component: string; // Component type (e.g., 'text-input', 'submit-button')
|
|
101
|
+
id: string; // Component identifier
|
|
102
|
+
label?: string; // Display label
|
|
103
|
+
[key: string]: any; // Component-specific props
|
|
105
104
|
}
|
|
106
105
|
```
|
|
107
106
|
|
|
@@ -172,54 +171,106 @@ Social buttons are configured using the `social-button-group` component:
|
|
|
172
171
|
|
|
173
172
|
## Props
|
|
174
173
|
|
|
175
|
-
| Prop
|
|
176
|
-
|
|
177
|
-
| `screen`
|
|
178
|
-
| `api-url`
|
|
179
|
-
| `branding`
|
|
180
|
-
| `theme`
|
|
181
|
-
| `loading`
|
|
182
|
-
| `auto-submit`
|
|
174
|
+
| Prop | Type | Default | Description |
|
|
175
|
+
| ------------------- | -------------------------------- | ------------------- | ------------------------------------------------------------------ |
|
|
176
|
+
| `screen` | `string \| UIScreen` | - | Screen configuration (JSON string or object) |
|
|
177
|
+
| `api-url` | `string` | - | API endpoint for screen fetching |
|
|
178
|
+
| `branding` | `string \| Branding` | - | Branding configuration |
|
|
179
|
+
| `theme` | `string` | - | Theme configuration JSON |
|
|
180
|
+
| `loading` | `boolean` | `false` | Loading state |
|
|
181
|
+
| `auto-submit` | `boolean` | `false` | Auto-submit forms to the action URL |
|
|
182
|
+
| `auto-navigate` | `boolean` | `false` | Auto-navigate on social login, links, and redirects |
|
|
183
|
+
| `state` | `string` | - | Login session state token |
|
|
184
|
+
| `screen-id` | `string` | - | Current screen ID for API fetching |
|
|
185
|
+
| `auth-params` | `string` | - | OAuth params JSON for social login (client_id, redirect_uri, etc.) |
|
|
186
|
+
| `base-url` | `string` | - | Base URL for API calls (for cross-domain embedding) |
|
|
187
|
+
| `state-persistence` | `'url' \| 'session' \| 'memory'` | `'memory'` | Where to persist state and screen ID |
|
|
188
|
+
| `storage-key` | `string` | `'authhero_widget'` | Storage key prefix for session persistence |
|
|
189
|
+
|
|
190
|
+
## Usage Modes
|
|
191
|
+
|
|
192
|
+
### 1. Event-Based (Default)
|
|
193
|
+
|
|
194
|
+
The widget emits events for your application to handle:
|
|
195
|
+
|
|
196
|
+
```html
|
|
197
|
+
<authhero-widget api-url="/u2/screen/identifier" state="your-state-token">
|
|
198
|
+
</authhero-widget>
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### 2. Self-Contained (Universal Login Pages)
|
|
202
|
+
|
|
203
|
+
The widget handles everything internally - ideal for hosted login pages:
|
|
204
|
+
|
|
205
|
+
```html
|
|
206
|
+
<authhero-widget
|
|
207
|
+
api-url="/u2/screen/{screenId}"
|
|
208
|
+
screen-id="identifier"
|
|
209
|
+
state="your-state-token"
|
|
210
|
+
auth-params='{"client_id":"abc123","redirect_uri":"https://app.example.com/callback"}'
|
|
211
|
+
auto-submit="true"
|
|
212
|
+
auto-navigate="true"
|
|
213
|
+
>
|
|
214
|
+
</authhero-widget>
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### 3. Embedded on External Pages
|
|
218
|
+
|
|
219
|
+
Use `base-url` when embedding the widget on a different domain:
|
|
220
|
+
|
|
221
|
+
```html
|
|
222
|
+
<authhero-widget
|
|
223
|
+
base-url="https://auth.example.com"
|
|
224
|
+
api-url="/u2/screen/{screenId}"
|
|
225
|
+
screen-id="identifier"
|
|
226
|
+
state="your-state-token"
|
|
227
|
+
auth-params='{"client_id":"abc123"}'
|
|
228
|
+
auto-submit="true"
|
|
229
|
+
auto-navigate="true"
|
|
230
|
+
state-persistence="session"
|
|
231
|
+
>
|
|
232
|
+
</authhero-widget>
|
|
233
|
+
```
|
|
183
234
|
|
|
184
235
|
## Events
|
|
185
236
|
|
|
186
237
|
The widget is a **pure UI component** that emits events for your auth library to handle. It does not manage tokens, sessions, or HTTP requests.
|
|
187
238
|
|
|
188
|
-
| Event
|
|
189
|
-
|
|
190
|
-
| `formSubmit`
|
|
191
|
-
| `buttonClick`
|
|
192
|
-
| `linkClick`
|
|
193
|
-
| `navigate`
|
|
194
|
-
| `flowComplete` | `{ result: any }`
|
|
195
|
-
| `flowError`
|
|
196
|
-
| `screenChange` | `UIScreen`
|
|
239
|
+
| Event | Detail | Description |
|
|
240
|
+
| -------------- | -------------------------------------- | -------------------------------- |
|
|
241
|
+
| `formSubmit` | `{ data: FormData, screen: UIScreen }` | Form submitted by user |
|
|
242
|
+
| `buttonClick` | `{ id: string, action: string }` | Button clicked |
|
|
243
|
+
| `linkClick` | `{ href: string }` | Link clicked |
|
|
244
|
+
| `navigate` | `{ to: string }` | Navigation requested |
|
|
245
|
+
| `flowComplete` | `{ result: any }` | Auth flow completed successfully |
|
|
246
|
+
| `flowError` | `{ error: Error }` | Auth flow error occurred |
|
|
247
|
+
| `screenChange` | `UIScreen` | Screen changed |
|
|
197
248
|
|
|
198
249
|
### Event-Based Integration (Recommended)
|
|
199
250
|
|
|
200
251
|
The recommended approach is to handle events and let your auth library manage the flow:
|
|
201
252
|
|
|
202
253
|
```javascript
|
|
203
|
-
const widget = document.querySelector(
|
|
254
|
+
const widget = document.querySelector("authhero-widget");
|
|
204
255
|
|
|
205
|
-
widget.addEventListener(
|
|
256
|
+
widget.addEventListener("formSubmit", async (e) => {
|
|
206
257
|
const { data, screen } = e.detail;
|
|
207
|
-
|
|
258
|
+
|
|
208
259
|
try {
|
|
209
260
|
// Your auth library handles the HTTP request
|
|
210
|
-
const response = await fetch(
|
|
211
|
-
method:
|
|
261
|
+
const response = await fetch("/u/flow/screen", {
|
|
262
|
+
method: "POST",
|
|
212
263
|
body: data,
|
|
213
264
|
});
|
|
214
|
-
|
|
265
|
+
|
|
215
266
|
const nextScreen = await response.json();
|
|
216
267
|
widget.screen = JSON.stringify(nextScreen);
|
|
217
268
|
} catch (error) {
|
|
218
|
-
widget.dispatchEvent(new CustomEvent(
|
|
269
|
+
widget.dispatchEvent(new CustomEvent("flowError", { detail: { error } }));
|
|
219
270
|
}
|
|
220
271
|
});
|
|
221
272
|
|
|
222
|
-
widget.addEventListener(
|
|
273
|
+
widget.addEventListener("linkClick", (e) => {
|
|
223
274
|
// Handle navigation
|
|
224
275
|
window.location.href = e.detail.href;
|
|
225
276
|
});
|
|
@@ -230,14 +281,12 @@ widget.addEventListener('linkClick', (e) => {
|
|
|
230
281
|
For simple use cases, the widget can handle HTTP requests automatically:
|
|
231
282
|
|
|
232
283
|
```html
|
|
233
|
-
<authhero-widget
|
|
234
|
-
api-url="/u/flow/screen"
|
|
235
|
-
auto-submit="true">
|
|
236
|
-
</authhero-widget>
|
|
284
|
+
<authhero-widget api-url="/u/flow/screen" auto-submit="true"> </authhero-widget>
|
|
237
285
|
```
|
|
238
286
|
|
|
239
287
|
⚠️ **Note**: Auto-submit mode is provided for convenience but is not recommended for production. Use the event-based approach for proper error handling, token management, and integration with auth libraries like Auth0 SPA SDK.
|
|
240
|
-
|
|
288
|
+
|
|
289
|
+
````
|
|
241
290
|
|
|
242
291
|
## Customization
|
|
243
292
|
|
|
@@ -250,7 +299,7 @@ authhero-widget {
|
|
|
250
299
|
--text-color: #333333;
|
|
251
300
|
--border-radius: 8px;
|
|
252
301
|
}
|
|
253
|
-
|
|
302
|
+
````
|
|
254
303
|
|
|
255
304
|
### Server-Side Branding
|
|
256
305
|
|
|
@@ -276,7 +325,8 @@ See [`packages/authhero/FLOWS.md`](../authhero/FLOWS.md) for detailed integratio
|
|
|
276
325
|
3. **Auth0 SPA SDK Integration** - Using `loginWithRedirect()` and callback handling
|
|
277
326
|
4. **Custom Token Management** - Custom refresh token and session handling
|
|
278
327
|
5. **Generic Forms** - Non-auth form use cases
|
|
279
|
-
|
|
328
|
+
|
|
329
|
+
````
|
|
280
330
|
|
|
281
331
|
## Development
|
|
282
332
|
|
|
@@ -295,7 +345,7 @@ pnpm build
|
|
|
295
345
|
|
|
296
346
|
# Run tests
|
|
297
347
|
pnpm test
|
|
298
|
-
|
|
348
|
+
````
|
|
299
349
|
|
|
300
350
|
### Demo Server
|
|
301
351
|
|
|
@@ -306,10 +356,12 @@ The widget includes a demo server at `demo-server/server.ts` that provides:
|
|
|
306
356
|
- **Server-Driven UI**: Demonstrates how the widget integrates with a backend
|
|
307
357
|
|
|
308
358
|
When you run `pnpm dev`, the demo is available at:
|
|
359
|
+
|
|
309
360
|
- Path-based: http://localhost:3456/u2/login/identifier
|
|
310
361
|
- Query-based: http://localhost:3456/u2/login?screen=identifier
|
|
311
362
|
|
|
312
363
|
The demo server provides:
|
|
364
|
+
|
|
313
365
|
- `GET /u2/screen/:screenId` - Returns screen configuration
|
|
314
366
|
- `POST /u2/screen/:screenId` - Processes form submissions and returns next screen
|
|
315
367
|
- Settings panel to customize theme, branding, and widget options
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{p as
|
|
1
|
+
import{p as a,b as e}from"./p-BzFenraS.js";export{s as setNonce}from"./p-BzFenraS.js";import{g as t}from"./p-DQuL1Twl.js";(()=>{const e=import.meta.url,t={};return""!==e&&(t.resourcesUrl=new URL(".",e).href),a(t)})().then((async a=>(await t(),e([["p-188ffffd",[[513,"authhero-node",{component:[16],value:[1],disabled:[4],passwordVisible:[32]}]]],["p-6e32b31d",[[513,"authhero-widget",{screen:[1],apiUrl:[1,"api-url"],baseUrl:[1,"base-url"],state:[1025],screenId:[1025,"screen-id"],authParams:[1,"auth-params"],statePersistence:[1,"state-persistence"],storageKey:[1,"storage-key"],branding:[1],theme:[1],loading:[1028],autoSubmit:[4,"auto-submit"],autoNavigate:[4,"auto-navigate"],_screen:[32],_authParams:[32],_branding:[32],_theme:[32],formData:[32]},null,{screen:[{watchScreen:0}],branding:[{watchBranding:0}],theme:[{watchTheme:0}],authParams:[{watchAuthParams:0}]}]]]],a))));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{r as t,c as i,g as e,h as s}from"./p-BzFenraS.js";function a(t,i){if(void 0!==i)return`${i}px`;switch(t){case"pill":return"9999px";case"rounded":return"8px";case"sharp":return"0";default:return}}function r(t){if(!t)return{};const i={};if(t.colors?.primary&&(i["--ah-color-primary"]=t.colors.primary,i["--ah-color-primary-hover"]=t.colors.primary),t.colors?.page_background){const e=t.colors.page_background;"solid"===e.type&&e.start?i["--ah-page-bg"]=e.start:"gradient"===e.type&&e.start&&e.end&&(i["--ah-page-bg"]=`linear-gradient(${e.angle_deg??180}deg, ${e.start}, ${e.end})`)}return t.logo_url&&(i["--ah-logo-url"]=`url(${t.logo_url})`),t.font?.url&&(i["--ah-font-url"]=t.font.url),i}function o(t){if(!t)return{};const i={};if(t.borders){const e=t.borders;void 0!==e.widget_corner_radius&&(i["--ah-widget-radius"]=`${e.widget_corner_radius}px`),void 0!==e.widget_border_weight&&(i["--ah-widget-border-width"]=`${e.widget_border_weight}px`),!1===e.show_widget_shadow&&(i["--ah-widget-shadow"]="none");const s=a(e.buttons_style,e.button_border_radius);s&&(i["--ah-btn-radius"]=s),void 0!==e.button_border_weight&&(i["--ah-btn-border-width"]=`${e.button_border_weight}px`);const r=a(e.inputs_style,e.input_border_radius);r&&(i["--ah-input-radius"]=r),void 0!==e.input_border_weight&&(i["--ah-input-border-width"]=`${e.input_border_weight}px`)}if(t.colors){const e=t.colors;e.primary_button&&(i["--ah-color-primary"]=e.primary_button,i["--ah-color-primary-hover"]=e.primary_button),e.primary_button_label&&(i["--ah-btn-primary-text"]=e.primary_button_label),e.secondary_button_border&&(i["--ah-btn-secondary-border"]=e.secondary_button_border),e.secondary_button_label&&(i["--ah-btn-secondary-text"]=e.secondary_button_label),e.body_text&&(i["--ah-color-text"]=e.body_text),e.header&&(i["--ah-color-text-header"]=e.header),e.input_labels_placeholders&&(i["--ah-color-text-label"]=e.input_labels_placeholders,i["--ah-color-text-muted"]=e.input_labels_placeholders),e.input_filled_text&&(i["--ah-color-input-text"]=e.input_filled_text),e.widget_background&&(i["--ah-color-bg"]=e.widget_background),e.input_background&&(i["--ah-color-input-bg"]=e.input_background),e.widget_border&&(i["--ah-widget-border-color"]=e.widget_border),e.input_border&&(i["--ah-color-border"]=e.input_border),e.links_focused_components&&(i["--ah-color-link"]=e.links_focused_components),e.base_focus_color&&(i["--ah-color-focus-ring"]=e.base_focus_color),e.base_hover_color&&(i["--ah-color-primary-hover"]=e.base_hover_color),e.error&&(i["--ah-color-error"]=e.error),e.success&&(i["--ah-color-success"]=e.success),e.icons&&(i["--ah-color-icon"]=e.icons)}if(t.fonts){const e=t.fonts,s=e.reference_text_size||16;if(e.font_url&&(i["--ah-font-url"]=e.font_url),e.reference_text_size&&(i["--ah-font-size-base"]=`${e.reference_text_size}px`),e.title?.size){const t=Math.round(e.title.size/100*s);i["--ah-font-size-title"]=`${t}px`}if(e.subtitle?.size){const t=Math.round(e.subtitle.size/100*s);i["--ah-font-size-subtitle"]=`${t}px`}if(e.body_text?.size){const t=Math.round(e.body_text.size/100*s);i["--ah-font-size-body"]=`${t}px`}if(e.input_labels?.size){const t=Math.round(e.input_labels.size/100*s);i["--ah-font-size-label"]=`${t}px`}if(e.buttons_text?.size){const t=Math.round(e.buttons_text.size/100*s);i["--ah-font-size-btn"]=`${t}px`}if(e.links?.size){const t=Math.round(e.links.size/100*s);i["--ah-font-size-link"]=`${t}px`}"underlined"===e.links_style&&(i["--ah-link-decoration"]="underline"),void 0!==e.title?.bold&&(i["--ah-font-weight-title"]=e.title.bold?"700":"400"),void 0!==e.subtitle?.bold&&(i["--ah-font-weight-subtitle"]=e.subtitle.bold?"700":"400"),void 0!==e.body_text?.bold&&(i["--ah-font-weight-body"]=e.body_text.bold?"700":"400"),void 0!==e.input_labels?.bold&&(i["--ah-font-weight-label"]=e.input_labels.bold?"700":"400"),void 0!==e.buttons_text?.bold&&(i["--ah-font-weight-btn"]=e.buttons_text.bold?"600":"400"),void 0!==e.links?.bold&&(i["--ah-font-weight-link"]=e.links.bold?"700":"400")}if(t.widget){const e=t.widget;if(e.header_text_alignment&&(i["--ah-title-align"]=e.header_text_alignment),e.logo_height&&(i["--ah-logo-height"]=`${e.logo_height}px`),e.logo_position){const t={center:"center",left:"flex-start",right:"flex-end"};"none"===e.logo_position?i["--ah-logo-display"]="none":i["--ah-logo-align"]=t[e.logo_position]??"center"}e.social_buttons_layout&&("top"===e.social_buttons_layout?(i["--ah-social-order"]="0",i["--ah-divider-order"]="1",i["--ah-fields-order"]="2"):(i["--ah-social-order"]="2",i["--ah-divider-order"]="1",i["--ah-fields-order"]="0"))}if(t.page_background){const e=t.page_background;e.background_color&&(i["--ah-page-bg"]=e.background_color),e.background_image_url&&(i["--ah-page-bg-image"]=`url(${e.background_image_url})`)}return i}const n=class{constructor(e){t(this,e),this.formSubmit=i(this,"formSubmit"),this.buttonClick=i(this,"buttonClick"),this.linkClick=i(this,"linkClick"),this.navigate=i(this,"navigate"),this.flowComplete=i(this,"flowComplete"),this.flowError=i(this,"flowError"),this.screenChange=i(this,"screenChange")}get el(){return e(this)}screen;apiUrl;baseUrl;state;screenId;authParams;statePersistence="memory";storageKey="authhero_widget";branding;theme;loading=!1;autoSubmit=!1;autoNavigate;_screen;_authParams;_branding;_theme;formData={};formSubmit;buttonClick;linkClick;navigate;flowComplete;flowError;screenChange;watchScreen(t){if("string"==typeof t)try{this._screen=JSON.parse(t)}catch{console.error("Failed to parse screen JSON")}else this._screen=t;this._screen&&this.screenChange.emit(this._screen)}watchBranding(t){if("string"==typeof t)try{this._branding=JSON.parse(t)}catch{console.error("Failed to parse branding JSON")}else this._branding=t;this.applyThemeStyles()}watchTheme(t){if("string"==typeof t)try{this._theme=JSON.parse(t)}catch{console.error("Failed to parse theme JSON")}else this._theme=t;this.applyThemeStyles()}watchAuthParams(t){if("string"==typeof t)try{this._authParams=JSON.parse(t)}catch{console.error("Failed to parse authParams JSON")}else this._authParams=t}applyThemeStyles(){const t=(i=this._theme,{...r(this._branding),...o(i)});var i;!function(t,i){Object.entries(i).forEach((([i,e])=>{t.style.setProperty(i,e)}))}(this.el,t)}get shouldAutoNavigate(){return this.autoNavigate??this.autoSubmit}buildUrl(t){return this.baseUrl?new URL(t,this.baseUrl).toString():t}loadPersistedState(){if("url"===this.statePersistence){const t=new URL(window.location.href).searchParams.get("state");t&&!this.state&&(this.state=t)}else if("session"===this.statePersistence)try{const t=sessionStorage.getItem(`${this.storageKey}_state`);t&&!this.state&&(this.state=t);const i=sessionStorage.getItem(`${this.storageKey}_screenId`);i&&!this.screenId&&(this.screenId=i)}catch{}}persistState(){if("url"===this.statePersistence){const t=new URL(window.location.href);this.state&&t.searchParams.set("state",this.state),this.screenId&&t.searchParams.set("screen",this.screenId),window.history.replaceState({},"",t.toString())}else if("session"===this.statePersistence)try{this.state&&sessionStorage.setItem(`${this.storageKey}_state`,this.state),this.screenId&&sessionStorage.setItem(`${this.storageKey}_screenId`,this.screenId)}catch{}}async componentWillLoad(){this.watchScreen(this.screen),this.watchBranding(this.branding),this.watchTheme(this.theme),this.watchAuthParams(this.authParams),this.loadPersistedState(),this.apiUrl&&!this._screen&&await this.fetchScreen(this.screenId)}async fetchScreen(t,i){if(!this.apiUrl)return;const e=t||this.screenId;let s=this.apiUrl;e&&s.includes("{screenId}")&&(s=s.replace("{screenId}",encodeURIComponent(e)));const a=new URL(s,this.baseUrl||window.location.origin);this.state&&a.searchParams.set("state",this.state),i&&a.searchParams.set("nodeId",i),this.loading=!0;try{const t=await fetch(this.buildUrl(a.pathname+a.search),{credentials:"include",headers:{Accept:"application/json"}});if(t.ok){const i=await t.json();i.screen?(this._screen=i.screen,i.branding&&(this._branding=i.branding,this.applyThemeStyles()),i.state&&(this.state=i.state),i.screenId&&(this.screenId=i.screenId)):this._screen=i,this._screen&&(e&&e!==this.screenId&&(this.screenId=e),this.screenChange.emit(this._screen),this.persistState())}else{const i=await t.json().catch((()=>({message:"Failed to load screen"})));this.flowError.emit({message:i.message||"Failed to load screen"})}}catch(t){console.error("Failed to fetch screen:",t),this.flowError.emit({message:t instanceof Error?t.message:"Failed to fetch screen"})}finally{this.loading=!1}}handleInputChange=(t,i)=>{this.formData={...this.formData,[t]:i}};handleSubmit=async t=>{if(t.preventDefault(),this._screen&&(this.formSubmit.emit({screen:this._screen,data:this.formData}),this.autoSubmit)){this.loading=!0;try{const t=await fetch(this.buildUrl(this._screen.action),{method:this._screen.method,credentials:"include",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({data:this.formData})}),i=t.headers.get("content-type");if(i?.includes("application/json")){const i=await t.json();i.redirect?(this.flowComplete.emit({redirectUrl:i.redirect}),this.navigate.emit({url:i.redirect}),this.shouldAutoNavigate&&(window.location.href=i.redirect)):i.screen?(this._screen=i.screen,this.formData={},this.screenChange.emit(i.screen),i.screenId&&(this.screenId=i.screenId),this.persistState(),i.branding&&(this._branding=i.branding,this.applyThemeStyles()),i.state&&(this.state=i.state,this.persistState())):i.complete&&this.flowComplete.emit({}),!t.ok&&i.screen&&(this._screen=i.screen,this.screenChange.emit(i.screen))}}catch(t){console.error("Form submission failed:",t),this.flowError.emit({message:t instanceof Error?t.message:"Form submission failed"})}finally{this.loading=!1}}};handleButtonClick=t=>{"submit"!==t.type?(this.buttonClick.emit(t),"SOCIAL"===t.type&&t.value&&this.shouldAutoNavigate?this.handleSocialLogin(t.value):"RESEND_BUTTON"===t.type&&this.shouldAutoNavigate&&this.handleResend()):this.handleSubmit({preventDefault:()=>{}})};handleSocialLogin(t){const i=this._authParams||{},e={connection:t};this.state?e.state=this.state:i.state&&(e.state=i.state),i.client_id&&(e.client_id=i.client_id),i.redirect_uri&&(e.redirect_uri=i.redirect_uri),i.scope&&(e.scope=i.scope),i.audience&&(e.audience=i.audience),i.nonce&&(e.nonce=i.nonce),i.response_type&&(e.response_type=i.response_type);const s=this.buildUrl("/authorize?"+new URLSearchParams(e).toString());this.navigate.emit({url:s}),window.location.href=s}async handleResend(){if(this._screen?.action)try{const t=this._screen.action+(this._screen.action.includes("?")?"&":"?")+"action=resend";await fetch(this.buildUrl(t),{method:"POST",credentials:"include"})}catch(t){console.error("Resend failed:",t)}}handleLinkClick=(t,i)=>{this.linkClick.emit({id:i.id,href:i.href,text:i.text}),this.shouldAutoNavigate||t.preventDefault()};getScreenErrors(){return this._screen?.messages?.filter((t=>"error"===t.type))||[]}getScreenSuccesses(){return this._screen?.messages?.filter((t=>"success"===t.type))||[]}getOrderedComponents(){return this._screen?[...this._screen.components].filter((t=>!1!==t.visible)).sort(((t,i)=>(t.order??0)-(i.order??0))):[]}isSocialComponent(t){return"SOCIAL"===t.type}isDividerComponent(t){return"DIVIDER"===t.type}render(){if(this.loading&&!this._screen)return s("div",{class:"widget-container"},s("div",{class:"loading-spinner"}));if(!this._screen)return s("div",{class:"widget-container"},s("div",{class:"error-message"},"No screen configuration provided"));const t=this.getScreenErrors(),i=this.getScreenSuccesses(),e=this.getOrderedComponents(),a=e.filter((t=>this.isSocialComponent(t))),r=e.filter((t=>!this.isSocialComponent(t)&&!this.isDividerComponent(t))),o=e.some((t=>this.isDividerComponent(t))),n=this._theme?.widget?.logo_url||this._branding?.logo_url;return s("div",{class:"widget-container",part:"container"},s("header",{class:"widget-header",part:"header"},n&&s("div",{class:"logo-wrapper",part:"logo-wrapper"},s("img",{class:"logo",part:"logo",src:n,alt:"Logo"})),this._screen.title&&s("h1",{class:"title",part:"title"},this._screen.title),this._screen.description&&s("p",{class:"description",part:"description"},this._screen.description)),s("div",{class:"widget-body",part:"body"},t.map((t=>s("div",{class:"message message-error",part:"message message-error",key:t.id??t.text},t.text))),i.map((t=>s("div",{class:"message message-success",part:"message message-success",key:t.id??t.text},t.text))),s("form",{onSubmit:this.handleSubmit,part:"form"},s("div",{class:"form-content"},a.length>0&&s("div",{class:"social-section",part:"social-section"},a.map((t=>s("authhero-node",{key:t.id,component:t,value:this.formData[t.id],onFieldChange:t=>this.handleInputChange(t.detail.id,t.detail.value),onButtonClick:t=>this.handleButtonClick(t.detail),disabled:this.loading})))),a.length>0&&r.length>0&&o&&s("div",{class:"divider",part:"divider"},s("span",{class:"divider-text"},"Or")),s("div",{class:"fields-section",part:"fields-section"},r.map((t=>s("authhero-node",{key:t.id,component:t,value:this.formData[t.id],onFieldChange:t=>this.handleInputChange(t.detail.id,t.detail.value),onButtonClick:t=>this.handleButtonClick(t.detail),disabled:this.loading})))))),this._screen.links&&this._screen.links.length>0&&s("div",{class:"links",part:"links"},this._screen.links.map((t=>s("span",{class:"link-wrapper",part:"link-wrapper",key:t.id??t.href},t.linkText?s("span",null,t.text," ",s("a",{href:t.href,class:"link",part:"link",onClick:i=>this.handleLinkClick(i,{id:t.id,href:t.href,text:t.linkText||t.text})},t.linkText)):s("a",{href:t.href,class:"link",part:"link",onClick:i=>this.handleLinkClick(i,{id:t.id,href:t.href,text:t.text})},t.text)))))))}static get watchers(){return{screen:[{watchScreen:0}],branding:[{watchBranding:0}],theme:[{watchTheme:0}],authParams:[{watchAuthParams:0}]}}};n.style=":host{display:block;font-family:var(--ah-font-family, 'ulp-font', -apple-system, BlinkMacSystemFont, Roboto, Helvetica, sans-serif);font-size:var(--ah-font-size-base, 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 48px 24px)}.widget-body{padding:var(--ah-body-padding, 0 48px 40px)}.logo-wrapper{display:var(--ah-logo-display, flex);justify-content:var(--ah-logo-align, center);margin-bottom:8px}.logo{display:block;height:var(--ah-logo-height, 52px);max-width:100%;width:auto;object-fit:contain}.title{font-size:var(--ah-font-size-title, 24px);font-weight:var(--ah-font-weight-title, 700);text-align:var(--ah-title-align, center);margin:var(--ah-title-margin, 24px 0 8px);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 0 8px);color:var(--ah-color-text, #1e212a);line-height:1.5}.message{padding:12px 16px;border-radius:4px;margin-bottom:16px;font-size:14px;line-height:1.5}.message-error{background-color:var(--ah-color-error-bg, #ffeaea);color:var(--ah-color-error, #d03c38);border-left:3px solid var(--ah-color-error, #d03c38)}.message-success{background-color:var(--ah-color-success-bg, #e6f9f1);color:var(--ah-color-success, #13a769);border-left:3px solid var(--ah-color-success, #13a769)}form{display:flex;flex-direction:column}.form-content{display:flex;flex-direction:column}.social-section{display:flex;flex-direction:column;gap:8px;order:var(--ah-social-order, 2)}.fields-section{display:flex;flex-direction:column;order:var(--ah-fields-order, 0)}.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}@media (max-width: 480px){:host{display:block;width:100%;min-height:100vh;background-color:var(--ah-color-bg, #ffffff)}.widget-container{box-shadow:none;border-radius:0;max-width:none;width:100%;margin:0}.widget-header{padding:24px 16px 16px}.widget-body{padding:0 16px 24px}}";export{n as authhero_widget}
|