Account · Sign in: log in, sign up, providers, a link by email, a second factor
LoginForm takes an email and a password, keeps one signed in on a box, and signs in on Enter once the address reads and a password is typed; a failed try says why above Sign in. SignupForm ticks a new password's rules as they hold and waits for all of them and the terms. OAuthButtons offer each provider, one spinning while the rest rest. MagicLinkForm and ForgotPassword send a link to an address and, once sent, say where it went and offer it again. TwoFactorInput takes a six-digit code at once and, after one fails, clears the boxes through forms::PinInput's new attempt, keeping its focus. The Account chapter splits into sign-in, profile and access, and billing and team.
This commit is contained in:
1 parent
69befddeb3
commit
c9e3400a71
15 files changed
+1455
-10
No files matched your search
+19
-2
@@ -13,6 +13,7 @@ type OnCode = Rc<dyn Fn(&str, &mut Window, &mut App)>;
|
||||
struct Pin {
|
||||
input: Entity<TextInput>,
|
||||
length: usize,
|
||||
attempt: usize,
|
||||
on_complete: Option<OnCode>,
|
||||
_events: Subscription,
|
||||
}
|
||||
@@ -24,6 +25,7 @@ pub struct PinInput {
|
||||
length: usize,
|
||||
letters: bool,
|
||||
masked: bool,
|
||||
attempt: usize,
|
||||
on_complete: Option<OnCode>,
|
||||
}
|
||||
|
||||
@@ -35,10 +37,17 @@ impl PinInput {
|
||||
length,
|
||||
letters: false,
|
||||
masked: false,
|
||||
attempt: 0,
|
||||
on_complete: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Clears the boxes whenever `attempt` changes, so a code that failed makes way for the next.
|
||||
pub fn attempt(mut self, attempt: usize) -> Self {
|
||||
self.attempt = attempt;
|
||||
self
|
||||
}
|
||||
|
||||
/// Accepts letters as well as digits.
|
||||
pub fn letters(mut self) -> Self {
|
||||
self.letters = true;
|
||||
@@ -60,7 +69,7 @@ impl PinInput {
|
||||
|
||||
impl RenderOnce for PinInput {
|
||||
fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||
let (length, letters) = (self.length, self.letters);
|
||||
let (length, letters, attempt) = (self.length, self.letters, self.attempt);
|
||||
let state = window.use_keyed_state(self.id.clone(), cx, |window, cx: &mut Context<Pin>| {
|
||||
let input = cx.new(|cx| {
|
||||
TextInput::new(window, cx)
|
||||
@@ -79,11 +88,19 @@ impl RenderOnce for PinInput {
|
||||
Pin {
|
||||
input,
|
||||
length,
|
||||
attempt,
|
||||
on_complete: None,
|
||||
_events: events,
|
||||
}
|
||||
});
|
||||
state.update(cx, |pin, _| pin.on_complete = self.on_complete.clone());
|
||||
state.update(cx, |pin, cx| {
|
||||
pin.on_complete = self.on_complete.clone();
|
||||
if pin.attempt != attempt {
|
||||
pin.attempt = attempt;
|
||||
log::info!("pin input: cleared for attempt {attempt}");
|
||||
pin.input.update(cx, |field, cx| field.set_text("", cx));
|
||||
}
|
||||
});
|
||||
let input = state.read(cx).input.clone();
|
||||
let (code, focused, caret_on) = {
|
||||
let field = input.read(cx);
|
||||
|
||||
Reference in new issue
Block a user