feat: add field component
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
use gpui::{
|
||||
AppContext as _, IntoElement, ParentElement as _, Render, Styled as _, TestAppContext,
|
||||
VisualTestContext, Window, div,
|
||||
};
|
||||
use gpui_native_core::button::{Button, ButtonVariant};
|
||||
use gpui_native_core::field::{Field, FieldVariant};
|
||||
use gpui_native_theme::Theme;
|
||||
|
||||
struct FieldHost {
|
||||
variant: FieldVariant,
|
||||
with_error: bool,
|
||||
}
|
||||
|
||||
impl Render for FieldHost {
|
||||
fn render(&mut self, _window: &mut Window, _cx: &mut gpui::Context<Self>) -> impl IntoElement {
|
||||
let mut field = Field::new("test-field", "Server URL")
|
||||
.description("Where patches are sent.")
|
||||
.variant(self.variant)
|
||||
.child(
|
||||
Button::new("test-field-button")
|
||||
.label("Edit")
|
||||
.variant(ButtonVariant::Ghost),
|
||||
);
|
||||
if self.with_error {
|
||||
field = field.error(Some("Required"));
|
||||
}
|
||||
|
||||
div().size_full().p_4().child(field)
|
||||
}
|
||||
}
|
||||
|
||||
fn field_window(
|
||||
variant: FieldVariant,
|
||||
with_error: bool,
|
||||
) -> (TestAppContext, gpui::AnyWindowHandle) {
|
||||
let mut cx = TestAppContext::single();
|
||||
cx.update(Theme::init);
|
||||
let window = cx.add_window(move |_, _| FieldHost {
|
||||
variant,
|
||||
with_error,
|
||||
});
|
||||
let window: gpui::AnyWindowHandle = window.into();
|
||||
cx.update_window(window, |_, window, cx| {
|
||||
window.draw(cx).clear(cx);
|
||||
})
|
||||
.unwrap();
|
||||
(cx, window)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn block_stacks_the_label_above_the_control() {
|
||||
let (cx, window) = field_window(FieldVariant::Block, false);
|
||||
let mut visual = VisualTestContext::from_window(window, &cx);
|
||||
let label = visual
|
||||
.debug_bounds("test-field-label")
|
||||
.expect("label missing");
|
||||
let control = visual
|
||||
.debug_bounds("test-field-control")
|
||||
.expect("control missing");
|
||||
|
||||
assert!(
|
||||
label.bottom() <= control.top(),
|
||||
"label must sit above the control: {label:?} vs {control:?}"
|
||||
);
|
||||
assert!(
|
||||
(label.left() - control.left()).abs() < gpui::px(1.),
|
||||
"label and control must share the left edge"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn row_leads_with_the_label_and_trails_the_control() {
|
||||
let (cx, window) = field_window(FieldVariant::Row, false);
|
||||
let mut visual = VisualTestContext::from_window(window, &cx);
|
||||
let label = visual
|
||||
.debug_bounds("test-field-label")
|
||||
.expect("label missing");
|
||||
let control = visual
|
||||
.debug_bounds("test-field-control")
|
||||
.expect("control missing");
|
||||
|
||||
assert!(
|
||||
control.left() >= label.right(),
|
||||
"the control must trail the label: {label:?} vs {control:?}"
|
||||
);
|
||||
let label_center = (label.top() + label.bottom()) / 2.;
|
||||
let control_center = (control.top() + control.bottom()) / 2.;
|
||||
assert!(
|
||||
(label_center - control_center).abs() < gpui::px(1.5),
|
||||
"the control must center on the title line: {label:?} vs {control:?}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_error_renders_under_the_control_only_when_set() {
|
||||
let (cx, window) = field_window(FieldVariant::Block, false);
|
||||
let mut visual = VisualTestContext::from_window(window, &cx);
|
||||
assert!(
|
||||
visual.debug_bounds("test-field-error").is_none(),
|
||||
"no error must render when none is set"
|
||||
);
|
||||
|
||||
let (cx, window) = field_window(FieldVariant::Block, true);
|
||||
let mut visual = VisualTestContext::from_window(window, &cx);
|
||||
let error = visual
|
||||
.debug_bounds("test-field-error")
|
||||
.expect("error missing");
|
||||
let control = visual
|
||||
.debug_bounds("test-field-control")
|
||||
.expect("control missing");
|
||||
assert!(
|
||||
error.top() >= control.bottom(),
|
||||
"the error must sit under the control: {control:?} vs {error:?}"
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user