use crate::harness;
use gpui::{prelude::*, px, AnyElement, TestAppContext};
use harness::{open_host, probe, settle, still};
use herogpui_components::{
Breadcrumbs, Button, Crumb, Pagination, RadioGroup, RadioOption, Tag, TagGroup, Toolbar,
};
const ROW: f32 = 400.;
type Build = fn(bool) -> AnyElement;
fn cases() -> Vec<(&'static str, Build)> {
vec![
("TagGroup", |full| {
TagGroup::new("tg", vec![Tag::new("a", "Alpha")])
.full_width(full)
.into_any_element()
}),
("Pagination", |full| {
Pagination::new("pg", 1, 3)
.full_width(full)
.into_any_element()
}),
("Breadcrumbs", |full| {
Breadcrumbs::new(vec![Crumb::new("Home"), Crumb::new("Docs")])
.full_width(full)
.into_any_element()
}),
("RadioGroup", |full| {
RadioGroup::new("rg", vec![RadioOption::new("One")])
.full_width(full)
.into_any_element()
}),
("Toolbar", |full| {
Toolbar::new()
.id("tb")
.full_width(full)
.child(Button::new("b").label("Bold").into_any_element())
.into_any_element()
}),
]
}
fn probe_x(cx: &mut TestAppContext, build: Build, full: bool) -> f32 {
still();
let vcx = open_host(cx, move || {
gpui::div()
.flex()
.flex_row()
.items_start()
.w(px(ROW))
.child(build(full))
.child(probe("after"))
.into_any_element()
});
settle(vcx);
let after = vcx
.debug_bounds("after")
.expect("the trailing probe must be laid out");
f32::from(after.origin.x)
}
#[gpui::test]
fn full_width_builders_reach_their_roots(cx: &mut TestAppContext) {
for (name, build) in cases() {
let hugging = probe_x(cx, build, false);
assert!(
hugging < ROW / 2.,
"{name}: without the flag the root must hug its content, the \
probe sat at x={hugging}"
);
let full = probe_x(cx, build, true);
assert!(
full > ROW - 20.,
"{name}: `full_width(true)` must expand the root across the row, \
the probe sat at x={full} (hugging: {hugging})"
);
}
}
fn combo_box_width(cx: &mut TestAppContext, min_width: Option<f32>, full: bool) -> f32 {
use herogpui_components::{ComboBox, InputState, PickerItem};
still();
let state = cx.new(|cx| InputState::new(cx));
let vcx = open_host(cx, move || {
let combo =
ComboBox::new(state.clone(), vec![PickerItem::new("a", "Alpha")]).full_width(full);
let combo = match min_width {
Some(w) => combo.min_width(px(w)),
None => combo,
};
gpui::div()
.flex()
.flex_row()
.items_start()
.child(gpui::div().when(full, |d| d.w(px(100.))).child(combo))
.child(probe("after"))
.into_any_element()
});
settle(vcx);
f32::from(
vcx.debug_bounds("after")
.expect("the trailing probe must be laid out")
.origin
.x,
)
}
#[gpui::test]
fn combo_box_min_width_replaces_the_180px_root_floor(cx: &mut TestAppContext) {
let stock = combo_box_width(cx, None, false);
assert!(
(stock - 180.).abs() < 0.5,
"stock floor is 180px, got {stock}"
);
let narrow = combo_box_width(cx, Some(120.), false);
assert!((narrow - 120.).abs() < 0.5, "a 120px floor, got {narrow}");
let wide = combo_box_width(cx, Some(260.), false);
assert!((wide - 260.).abs() < 0.5, "a 260px floor, got {wide}");
let full = combo_box_width(cx, Some(260.), true);
assert!(
(full - 100.).abs() < 0.5,
"a full-width combo box ignores the floor, got {full}"
);
}
fn vertical_tab_content_width(cx: &mut TestAppContext, floor: Option<f32>) -> f32 {
use gpui::{canvas, Bounds, Pixels};
use herogpui_components::{Orientation, TabItem, Tabs};
use std::cell::Cell;
use std::rc::Rc;
still();
let seen: Rc<Cell<Option<Bounds<Pixels>>>> = Rc::new(Cell::new(None));
let sink = seen.clone();
let vcx = open_host(cx, move || {
let sink = sink.clone();
let slot = gpui::div()
.w_full()
.h(px(4.))
.child(canvas(move |bounds, _, _| sink.set(Some(bounds)), |_, _, _, _| {}).size_full());
let tabs = Tabs::new(
"vertical-floor",
vec![TabItem::new("a", "A").trigger(slot), TabItem::new("b", "B")],
"a",
)
.orientation(Orientation::Vertical);
match floor {
Some(w) => tabs.vertical_tab_min_width(px(w)),
None => tabs,
}
.into_any_element()
});
settle(vcx);
f32::from(
seen.get()
.expect("the trigger slot must be laid out")
.size
.width,
)
}
#[gpui::test]
fn vertical_tab_min_width_replaces_the_80px_tab_floor(cx: &mut TestAppContext) {
let stock = vertical_tab_content_width(cx, None);
let wide = vertical_tab_content_width(cx, Some(200.));
assert!(
(wide - stock - 120.).abs() < 0.5,
"a 200px floor widens the tab by 120px over the 80px one \
(stock content {stock}, wide {wide})"
);
let narrow = vertical_tab_content_width(cx, Some(40.));
assert!(
narrow < stock - 30.,
"a 40px floor lets one-letter tabs narrow (stock {stock}, narrow {narrow})"
);
}