@hotosm/hanko-auth 0.4.5 → 0.4.7
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 +38 -9
- package/dist/hanko-auth.esm.js +782 -660
- package/dist/hanko-auth.iife.js +171 -57
- package/dist/hanko-auth.umd.js +172 -58
- package/package.json +1 -1
- package/src/hanko-auth.styles.ts +85 -19
- package/src/hanko-auth.ts +89 -2
package/package.json
CHANGED
package/src/hanko-auth.styles.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { css } from "lit";
|
|
|
3
3
|
export const styles = css`
|
|
4
4
|
:host {
|
|
5
5
|
display: block;
|
|
6
|
-
font-family: var(--hot-font-sans);
|
|
6
|
+
font-family: var(--font-family, var(--hot-font-sans));
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
.container {
|
|
@@ -38,28 +38,26 @@ export const styles = css`
|
|
|
38
38
|
animation: spin 1s linear infinite;
|
|
39
39
|
margin: 0 auto;
|
|
40
40
|
}
|
|
41
|
-
/* Container that mimics the
|
|
41
|
+
/* Container that mimics the avatar/dropdown-trigger dimensions */
|
|
42
42
|
.loading-placeholder {
|
|
43
43
|
display: inline-grid;
|
|
44
44
|
place-items: center;
|
|
45
|
-
/*
|
|
46
|
-
padding: var(--
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
border-radius: var(--login-btn-border-radius, var(--hot-border-radius-medium));
|
|
45
|
+
/* Match dropdown-trigger padding so size is stable pre/post load */
|
|
46
|
+
padding: var(--hot-spacing-x-small);
|
|
47
|
+
width: var(--hot-spacing-2x-large);
|
|
48
|
+
height: var(--hot-spacing-2x-large);
|
|
49
|
+
box-sizing: content-box;
|
|
51
50
|
}
|
|
52
51
|
|
|
53
52
|
/* Invisible text to reserve button width */
|
|
54
53
|
.loading-placeholder-text {
|
|
55
|
-
|
|
56
|
-
grid-area: 1 / 1;
|
|
54
|
+
display: none;
|
|
57
55
|
}
|
|
58
56
|
|
|
59
57
|
.spinner-small {
|
|
60
58
|
grid-area: 1 / 1;
|
|
61
|
-
width:
|
|
62
|
-
height:
|
|
59
|
+
width: var(--hot-spacing-2x-large);
|
|
60
|
+
height: var(--hot-spacing-2x-large);
|
|
63
61
|
border: 2px solid var(--hot-color-gray-200);
|
|
64
62
|
border-top: 2px solid var(--hot-color-gray-600);
|
|
65
63
|
border-radius: 50%;
|
|
@@ -87,7 +85,8 @@ export const styles = css`
|
|
|
87
85
|
border: none;
|
|
88
86
|
border-radius: 6px;
|
|
89
87
|
font-size: 14px;
|
|
90
|
-
font-
|
|
88
|
+
font-family: var(--font-family, var(--hot-font-sans));
|
|
89
|
+
font-weight: var(--font-weight, 500);
|
|
91
90
|
cursor: pointer;
|
|
92
91
|
transition: all 0.2s;
|
|
93
92
|
}
|
|
@@ -255,15 +254,21 @@ export const styles = css`
|
|
|
255
254
|
.login-link {
|
|
256
255
|
color: var(--login-btn-text-color, white);
|
|
257
256
|
font-size: var(--login-btn-text-size, var(--hot-font-size-medium));
|
|
258
|
-
border-radius: var(
|
|
257
|
+
border-radius: var(
|
|
258
|
+
--login-btn-border-radius,
|
|
259
|
+
var(--hot-border-radius-medium)
|
|
260
|
+
);
|
|
259
261
|
text-decoration: none;
|
|
260
|
-
padding: var(
|
|
262
|
+
padding: var(
|
|
263
|
+
--login-btn-padding,
|
|
264
|
+
var(--hot-spacing-x-small) var(--hot-spacing-medium)
|
|
265
|
+
);
|
|
261
266
|
margin: var(--login-btn-margin, 0);
|
|
262
267
|
display: inline-block;
|
|
263
268
|
cursor: pointer;
|
|
264
269
|
transition: all 0.2s;
|
|
265
|
-
font-weight: var(--hot-font-weight-medium);
|
|
266
|
-
font-family: var(--login-btn-font-family,
|
|
270
|
+
font-weight: var(--login-btn-font-weight, var(--font-weight, var(--hot-font-weight-medium)));
|
|
271
|
+
font-family: var(--login-btn-font-family, var(--font-family, var(--hot-font-sans)));
|
|
267
272
|
}
|
|
268
273
|
|
|
269
274
|
/* Button variants - filled */
|
|
@@ -365,7 +370,6 @@ export const styles = css`
|
|
|
365
370
|
position: absolute;
|
|
366
371
|
right: 0;
|
|
367
372
|
background: white;
|
|
368
|
-
border: 1px solid var(--hot-color-gray-100);
|
|
369
373
|
border-radius: var(--hot-border-radius-medium);
|
|
370
374
|
z-index: 1000;
|
|
371
375
|
opacity: 0;
|
|
@@ -386,7 +390,7 @@ export const styles = css`
|
|
|
386
390
|
.dropdown-content.open {
|
|
387
391
|
opacity: 1;
|
|
388
392
|
visibility: visible;
|
|
389
|
-
transform: translateY(
|
|
393
|
+
transform: translateY(-1px);
|
|
390
394
|
}
|
|
391
395
|
|
|
392
396
|
.dropdown-content button {
|
|
@@ -400,6 +404,7 @@ export const styles = css`
|
|
|
400
404
|
text-align: left;
|
|
401
405
|
transition: background-color 0.2s ease;
|
|
402
406
|
gap: var(--hot-spacing-small);
|
|
407
|
+
font-family: var(--font-family, var(--hot-font-sans, inherit));
|
|
403
408
|
font-size: var(--hot-font-size-small);
|
|
404
409
|
color: var(--hot-color-gray-900);
|
|
405
410
|
}
|
|
@@ -427,4 +432,65 @@ export const styles = css`
|
|
|
427
432
|
width: 20px;
|
|
428
433
|
height: 20px;
|
|
429
434
|
}
|
|
435
|
+
|
|
436
|
+
/* Bar display mode */
|
|
437
|
+
|
|
438
|
+
:host([display="bar"]) {
|
|
439
|
+
width: 100%;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
:host([display="bar"]) .dropdown {
|
|
443
|
+
display: block;
|
|
444
|
+
width: 100%;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
.bar-trigger {
|
|
448
|
+
display: flex;
|
|
449
|
+
align-items: center;
|
|
450
|
+
width: 100%;
|
|
451
|
+
padding: var(--hot-spacing-small) var(--hot-spacing-medium);
|
|
452
|
+
background: none;
|
|
453
|
+
border: none;
|
|
454
|
+
cursor: pointer;
|
|
455
|
+
gap: var(--hot-spacing-small);
|
|
456
|
+
font-family: var(--font-family, var(--hot-font-sans, inherit));
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
.bar-trigger:hover,
|
|
460
|
+
.bar-trigger:active,
|
|
461
|
+
.bar-trigger:focus {
|
|
462
|
+
background: none;
|
|
463
|
+
outline: none;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
.bar-info {
|
|
467
|
+
display: flex;
|
|
468
|
+
align-items: center;
|
|
469
|
+
gap: var(--hot-spacing-small);
|
|
470
|
+
flex: 1;
|
|
471
|
+
min-width: 0;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
.bar-email {
|
|
475
|
+
font-size: var(--hot-font-size-medium);
|
|
476
|
+
color: var(--hot-color-gray-900);
|
|
477
|
+
overflow: hidden;
|
|
478
|
+
text-overflow: ellipsis;
|
|
479
|
+
white-space: nowrap;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
.bar-chevron {
|
|
483
|
+
width: 16px;
|
|
484
|
+
height: 16px;
|
|
485
|
+
flex-shrink: 0;
|
|
486
|
+
color: var(--hot-color-gray-900);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/* When bar-trigger is used as a login-link, override width behavior */
|
|
490
|
+
a.bar-trigger.login-link {
|
|
491
|
+
display: flex;
|
|
492
|
+
width: 100%;
|
|
493
|
+
box-sizing: border-box;
|
|
494
|
+
text-decoration: none;
|
|
495
|
+
}
|
|
430
496
|
`;
|
package/src/hanko-auth.ts
CHANGED
|
@@ -27,6 +27,8 @@ import accountIcon from "../assets/icon-account.svg";
|
|
|
27
27
|
import logoutIcon from "../assets/icon-logout.svg";
|
|
28
28
|
import mapIcon from "../assets/icon-map.svg";
|
|
29
29
|
import checkIcon from "../assets/icon-check.svg";
|
|
30
|
+
import chevronDownIcon from "../assets/chevron-down.svg";
|
|
31
|
+
import chevronUpIcon from "../assets/chevron-up.svg";
|
|
30
32
|
|
|
31
33
|
// Track if Hanko has been registered globally
|
|
32
34
|
let hankoRegistered = false;
|
|
@@ -129,6 +131,9 @@ export class HankoAuth extends LitElement {
|
|
|
129
131
|
| "primary"
|
|
130
132
|
| "neutral"
|
|
131
133
|
| "danger" = "primary";
|
|
134
|
+
// Display mode: "default" (compact avatar button) or "bar" (full-width bar with avatar + email + chevron)
|
|
135
|
+
@property({ type: String, reflect: true }) display: "default" | "bar" =
|
|
136
|
+
"default";
|
|
132
137
|
|
|
133
138
|
// Internal state
|
|
134
139
|
@state() private user: UserState | null = null;
|
|
@@ -167,6 +172,40 @@ export class HankoAuth extends LitElement {
|
|
|
167
172
|
}
|
|
168
173
|
};
|
|
169
174
|
|
|
175
|
+
/** Dropdown menu content for bar display mode (no email, only action links) */
|
|
176
|
+
private renderBarDropdownContent() {
|
|
177
|
+
return html`
|
|
178
|
+
<div class="dropdown-content ${this.isOpen ? "open" : ""}">
|
|
179
|
+
<button data-action="profile" @click=${this.handleDropdownSelect}>
|
|
180
|
+
<img src="${accountIcon}" class="icon" alt="Account icon" />
|
|
181
|
+
${this.t("myHotAccount")}
|
|
182
|
+
</button>
|
|
183
|
+
${this.osmRequired
|
|
184
|
+
? this.osmConnected
|
|
185
|
+
? html`
|
|
186
|
+
<button class="osm-connected" disabled>
|
|
187
|
+
<img src="${checkIcon}" alt="Check icon" class="icon" />
|
|
188
|
+
${this.t("connectedToOsm")} (@${this.osmData?.osm_username})
|
|
189
|
+
</button>
|
|
190
|
+
`
|
|
191
|
+
: html`
|
|
192
|
+
<button
|
|
193
|
+
data-action="connect-osm"
|
|
194
|
+
@click=${this.handleDropdownSelect}
|
|
195
|
+
>
|
|
196
|
+
<img src="${mapIcon}" alt="Check icon" class="icon" />
|
|
197
|
+
${this.t("connectToOsm")}
|
|
198
|
+
</button>
|
|
199
|
+
`
|
|
200
|
+
: ""}
|
|
201
|
+
<button data-action="logout" @click=${this.handleDropdownSelect}>
|
|
202
|
+
<img src="${logoutIcon}" alt="Log out icon" class="icon" />
|
|
203
|
+
${this.t("logOut")}
|
|
204
|
+
</button>
|
|
205
|
+
</div>
|
|
206
|
+
`;
|
|
207
|
+
}
|
|
208
|
+
|
|
170
209
|
// Private fields
|
|
171
210
|
private _trailingSlashCache: Record<string, boolean> = {};
|
|
172
211
|
private _debugMode = false;
|
|
@@ -865,7 +904,11 @@ export class HankoAuth extends LitElement {
|
|
|
865
904
|
super.updated(changedProperties);
|
|
866
905
|
// Re-attach event listeners when user becomes null (after logout)
|
|
867
906
|
// because a new <hanko-auth> element is created
|
|
868
|
-
if (
|
|
907
|
+
if (
|
|
908
|
+
changedProperties.has("user") &&
|
|
909
|
+
this.user === null &&
|
|
910
|
+
this.showProfile
|
|
911
|
+
) {
|
|
869
912
|
this.log("🔄 User logged out, re-attaching event listeners...");
|
|
870
913
|
this._currentHankoAuthElement = null;
|
|
871
914
|
this.setupEventListeners();
|
|
@@ -1483,8 +1526,34 @@ export class HankoAuth extends LitElement {
|
|
|
1483
1526
|
</div>
|
|
1484
1527
|
</div>
|
|
1485
1528
|
`;
|
|
1529
|
+
} else if (this.display === "bar") {
|
|
1530
|
+
// Logged in, show-profile=false, display=bar: render full-width bar trigger
|
|
1531
|
+
return html`
|
|
1532
|
+
<div class="dropdown">
|
|
1533
|
+
<button
|
|
1534
|
+
@click=${this.toggleDropdown}
|
|
1535
|
+
aria-label="${this.t("openAccountMenu")}"
|
|
1536
|
+
aria-expanded=${this.isOpen}
|
|
1537
|
+
aria-haspopup="true"
|
|
1538
|
+
class="bar-trigger"
|
|
1539
|
+
>
|
|
1540
|
+
<div class="bar-info">
|
|
1541
|
+
<span class="header-avatar">${initial}</span>
|
|
1542
|
+
<span class="bar-email"
|
|
1543
|
+
>${this.user.email || this.user.id}</span
|
|
1544
|
+
>
|
|
1545
|
+
</div>
|
|
1546
|
+
<img
|
|
1547
|
+
src="${this.isOpen ? chevronUpIcon : chevronDownIcon}"
|
|
1548
|
+
class="bar-chevron"
|
|
1549
|
+
alt=""
|
|
1550
|
+
/>
|
|
1551
|
+
</button>
|
|
1552
|
+
${this.renderBarDropdownContent()}
|
|
1553
|
+
</div>
|
|
1554
|
+
`;
|
|
1486
1555
|
} else {
|
|
1487
|
-
// Logged in, show-profile=false: render dropdown
|
|
1556
|
+
// Logged in, show-profile=false, display=default: render compact dropdown
|
|
1488
1557
|
return html`
|
|
1489
1558
|
<div class="dropdown">
|
|
1490
1559
|
<button
|
|
@@ -1621,6 +1690,24 @@ export class HankoAuth extends LitElement {
|
|
|
1621
1690
|
returnTo,
|
|
1622
1691
|
)}${this.osmRequired ? "&osm_required=true" : ""}${autoConnectParam}&lang=${this.lang}`;
|
|
1623
1692
|
|
|
1693
|
+
/* if (this.display === "bar") {
|
|
1694
|
+
return html`<a
|
|
1695
|
+
class="bar-trigger login-link ${this.buttonVariant} ${this.buttonColor}"
|
|
1696
|
+
href="${loginUrl}"
|
|
1697
|
+
@click=${(e: Event) => {
|
|
1698
|
+
e.preventDefault();
|
|
1699
|
+
window.location.href = loginUrl;
|
|
1700
|
+
}}
|
|
1701
|
+
>
|
|
1702
|
+
<span class="bar-email">${this.t("logIn")}</span>
|
|
1703
|
+
<img
|
|
1704
|
+
src="${chevronDownIcon}"
|
|
1705
|
+
class="bar-chevron"
|
|
1706
|
+
alt=""
|
|
1707
|
+
/>
|
|
1708
|
+
</a>`;
|
|
1709
|
+
} */
|
|
1710
|
+
|
|
1624
1711
|
return html`<a
|
|
1625
1712
|
class="login-link ${this.buttonVariant} ${this.buttonColor}"
|
|
1626
1713
|
href="${loginUrl}"
|