Components / controls
TextArea view
Wrapped, multi-line editable text.
A view survives a frame. Hold it in an Entity with cx.new(..) and reach it with .update(..).
use gpui_kit::controls::textarea::TextArea;
Reviewed in touch-inputs textarea editor-options.
Construct
new(ident: impl Into<Ident>, window: &mut Window, cx: &mut Context<Self>) -> Self
detached(ident: impl Into<Ident>, cx: &mut Context<Self>) -> Self
bind(area: &Entity<Self>, signal: &Signal<String>, cx: &mut App) -> Vec<Subscription>
Options
Chain onto the value.
placeholder(placeholder: impl Into<SharedString>) -> Self
input_options(options: gpui::TextInputOptions) -> Self
frame(frame: Frame) -> Self
wrap(wrap: TextAreaWrap) -> Self
text(text: impl Into<SharedString>) -> Self
invalid(invalid: bool) -> Self
required(required: bool) -> Self
read_only(read_only: bool) -> Self
rows(rows: usize) -> Self
max_rows(max_rows: usize) -> Self
autosize(min_rows: usize, max_rows: usize) -> Self
enter(enter: Enter) -> Self
max_length(max_length: usize) -> Self
Commands
Need a Context, so they need a view.
set_input_options(options: gpui::TextInputOptions, cx: &mut Context<Self>)
set_placeholder(placeholder: impl Into<SharedString>, cx: &mut Context<Self>)
set_frame(frame: Frame, cx: &mut Context<Self>)
set_wrap(wrap: TextAreaWrap, cx: &mut Context<Self>)
set_required(required: bool, cx: &mut Context<Self>)
set_rows(rows: usize, cx: &mut Context<Self>)
set_max_rows(max_rows: Option<usize>, cx: &mut Context<Self>)
set_autosize(rows: Option<(usize, usize)>, cx: &mut Context<Self>)
set_enter(enter: Enter, cx: &mut Context<Self>)
set_max_length(max_length: Option<usize>, cx: &mut Context<Self>)
set_control_size(size: ControlSize, cx: &mut Context<Self>)
set_arrows_claimed(claimed: bool)
set_completion_claimed(claimed: bool)
set_value(value: impl Into<SharedString>, cx: &mut Context<Self>)
insert(text: &str, cx: &mut Context<Self>)
replace_range(range: Range<usize>, text: &str, cx: &mut Context<Self>) -> Option<Range<usize>>
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>)
set_selected_range(range: Range<usize>, cx: &mut Context<Self>)
replace_ranges(edits: impl IntoIterator<Item = (Range<usize>, SharedString)>, cx: &mut Context<Self>) -> bool
set_selections(selections: impl IntoIterator<Item = (Range<usize>, bool)>, cx: &mut Context<Self>) -> bool
select_rectangle(anchor: Point<Pixels>, focus: Point<Pixels>, cx: &mut Context<Self>) -> bool
Queries
Only answer; they change nothing.
arrows_claimed() -> bool
completion_claimed() -> bool
value() -> &SharedString
document() -> gpui::EditSnapshot
snapshot() -> TextAreaSnapshot
revision() -> u64
wrap_mode() -> TextAreaWrap
is_empty() -> bool
is_disabled() -> bool
is_read_only() -> bool
selected_range() -> Range<usize>
cursor_offset() -> usize
selections() -> Vec<(Range<usize>, bool)>
bounds_for_range(range: Range<usize>) -> Option<Vec<Bounds<Pixels>>>
caret_bounds() -> Option<Bounds<Pixels>>
bounds_for_position(offset: usize) -> Option<Bounds<Pixels>>
cursor_row() -> usize
shaping_work() -> Option<gpui::EditableTextWork>
accessibility_work() -> gpui::AccessibleTextWork
row_index_work() -> usize
wrapped_index_work() -> usize
measured() -> Option<Measured>
horizontal_scroll_offset() -> Pixels
Reports
The variants of the event it emits. It never applies the change itself.
- Edited
- Change
- Submit
- Cancel
- Pasted
- MoveUp
- MoveDown
- AcceptCompletion
- DismissCompletion
- IndentRequested
- OutdentRequested
- SelectionChanged
- GeometryChanged
- Focus
- Blur
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()
}