Components / controls
OneTimeCodeInput view
One sensitive editor presented as a bounded run of visual slots.
A view survives a frame. Hold it in an Entity with cx.new(..) and reach it with .update(..).
use gpui_kit::controls::auth::OneTimeCodeInput;
Reviewed in touch-inputs auth-verification.
Construct
new(ident: impl Into<Ident>, window: &mut Window, cx: &mut Context<Self>) -> Self
Options
Chain onto the value.
input_options(options: gpui::TextInputOptions) -> Self
name(name: impl Into<SharedString>) -> Self
text(text: impl Into<SharedString>) -> Self
slots(slots: usize) -> Self
invalid(invalid: bool) -> Self
required(required: bool) -> Self
read_only(read_only: bool) -> Self
Commands
Need a Context, so they need a view.
set_input_options(options: gpui::TextInputOptions, cx: &mut Context<Self>)
set_name(name: Option<SharedString>, cx: &mut Context<Self>)
set_slots(slots: usize, cx: &mut Context<Self>)
set_required(required: bool, cx: &mut Context<Self>)
set_control_size(size: ControlSize, cx: &mut Context<Self>)
set_value(value: impl Into<SharedString>, cx: &mut Context<Self>)
set_disabled(disabled: bool, cx: &mut Context<Self>)
set_read_only(read_only: bool, cx: &mut Context<Self>)
set_invalid(invalid: bool, cx: &mut Context<Self>)
Queries
Only answer; they change nothing.
value(cx: &App) -> SharedString
len(cx: &App) -> usize
is_empty(cx: &App) -> bool
is_complete(cx: &App) -> bool
slot_count() -> usize
is_disabled() -> bool
Reports
The variants of the event it emits. It never applies the change itself.
- Change
- Submit
Example · touch-inputs
fn touch_inputs(window: &mut Window, cx: &mut App) -> AnyElement {
if !cx.has_global::<TouchInputs>() {
let email = cx.new(|cx| {
TextInput::new("scene.touch.email", window, cx)
.name("Email")
.placeholder("[email protected]")
.control_size(ControlSize::Touch)
.input_options(gpui::TextInputOptions {
purpose: gpui::KeyboardPurpose::Email,
action: gpui::TextInputAction::Next,
autofill: Some(gpui::AutofillPurpose::Email),
..Default::default()
})
});
let password = cx.new(|cx| {
PasswordInput::new("scene.touch.password", window, cx)
.name("Password")
.placeholder("Password")
.control_size(ControlSize::Touch)
.input_options(gpui::TextInputOptions {
action: gpui::TextInputAction::Done,
autofill: Some(gpui::AutofillPurpose::CurrentPassword),
..Default::default()
})
});
let password_focus = password.clone();
let host_window = window.window_handle();
let next = cx.subscribe(&email, move |_, action: &gpui::TextInputAction, cx| {
if *action == gpui::TextInputAction::Next {
let focus = password_focus.read(cx).focus_handle(cx);
cx.update_window(host_window, |_, window, cx| focus.focus(window, cx))
.ok();
}
});
let code = cx.new(|cx| {
OneTimeCodeInput::new("scene.touch.code", window, cx)
.name("Code")
.slots(6)
.control_size(ControlSize::Touch)
.input_options(gpui::TextInputOptions {
purpose: gpui::KeyboardPurpose::Number,
autofill: Some(gpui::AutofillPurpose::OneTimeCode),
..Default::default()
})
});
let notes = cx.new(|cx| {
TextArea::new("scene.touch.notes", window, cx)
.placeholder("Notes · wraps at this width")
.rows(2)
.control_size(ControlSize::Touch)
});
let disabled = cx.new(|cx| {
TextInput::new("scene.touch.disabled", window, cx)
.name("Disabled fixture")
.text("Managed by the host")
.disabled(true)
.control_size(ControlSize::Touch)
});
let invalid = cx.new(|cx| {
TextInput::new("scene.touch.invalid", window, cx)
.name("Invalid email fixture")
.text("not an address")
.invalid(true)
.control_size(ControlSize::Touch)
});
cx.set_global(TouchInputs {
fields: vec![
("scene.touch.email", "Email", email.into()),
("scene.touch.password", "Password", password.into()),
(
"scene.touch.code",
"Verification code · 6 characters",
code.into(),
),
("scene.touch.notes", "Notes", notes.into()),
("scene.touch.disabled", "Managed field", disabled.into()),
("scene.touch.invalid", "Invalid email", invalid.into()),
],
_next: next,
});
}
let theme = cx.theme().clone();
stack(&theme)
.w(px(390.0))
.max_w_full()
.child(caption(
&theme,
"Touch editing fixtures · keyboard hints are platform-dependent",
))
.children(
cx.global::<TouchInputs>()
.fields
.iter()
.map(|(id, label, view)| {
FormField::new(format!("{id}.field"), *label)
.control(*id)
.child(view.clone())
}),
)
.child(caption(
&theme,
"Code paste is not SMS autofill. Error and disabled values remain visible.",
))
.into_any_element()
}