Compare commits

...
Sign in to create a new pull request.

1 commit

Author SHA1 Message Date
Anthony
4ba9259890 Start work to add container queries to gpui 2025-08-18 04:03:03 -04:00
4 changed files with 112 additions and 4 deletions

View file

@ -21,6 +21,7 @@ impl Render for HolyGrailExample {
div()
.gap_1()
.id("Random")
.grid()
.bg(rgb(0x505050))
.size(px(500.0))
@ -37,7 +38,9 @@ impl Render for HolyGrailExample {
)
.child(
block(gpui::red())
.col_span(1)
.id("Table of contents")
.row_span(1)
.container_3xs(|style| style.col_span(1).row_span_auto())
.h_56()
.child("Table of contents"),
)
@ -49,8 +52,10 @@ impl Render for HolyGrailExample {
)
.child(
block(gpui::blue())
.col_span(1)
.row_span(3)
.id("Ads")
.col_span(3)
.row_span(1)
.container_3xs(|style| style.col_span(1).row_span(3))
.child("AD :(")
.text_color(gpui::white()),
)

View file

@ -648,6 +648,61 @@ pub trait InteractiveElement: Sized {
self
}
/// Apply the given style when container width is is less than or equal to 256.0 Pixels
fn container_3xs(mut self, f: impl Fn(StyleRefinement) -> StyleRefinement + 'static) -> Self {
self.container_query_with(256.0, f)
}
/// Apply the given style when container width is is less than or equal to 288.0 Pixels
fn container_2xs(mut self, f: impl Fn(StyleRefinement) -> StyleRefinement + 'static) -> Self {
self.container_query_with(288.0, f)
}
/// Apply the given style when container width is is less than or equal to 320.0 Pixels
fn container_xs(mut self, f: impl Fn(StyleRefinement) -> StyleRefinement + 'static) -> Self {
self.container_query_with(320.0, f)
}
/// Apply the given style when container width is is less than or equal to 384.0 Pixels
fn container_sm(mut self, f: impl Fn(StyleRefinement) -> StyleRefinement + 'static) -> Self {
self.container_query_with(384.0, f)
}
/// Apply the given style when container width is is less than or equal to 448.0 Pixels
fn container_md(mut self, f: impl Fn(StyleRefinement) -> StyleRefinement + 'static) -> Self {
self.container_query_with(448.0, f)
}
/// Apply the given style when container width is is less than or equal to 512.0 Pixels
fn container_lg(mut self, f: impl Fn(StyleRefinement) -> StyleRefinement + 'static) -> Self {
self.container_query_with(512.0, f)
}
/// Apply the given style when container width is is less than or equal to 576.0 Pixels
fn container_xl(mut self, f: impl Fn(StyleRefinement) -> StyleRefinement + 'static) -> Self {
self.container_query_with(576.0, f)
}
/// Apply the given style when width is less than or equal to the current value
fn container_query_with(
mut self,
width: impl Into<Pixels>,
f: impl Fn(StyleRefinement) -> StyleRefinement + 'static,
) -> Self {
let width = width.into();
self.interactivity()
.container_queries
.push(Box::new(move |layout_width, style| {
if layout_width >= width {
f(style)
} else {
style
}
}));
self
}
/// Apply the given style to this element when the mouse hovers over a group member
fn group_hover(
mut self,
@ -1464,6 +1519,7 @@ pub struct Interactivity {
pub(crate) click_listeners: Vec<ClickListener>,
pub(crate) drag_listener: Option<(Arc<dyn Any>, DragListener)>,
pub(crate) hover_listener: Option<Box<dyn Fn(&bool, &mut Window, &mut App)>>,
pub(crate) container_queries: Vec<Box<dyn Fn(Pixels, StyleRefinement) -> StyleRefinement>>,
pub(crate) tooltip_builder: Option<TooltipBuilder>,
pub(crate) window_control: Option<WindowControlArea>,
pub(crate) hitbox_behavior: HitboxBehavior,
@ -1556,7 +1612,22 @@ impl Interactivity {
}
}
let style = self.compute_style_internal(None, element_state.as_mut(), window, cx);
let mut style =
self.compute_style_internal(None, element_state.as_mut(), window, cx);
let mut style_refinement = StyleRefinement::default();
if let Some(element_state) = element_state.as_ref()
&& let Some(bounds) = element_state.cached_bounds
{
let current_width = bounds.size.width;
for query in self.container_queries.iter() {
style_refinement = query(current_width, style_refinement);
}
style.refine(&style_refinement);
}
let layout_id = f(style, window, cx);
(layout_id, element_state)
},
@ -1738,6 +1809,10 @@ impl Interactivity {
let mut element_state =
element_state.map(|element_state| element_state.unwrap_or_default());
if let Some(element_state) = element_state.as_mut() {
element_state.cached_bounds = Some(bounds);
}
let style = self.compute_style_internal(hitbox, element_state.as_mut(), window, cx);
#[cfg(any(feature = "test-support", test))]
@ -2517,6 +2592,7 @@ pub struct InteractiveElementState {
pub(crate) pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
pub(crate) scroll_offset: Option<Rc<RefCell<Point<Pixels>>>>,
pub(crate) active_tooltip: Option<Rc<RefCell<Option<ActiveTooltip>>>>,
pub(crate) cached_bounds: Option<Bounds<Pixels>>,
}
/// Whether or not the element or a group that contains it is clicked by the mouse.

View file

@ -271,6 +271,9 @@ pub struct Style {
/// The grid location of this element
pub grid_location: Option<GridLocation>,
/// The container name (used for container queries)
pub container_name: Option<SharedString>,
/// Whether to draw a red debugging outline around this element
#[cfg(debug_assertions)]
pub debug: bool,
@ -778,6 +781,7 @@ impl Default for Style {
grid_rows: None,
grid_cols: None,
grid_location: None,
container_name: None,
#[cfg(debug_assertions)]
debug: false,

View file

@ -701,6 +701,13 @@ pub trait Styled: Sized {
self
}
/// Sets the column span of this element to auto.
fn col_span_auto(mut self) -> Self {
let grid_location = self.style().grid_location_mut();
grid_location.column = GridPlacement::Auto..GridPlacement::Auto;
self
}
/// Sets the row start of this element.
fn row_start(mut self, start: i16) -> Self {
let grid_location = self.style().grid_location_mut();
@ -722,6 +729,13 @@ pub trait Styled: Sized {
self
}
/// Sets the row span to auto
fn row_span_auto(mut self) -> Self {
let grid_location = self.style().grid_location_mut();
grid_location.row = GridPlacement::Auto..GridPlacement::Auto;
self
}
/// Sets the row end of this element to "auto"
fn row_end_auto(mut self) -> Self {
let grid_location = self.style().grid_location_mut();
@ -743,6 +757,15 @@ pub trait Styled: Sized {
self
}
/// Sets the container name of this element.
fn container_name(mut self, name: SharedString) -> Self {
let container_name = &mut self.style().container_name;
if container_name.is_none() {
*container_name = Some(name);
} // todo! Add a debug assert here so there can only be one container name per element
self
}
/// Draws a debug border around this element.
#[cfg(debug_assertions)]
fn debug(mut self) -> Self {