list_item.rs

  1use crate::prelude::{DisclosureControlVisibility, InteractionState, ToggleState};
  2use crate::theme::theme;
  3use crate::tokens::token;
  4use crate::{icon, IconAsset, Label};
  5use gpui2::style::{StyleHelpers, Styleable};
  6use gpui2::{elements::div, IntoElement};
  7use gpui2::{Element, ParentElement, ViewContext};
  8
  9#[derive(Element, Clone)]
 10pub struct ListItem {
 11    label: Label,
 12    left_icon: Option<IconAsset>,
 13    indent_level: u32,
 14    state: InteractionState,
 15    disclosure_control_style: DisclosureControlVisibility,
 16    toggle: Option<ToggleState>,
 17}
 18
 19pub fn list_item(label: Label) -> ListItem {
 20    ListItem {
 21        label,
 22        indent_level: 0,
 23        left_icon: None,
 24        disclosure_control_style: DisclosureControlVisibility::default(),
 25        state: InteractionState::default(),
 26        toggle: None,
 27    }
 28}
 29
 30impl ListItem {
 31    pub fn indent_level(mut self, indent_level: u32) -> Self {
 32        self.indent_level = indent_level;
 33        self
 34    }
 35
 36    pub fn set_toggle(mut self, toggle: ToggleState) -> Self {
 37        self.toggle = Some(toggle);
 38        self
 39    }
 40
 41    pub fn left_icon(mut self, left_icon: Option<IconAsset>) -> Self {
 42        self.left_icon = left_icon;
 43        self
 44    }
 45
 46    pub fn state(mut self, state: InteractionState) -> Self {
 47        self.state = state;
 48        self
 49    }
 50
 51    pub fn disclosure_control_style(
 52        mut self,
 53        disclosure_control_style: DisclosureControlVisibility,
 54    ) -> Self {
 55        self.disclosure_control_style = disclosure_control_style;
 56        self
 57    }
 58
 59    fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
 60        let theme = theme(cx);
 61        let token = token();
 62        let mut disclosure_control = match self.toggle {
 63            Some(ToggleState::NotToggled) => Some(div().child(icon(IconAsset::ChevronRight))),
 64            Some(ToggleState::Toggled) => Some(div().child(icon(IconAsset::ChevronDown))),
 65            None => Some(div()),
 66        };
 67
 68        match self.disclosure_control_style {
 69            DisclosureControlVisibility::OnHover => {
 70                disclosure_control =
 71                    disclosure_control.map(|c| div().absolute().neg_left_5().child(c));
 72            }
 73            DisclosureControlVisibility::Always => {}
 74        }
 75
 76        div()
 77            .fill(theme.middle.base.default.background)
 78            .hover()
 79            .fill(theme.middle.base.hovered.background)
 80            .active()
 81            .fill(theme.middle.base.pressed.background)
 82            .relative()
 83            .py_1()
 84            .child(
 85                div()
 86                    .h_6()
 87                    .px_2()
 88                    // .ml(rems(0.75 * self.indent_level as f32))
 89                    .children((0..self.indent_level).map(|_| {
 90                        div()
 91                            .w(token.list_indent_depth)
 92                            .h_full()
 93                            .flex()
 94                            .justify_center()
 95                            .child(
 96                                div()
 97                                    .ml_px()
 98                                    .w_px()
 99                                    .h_full()
100                                    .fill(theme.middle.base.default.border),
101                            )
102                    }))
103                    .flex()
104                    .gap_1()
105                    .items_center()
106                    .relative()
107                    .children(disclosure_control)
108                    .children(self.left_icon.map(|i| icon(i)))
109                    .child(self.label.clone()),
110            )
111    }
112}