GPUI Box GitHub

Components / controls

TagInput view

A field that collects a set of short tokens.

A view survives a frame. Hold it in an Entity with cx.new(..) and reach it with .update(..).

use gpui_kit::controls::tag_input::TagInput;

Reviewed in form.

Construct
new(ident: impl Into<Ident>, window: &mut Window, cx: &mut Context<Self>) -> Self
bind(field: &Entity<Self>, signal: &Signal<Vec<SharedString>>, cx: &mut App) -> Vec<Subscription>
Options

Chain onto the value.

tags(tags: impl IntoIterator<Item = impl Into<SharedString>>) -> Self
placeholder(placeholder: impl Into<SharedString>) -> Self
max(max: usize) -> Self
invalid(invalid: bool) -> Self
reorderable(reorderable: bool) -> Self
collapse_at(visible: usize) -> Self
Commands

Need a Context, so they need a view.

set_invalid(invalid: bool, cx: &mut Context<Self>)
set_tags(tags: Vec<SharedString>, cx: &mut Context<Self>)
set_disabled(disabled: bool, cx: &mut Context<Self>)
set_placeholder(placeholder: Option<SharedString>, cx: &mut Context<Self>)
set_max(max: Option<usize>, cx: &mut Context<Self>)
set_reorderable(reorderable: bool, cx: &mut Context<Self>)
set_collapse_at(visible: Option<usize>, cx: &mut Context<Self>)
set_control_size(size: ControlSize, cx: &mut Context<Self>)
Queries

Only answer; they change nothing.

current() -> &[SharedString]
is_disabled() -> bool
field() -> &Entity<TextInput>
targeted() -> Option<&SharedString>
refusal() -> Option<&SharedString>
Reports

The variants of the event it emits. It never applies the change itself.

  • Added
  • Removed
  • Duplicate
  • Refused
  • Moved
  • EditRequested
Example · form
fn form(window: &mut Window, cx: &mut App) -> AnyElement {
    ensure_form(window, cx);
    let form = cx.global::<SceneForm>();
    let (name, retention, region, labels) = (
        form.name.clone(),
        form.retention.clone(),
        form.region.clone(),
        form.labels.clone(),
    );
    let theme = cx.theme().clone();

    // No fixed height and nothing pushed to the bottom: a form is a stack of
    // fields one gap apart, and the 250px of nothing that a pinned last field
    // opened up is not a rhythm anything else in the library keeps.
    stack(&theme)
        .w(px(420.0))
        .child(
            FormField::new("scene.form.name.form-field", "Workspace name")
                .control("scene.form.name")
                .required(true)
                // The description says what the field is for and the error
                // says what went wrong; neither answers for the other.
                .description("Shown wherever this workspace appears.")
                .error("A workspace with this name already exists.")
                .child(name),
        )
        .child(
            FormField::new("scene.form.retention.form-field", "Retention")
                .control("scene.form.retention")
                .required(true)
                .description("How long a finished run is kept.")
                .error("This workspace allows at most 60 days.")
                .child(retention),
        )
        .child(
            FormField::new("scene.form.visibility.form-field", "Visibility")
                .control("scene.form.visibility")
                .description("Who can open the runs in this workspace.")
                .validation(ValidationState::Validating)
                .child(
                    SegmentedControl::new("scene.form.visibility")
                        .label("Visibility")
                        .segments([
                            Segment::new("private", "Only me"),
                            Segment::new("team", "Workspace team"),
                            Segment::new("public", "Public").disabled(true),
                        ])
                        .selected("team")
                        .on_select(|_, _, _| {}),
                ),
        )
        .child(
            // The neutral strip above uses a raised knob alone. This large
            // capsule opts into identity tint; selection does not invent it.
            FormField::new("scene.form.lane.form-field", "Lane")
                .control("scene.form.lane")
                .description("Each lane keeps the colour it is known by.")
                .child(
                    SegmentedControl::new("scene.form.lane")
                        .label("Lane")
                        .control_size(ControlSize::Lg)
                        .segments([
                            Segment::new("read", "Read")
                                .tint(super::display::identity_tint(&theme, "agent.read")),
                            Segment::new("shell", "Shell")
                                .tint(super::display::identity_tint(&theme, "agent.shell")),
                            Segment::new("network", "Network")
                                .tint(super::display::identity_tint(&theme, "agent.network")),
                        ])
                        .selected("shell")
                        .on_select(|_, _, _| {}),
                ),
        )
        .child(
            FormField::new("scene.form.labels.form-field", "Labels")
                .control("scene.form.labels")
                // The keystroke lives in the hint, so the description does not
                // spend a second line repeating it.
                .description("At most five, and each one only once.")
                .hint("enter")
                .child(labels),
        )
        .child(
            FormField::new("scene.form.region.form-field", "All Agent models")
                .control("scene.form.region")
                .description("Choose a chat-capable model for direct runs.")
                .child(region),
        )
        .into_any_element()
}

Source: crates/gpui-kit/src/controls/tag_input.rs