fix(auth): show username input on first login before passkey prompt
When no known accounts exist in localStorage, show a username/email input field instead of immediately triggering the unscoped passkey picker. User types their username, then gets a scoped passkey prompt for only that account's credentials. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
724c0e16ba
commit
af446938be
|
|
@ -332,6 +332,34 @@ const styles = `
|
|||
color: var(--eid-primary);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.username-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.username-input {
|
||||
padding: 10px 14px;
|
||||
background: var(--eid-bg);
|
||||
border: 1px solid var(--eid-text-secondary);
|
||||
border-radius: var(--eid-radius);
|
||||
color: var(--eid-text);
|
||||
font-size: 0.95rem;
|
||||
font-family: inherit;
|
||||
outline: none;
|
||||
transition: border-color 0.2s;
|
||||
}
|
||||
|
||||
.username-input:focus {
|
||||
border-color: var(--eid-primary);
|
||||
}
|
||||
|
||||
.username-input::placeholder {
|
||||
color: var(--eid-text-secondary);
|
||||
opacity: 0.7;
|
||||
}
|
||||
`;
|
||||
|
||||
// ============================================================================
|
||||
|
|
@ -456,13 +484,16 @@ export class EncryptIDLoginButton extends HTMLElement {
|
|||
|
||||
const accounts = getKnownAccounts();
|
||||
|
||||
// No known accounts → generic passkey button
|
||||
// No known accounts → username input + sign-in button
|
||||
if (accounts.length === 0) {
|
||||
return `
|
||||
<button class="login-btn ${sizeClass} ${variantClass}">
|
||||
<div class="username-form">
|
||||
<input class="username-input" type="text" placeholder="Username or email" autocomplete="username webauthn" />
|
||||
<button class="login-btn ${sizeClass} ${variantClass}" data-action="username-login">
|
||||
${PASSKEY_ICON}
|
||||
<span>${this.label}</span>
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
|
|
@ -554,9 +585,23 @@ export class EncryptIDLoginButton extends HTMLElement {
|
|||
});
|
||||
});
|
||||
} else {
|
||||
// Login button with scoped username
|
||||
const loginBtn = this.shadow.querySelector('.login-btn');
|
||||
if (loginBtn) {
|
||||
// Username input form (no known accounts)
|
||||
const usernameInput = this.shadow.querySelector('.username-input') as HTMLInputElement;
|
||||
const usernameLoginBtn = this.shadow.querySelector('[data-action="username-login"]');
|
||||
if (usernameInput && usernameLoginBtn) {
|
||||
const doLogin = () => {
|
||||
const val = usernameInput.value.trim();
|
||||
this.handleLogin(val || undefined);
|
||||
};
|
||||
usernameLoginBtn.addEventListener('click', doLogin);
|
||||
usernameInput.addEventListener('keydown', (e) => {
|
||||
if ((e as KeyboardEvent).key === 'Enter') doLogin();
|
||||
});
|
||||
}
|
||||
|
||||
// Login button with scoped username (1 known account)
|
||||
const loginBtn = this.shadow.querySelector('.login-btn:not([data-action])');
|
||||
if (loginBtn && !usernameInput) {
|
||||
loginBtn.addEventListener('click', () => {
|
||||
const username = (loginBtn as HTMLElement).dataset.username;
|
||||
this.handleLogin(username);
|
||||
|
|
|
|||
Loading…
Reference in New Issue