✨ (pagetop): Añade puntos de corte a Flex/FlexItem
- `Breakpoint` gana variante `Xxxl` y métodos `name()`/`min_width()`/ `resolved()`, para consultarse contra el tema activo. - `Theme::breakpoint_entry()` sustituye a `breakpoint_min_width()`: devuelve un `BreakpointEntry` con nombre y ancho mínimo. - Nuevo `Responsive<T>`, valor en cascada mobile-first por punto de corte. - Ejemplo `examples/intro-responsive.rs` con los patrones de uso.
This commit is contained in:
parent
8577ca8a59
commit
0b8f3f3000
22 changed files with 1257 additions and 359 deletions
|
|
@ -143,3 +143,75 @@ async fn gap_none_adds_no_gap_style() {
|
|||
assert!(!html.contains("gap"));
|
||||
assert!(!assets.contains("gap"));
|
||||
}
|
||||
|
||||
#[pagetop::test]
|
||||
async fn inline_flex_uses_its_own_display_value() {
|
||||
let mut cx = Context::default();
|
||||
let mut container = Container::new()
|
||||
.with_flex(Flex::inline())
|
||||
.with_child(Lc::n("x"));
|
||||
let html = container.render(&mut cx).await.into_string();
|
||||
let assets = cx.render_assets().into_string();
|
||||
|
||||
assert!(html.contains(r#"class="_inline-flex_""#));
|
||||
assert!(assets.contains("_inline-flex_{display:inline-flex}"));
|
||||
}
|
||||
|
||||
#[pagetop::test]
|
||||
async fn inline_flex_at_a_breakpoint_adds_its_suffix() {
|
||||
let mut cx = Context::default();
|
||||
let mut container = Container::new()
|
||||
.with_flex(Flex::inline_at(Breakpoint::Lg))
|
||||
.with_child(Lc::n("x"));
|
||||
let html = container.render(&mut cx).await.into_string();
|
||||
let assets = cx.render_assets().into_string();
|
||||
|
||||
assert!(html.contains(r#"class="_inline-flex_lg_""#));
|
||||
assert!(assets.contains("@media(min-width:992px){._inline-flex_lg_{display:inline-flex}}"));
|
||||
}
|
||||
|
||||
#[pagetop::test]
|
||||
async fn flex_and_flex_item_classes_keep_their_order() {
|
||||
let mut cx = Context::default();
|
||||
let mut container = Container::new()
|
||||
.with_prop(PropsOp::add_classes("own"))
|
||||
.with_flex(Flex::new().with_direction(flex::Direction::Column))
|
||||
.with_prop(PropsOp::flex_item(
|
||||
FlexItem::new().with_grow(flex::ItemGrow::Is1),
|
||||
))
|
||||
.with_child(Lc::n("x"));
|
||||
let html = container.render(&mut cx).await.into_string();
|
||||
|
||||
// The component's own classes come first, then those of `Flex`, then those of `FlexItem`,
|
||||
// which share a single accumulator in `Props::unpack_with_flex()`.
|
||||
assert!(html.contains(r#"class="own _flex_ _flex-direction_column_ _flex-item-grow_1_""#));
|
||||
}
|
||||
|
||||
#[pagetop::test]
|
||||
async fn flex_without_display_adds_no_class_of_its_own() {
|
||||
let mut cx = Context::default();
|
||||
let mut container = Container::new()
|
||||
.with_prop(PropsOp::add_classes("own"))
|
||||
.with_flex(Flex::default())
|
||||
.with_child(Lc::n("x"));
|
||||
let html = container.render(&mut cx).await.into_string();
|
||||
|
||||
assert!(html.contains(r#"class="own""#));
|
||||
assert!(cx.render_assets().into_string().is_empty());
|
||||
}
|
||||
|
||||
#[pagetop::test]
|
||||
async fn breakpoints_add_their_suffix_and_wrap_rules_in_media_queries() {
|
||||
let mut cx = Context::default();
|
||||
let mut container = Container::new()
|
||||
.with_flex(
|
||||
Flex::at(Breakpoint::Md).with_direction_at(Breakpoint::Lg, flex::Direction::Column),
|
||||
)
|
||||
.with_child(Lc::n("x"));
|
||||
let html = container.render(&mut cx).await.into_string();
|
||||
let assets = cx.render_assets().into_string();
|
||||
|
||||
assert!(html.contains(r#"class="_flex_md_ _flex-direction_column_lg_""#));
|
||||
assert!(assets.contains("@media(min-width:768px){._flex_md_{display:flex}}"));
|
||||
assert!(assets.contains("@media(min-width:992px){._flex-direction_column_lg_"));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -143,6 +143,39 @@ async fn combines_several_facets_in_one_call() {
|
|||
assert!(assets.contains("_flex-item-offset_10pct_{margin-inline-start:10%}"));
|
||||
}
|
||||
|
||||
#[pagetop::test]
|
||||
async fn size_at_a_breakpoint_combines_token_and_suffix() {
|
||||
let mut cx = Context::default();
|
||||
let props = Props::default().with_prop(PropsOp::flex_item(
|
||||
FlexItem::new().with_size_at(Breakpoint::Md, flex::ItemSize::Percent33),
|
||||
));
|
||||
let html = html! { span (props.unpack(&mut cx)) {} }.into_string();
|
||||
let assets = cx.render_assets().into_string();
|
||||
|
||||
// Both the sanitized value (`33.3333%` -> `33_3333pct`) and the breakpoint suffix are part of
|
||||
// the same class name, and the rule is wrapped in its media query.
|
||||
assert!(html.contains(r#"class="_flex-item-basis_33_3333pct_md_""#));
|
||||
assert!(assets.contains(
|
||||
"@media(min-width:768px){._flex-item-basis_33_3333pct_md_{flex-basis:33.3333%}}"
|
||||
));
|
||||
}
|
||||
|
||||
#[pagetop::test]
|
||||
async fn base_and_breakpoint_values_generate_one_class_each() {
|
||||
let mut cx = Context::default();
|
||||
let props = Props::default().with_prop(PropsOp::flex_item(
|
||||
FlexItem::new()
|
||||
.with_grow(flex::ItemGrow::Default)
|
||||
.with_size(flex::ItemSize::Percent50)
|
||||
.with_size_at(Breakpoint::Lg, flex::ItemSize::Percent25),
|
||||
));
|
||||
let html = html! { span (props.unpack(&mut cx)) {} }.into_string();
|
||||
|
||||
// `ItemGrow::Default` resolves to an empty CSS value, so it adds no class at all.
|
||||
assert!(html.contains(r#"class="_flex-item-basis_50pct_ _flex-item-basis_25pct_lg_""#));
|
||||
assert!(!html.contains("_flex-item-grow_"));
|
||||
}
|
||||
|
||||
#[pagetop::test]
|
||||
async fn from_flex_item_for_props_op() {
|
||||
let mut cx = Context::default();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue