content_group.rs

  1use crate::prelude::*;
  2use component::{example_group, single_example, ComponentPreview};
  3use gpui::{AnyElement, IntoElement, ParentElement, StyleRefinement, Styled};
  4use smallvec::SmallVec;
  5
  6/// Creates a new [ContentGroup].
  7pub fn content_group() -> ContentGroup {
  8    ContentGroup::new()
  9}
 10
 11/// A [ContentGroup] that vertically stacks its children.
 12///
 13/// This is a convenience function that simply combines [`ContentGroup`] and [`v_flex`](crate::v_flex).
 14pub fn v_group() -> ContentGroup {
 15    content_group().v_flex()
 16}
 17
 18/// Creates a new horizontal [ContentGroup].
 19///
 20/// This is a convenience function that simply combines [`ContentGroup`] and [`h_flex`](crate::h_flex).
 21pub fn h_group() -> ContentGroup {
 22    content_group().h_flex()
 23}
 24
 25/// A flexible container component that can hold other elements.
 26#[derive(IntoElement, IntoComponent)]
 27#[component(scope = "layout")]
 28pub struct ContentGroup {
 29    base: Div,
 30    border: bool,
 31    fill: bool,
 32    children: SmallVec<[AnyElement; 2]>,
 33}
 34
 35impl ContentGroup {
 36    /// Creates a new [`ContentGroup`].
 37    pub fn new() -> Self {
 38        Self {
 39            base: div(),
 40            border: true,
 41            fill: true,
 42            children: SmallVec::new(),
 43        }
 44    }
 45
 46    /// Removes the border from the [`ContentGroup`].
 47    pub fn borderless(mut self) -> Self {
 48        self.border = false;
 49        self
 50    }
 51
 52    /// Removes the background fill from the [`ContentGroup`].
 53    pub fn unfilled(mut self) -> Self {
 54        self.fill = false;
 55        self
 56    }
 57}
 58
 59impl ParentElement for ContentGroup {
 60    fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
 61        self.children.extend(elements)
 62    }
 63}
 64
 65impl Styled for ContentGroup {
 66    fn style(&mut self) -> &mut StyleRefinement {
 67        self.base.style()
 68    }
 69}
 70
 71impl RenderOnce for ContentGroup {
 72    fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
 73        // TODO:
 74        // Baked in padding will make scrollable views inside of content boxes awkward.
 75        //
 76        // Do we make the padding optional, or do we push to use a different component?
 77
 78        self.base
 79            .when(self.fill, |this| {
 80                this.bg(cx.theme().colors().text.opacity(0.05))
 81            })
 82            .when(self.border, |this| {
 83                this.border_1().border_color(cx.theme().colors().border)
 84            })
 85            .rounded_md()
 86            .p_2()
 87            .children(self.children)
 88    }
 89}
 90
 91impl ComponentPreview for ContentGroup {
 92    fn preview(_window: &mut Window, _cx: &App) -> AnyElement {
 93        example_group(vec![
 94            single_example(
 95                "Default",
 96                ContentGroup::new()
 97                    .flex_1()
 98                    .items_center()
 99                    .justify_center()
100                    .h_48()
101                    .child(Label::new("Default ContentBox"))
102                    .into_any_element(),
103            )
104            .grow(),
105            single_example(
106                "Without Border",
107                ContentGroup::new()
108                    .flex_1()
109                    .items_center()
110                    .justify_center()
111                    .h_48()
112                    .borderless()
113                    .child(Label::new("Borderless ContentBox"))
114                    .into_any_element(),
115            )
116            .grow(),
117            single_example(
118                "Without Fill",
119                ContentGroup::new()
120                    .flex_1()
121                    .items_center()
122                    .justify_center()
123                    .h_48()
124                    .unfilled()
125                    .child(Label::new("Unfilled ContentBox"))
126                    .into_any_element(),
127            )
128            .grow(),
129        ])
130        .into_any_element()
131    }
132}