T06g forms structure: form with Cmd-Enter submit, sections, fields, labels, errors, field arrays, inline forms, dirty indicator
This commit is contained in:
13 files changed
+850
-78
No files matched your search
@@ -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"]
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user