1use crate::prelude::*;
2use gpui::{AnyElement, AnyView, ClickEvent, Hsla, IntoElement, ParentElement, Styled};
3
4#[derive(IntoElement, RegisterComponent)]
14pub struct Chip {
15 label: SharedString,
16 label_color: Color,
17 label_size: LabelSize,
18 icon: Option<IconName>,
19 icon_color: Color,
20 bg_color: Option<Hsla>,
21 border_color: Option<Hsla>,
22 height: Option<Pixels>,
23 truncate: bool,
24 pill: bool,
25 on_dismiss: Option<Box<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>>,
26 tooltip: Option<Box<dyn Fn(&mut Window, &mut App) -> AnyView + 'static>>,
27}
28
29impl Chip {
30 pub fn new(label: impl Into<SharedString>) -> Self {
32 Self {
33 label: label.into(),
34 label_color: Color::Default,
35 label_size: LabelSize::XSmall,
36 icon: None,
37 icon_color: Color::Default,
38 bg_color: None,
39 border_color: None,
40 height: None,
41 truncate: false,
42 pill: false,
43 on_dismiss: None,
44 tooltip: None,
45 }
46 }
47
48 pub fn label_color(mut self, color: Color) -> Self {
50 self.label_color = color;
51 self
52 }
53
54 pub fn label_size(mut self, size: LabelSize) -> Self {
56 self.label_size = size;
57 self
58 }
59
60 pub fn icon(mut self, icon: IconName) -> Self {
62 self.icon = Some(icon);
63 self
64 }
65
66 pub fn icon_color(mut self, color: Color) -> Self {
68 self.icon_color = color;
69 self
70 }
71
72 pub fn bg_color(mut self, color: Hsla) -> Self {
74 self.bg_color = Some(color);
75 self
76 }
77
78 pub fn border_color(mut self, color: Hsla) -> Self {
80 self.border_color = Some(color);
81 self
82 }
83
84 pub fn height(mut self, height: Pixels) -> Self {
86 self.height = Some(height);
87 self
88 }
89
90 pub fn truncate(mut self) -> Self {
92 self.truncate = true;
93 self
94 }
95
96 pub fn pill(mut self, pill: bool) -> Self {
98 self.pill = pill;
99 self
100 }
101
102 pub fn dismissible(
104 mut self,
105 on_dismiss: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static,
106 ) -> Self {
107 self.on_dismiss = Some(Box::new(on_dismiss));
108 self
109 }
110
111 pub fn tooltip(mut self, tooltip: impl Fn(&mut Window, &mut App) -> AnyView + 'static) -> Self {
112 self.tooltip = Some(Box::new(tooltip));
113 self
114 }
115}
116
117impl RenderOnce for Chip {
118 fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {
119 let bg_color = self.bg_color.unwrap_or_else(|| semantic::surface(cx));
120 let border_color = self.border_color.unwrap_or_else(|| semantic::border(cx));
121 let pill = self.pill;
122
123 h_flex()
124 .when_some(self.height, |this, h| this.h(h))
125 .when(self.truncate, |this| this.min_w_0())
126 .when(!self.truncate, |this| this.flex_none())
127 .gap_1()
128 .px_2()
129 .py_0p5()
130 .border_1()
131 .when(pill, |this| this.rounded_full())
132 .when(!pill, |this| this.rounded_md())
133 .border_color(border_color)
134 .bg(bg_color)
135 .overflow_hidden()
136 .when_some(self.icon, |this, icon| {
137 this.child(
138 Icon::new(icon)
139 .size(IconSize::XSmall)
140 .color(self.icon_color),
141 )
142 })
143 .child(
144 Label::new(self.label.clone())
145 .size(self.label_size)
146 .color(self.label_color)
147 .buffer_font(cx)
148 .truncate(),
149 )
150 .id(self.label.clone())
151 .when_some(self.on_dismiss, |this, on_dismiss| {
152 this.child(
153 div()
154 .id("dismiss")
155 .cursor_pointer()
156 .child(
157 Icon::new(IconName::XMark)
158 .size(IconSize::XSmall)
159 .color(Color::Muted),
160 )
161 .on_click(move |event, window, cx| {
162 cx.stop_propagation();
163 on_dismiss(event, window, cx)
164 }),
165 )
166 })
167 .when_some(self.tooltip, |this, tooltip| this.tooltip(tooltip))
168 }
169}
170
171impl Component for Chip {
172 fn scope() -> ComponentScope {
173 ComponentScope::DataDisplay
174 }
175
176 fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
177 let chip_examples = vec![
178 single_example("Default", Chip::new("Chip Example").into_any_element()),
179 single_example(
180 "Pill",
181 Chip::new("Chip Example").pill(true).into_any_element(),
182 ),
183 single_example(
184 "Customized Label Color",
185 Chip::new("Chip Example")
186 .label_color(Color::Accent)
187 .into_any_element(),
188 ),
189 single_example(
190 "Customized Label Size",
191 Chip::new("Chip Example")
192 .label_size(LabelSize::Large)
193 .label_color(Color::Accent)
194 .into_any_element(),
195 ),
196 single_example(
197 "With Icon",
198 Chip::new("Chip Example")
199 .icon(IconName::Check)
200 .into_any_element(),
201 ),
202 single_example(
203 "Dismissible",
204 Chip::new("Chip Example")
205 .dismissible(|_, _, _| {})
206 .into_any_element(),
207 ),
208 ];
209
210 Some(example_group(chip_examples).vertical().into_any_element())
211 }
212}