T06g forms structure: form with Cmd-Enter submit, sections, fields, labels, errors, field arrays, inline forms, dirty indicator

This commit is contained in:
ZacharyZhang-NY committed 2026-09-25 10:46:27 -04:00
1 parent 0ca1ff65c7
commit 05ff67ad9f
13 files changed
+850 -78

No files matched your search

+113
View File
@@ -0,0 +1,113 @@
use gpui::{
AppContext as _, Context, Entity, IntoElement, KeyUpEvent, Keystroke, ParentElement, Render,
TestAppContext, VisualTestContext, Window, div,
};
use super::setup;
use crate::forms::{FieldArray, Form, FormField, Input, InputEvent, TextInput};
struct Signup {
name: Entity<TextInput>,
sent: usize,
field_submits: usize,
}
impl Render for Signup {
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let view = cx.entity();
Form::new("signup")
.on_submit(move |_, cx| {
view.update(cx, |view, cx| {
view.sent += 1;
cx.notify();
})
})
.child(
FormField::new("signup-name", "Name")
.required()
.child(Input::new(&self.name)),
)
}
}
#[gpui::test]
fn cmd_enter_in_a_field_submits_the_form_once(cx: &mut TestAppContext) {
setup(cx);
let (view, cx) = cx.add_window_view(|window, cx| {
let name = cx.new(|cx| TextInput::new(window, cx));
cx.subscribe(&name, |view: &mut Signup, _, event, _| {
if *event == InputEvent::Submit {
view.field_submits += 1;
}
})
.detach();
Signup {
name,
sent: 0,
field_submits: 0,
}
});
cx.update(|window, _| window.focus_next());
cx.simulate_input("Ada");
cx.simulate_keystrokes("cmd-enter");
let counts = view.read_with(cx, |view, _| (view.sent, view.field_submits));
assert_eq!(counts, (1, 0));
}
struct Rows {
rows: Vec<&'static str>,
}
impl Render for Rows {
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let (grow, shrink) = (cx.entity(), cx.entity());
self.rows.iter().fold(
FieldArray::new("rows")
.on_add(move |_, cx| {
grow.update(cx, |view, cx| {
view.rows.push("new");
cx.notify();
})
})
.on_remove(move |ix, _, cx| {
shrink.update(cx, |view, cx| {
view.rows.remove(ix);
cx.notify();
})
}),
|array, row| array.row(div().child(*row)),
)
}
}
fn press(key: &str, cx: &mut VisualTestContext) {
cx.simulate_keystrokes(key);
cx.simulate_event(KeyUpEvent {
keystroke: Keystroke::parse(key).unwrap(),
});
}
#[gpui::test]
fn field_array_buttons_remove_their_own_row_and_add_one(cx: &mut TestAppContext) {
setup(cx);
let (view, cx) = cx.add_window_view(|_, _| Rows {
rows: vec!["a", "b", "c"],
});
cx.update(|window, _| {
window.focus_next();
window.focus_next();
});
press("space", cx);
assert_eq!(view.read_with(cx, |view, _| view.rows.clone()), ["a", "c"]);
cx.update(|window, _| {
window.blur();
for _ in 0..3 {
window.focus_next();
}
});
press("space", cx);
assert_eq!(
view.read_with(cx, |view, _| view.rows.clone()),
["a", "c", "new"]
);
}