Skip to main content

ui/components/list/
list_bullet_item.rs

1use crate::{ButtonLink, ListItem, prelude::*};
2use component::{Component, ComponentScope, example_group, single_example};
3use gpui::{IntoElement, ParentElement, SharedString};
4
5#[derive(IntoElement, RegisterComponent)]
6pub struct ListBulletItem {
7    label: SharedString,
8    label_color: Option<Color>,
9    children: Vec<AnyElement>,
10}
11
12impl ListBulletItem {
13    pub fn new(label: impl Into<SharedString>) -> Self {
14        Self {
15            label: label.into(),
16            label_color: None,
17            children: Vec::new(),
18        }
19    }
20
21    pub fn label_color(mut self, color: Color) -> Self {
22        self.label_color = Some(color);
23        self
24    }
25}
26
27impl ParentElement for ListBulletItem {
28    fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
29        self.children.extend(elements)
30    }
31}
32
33impl RenderOnce for ListBulletItem {
34    fn render(self, window: &mut Window, _cx: &mut App) -> impl IntoElement {
35        let line_height = window.line_height() * 0.85;
36
37        ListItem::new("list-item")
38            .selectable(false)
39            .child(
40                h_flex()
41                    .w_full()
42                    .min_w_0()
43                    .gap_1()
44                    .items_start()
45                    .child(
46                        h_flex().h(line_height).justify_center().child(
47                            Icon::new(IconName::Dash)
48                                .size(IconSize::XSmall)
49                                .color(Color::Hidden),
50                        ),
51                    )
52                    .map(|this| {
53                        if !self.children.is_empty() {
54                            this.child(h_flex().gap_0p5().flex_wrap().children(self.children))
55                        } else {
56                            this.child(
57                                div().w_full().min_w_0().child(
58                                    Label::new(self.label)
59                                        .color(self.label_color.unwrap_or(Color::Default)),
60                                ),
61                            )
62                        }
63                    }),
64            )
65            .into_any_element()
66    }
67}
68
69impl Component for ListBulletItem {
70    fn scope() -> ComponentScope {
71        ComponentScope::DataDisplay
72    }
73
74    fn description() -> Option<&'static str> {
75        Some("A list item with a dash indicator for unordered lists.")
76    }
77
78    fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
79        let basic_examples = vec![
80            single_example(
81                "Simple",
82                ListBulletItem::new("First bullet item").into_any_element(),
83            ),
84            single_example(
85                "Multiple Lines",
86                v_flex()
87                    .child(ListBulletItem::new("First item"))
88                    .child(ListBulletItem::new("Second item"))
89                    .child(ListBulletItem::new("Third item"))
90                    .into_any_element(),
91            ),
92            single_example(
93                "Long Text",
94                ListBulletItem::new(
95                    "A longer bullet item that demonstrates text wrapping behavior",
96                )
97                .into_any_element(),
98            ),
99            single_example(
100                "With Link",
101                ListBulletItem::new("")
102                    .child(Label::new("Create an account by"))
103                    .child(ButtonLink::new(
104                        "visiting the website",
105                        "https://example.com",
106                    ))
107                    .into_any_element(),
108            ),
109        ];
110
111        Some(
112            v_flex()
113                .gap_6()
114                .child(example_group(basic_examples).vertical())
115                .into_any_element(),
116        )
117    }
118}