1use gpui::prelude::*;
4use gpui::{div, px, App, ClickEvent, ElementId, FontWeight, IntoElement, SharedString, Window};
5
6use crate::input::ClickHandler;
7use crate::style::ColorValue;
8use crate::theme::{theme, Size};
9
10#[derive(IntoElement)]
13pub struct Chip {
14 id: ElementId,
15 label: SharedString,
16 checked: bool,
17 color: ColorValue,
18 size: Size,
19 on_change: Option<ClickHandler>,
20}
21
22impl Chip {
23 pub fn new(id: impl Into<ElementId>, label: impl Into<SharedString>) -> Self {
24 Chip {
25 id: id.into(),
26 label: label.into(),
27 checked: false,
28 color: ColorValue::default(),
29 size: Size::Md,
30 on_change: None,
31 }
32 }
33
34 pub fn checked(mut self, checked: bool) -> Self {
35 self.checked = checked;
36 self
37 }
38
39 pub fn color(mut self, color: impl Into<ColorValue>) -> Self {
40 self.color = color.into();
41 self
42 }
43
44 pub fn size(mut self, size: Size) -> Self {
45 self.size = size;
46 self
47 }
48
49 pub fn on_change(
50 mut self,
51 handler: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static,
52 ) -> Self {
53 self.on_change = Some(Box::new(handler));
54 self
55 }
56
57 fn metrics(&self) -> (f32, f32, f32) {
58 match self.size {
59 Size::Xs => (24.0, 10.0, 11.0),
60 Size::Sm => (28.0, 12.0, 12.0),
61 Size::Md => (32.0, 16.0, 14.0),
62 Size::Lg => (38.0, 20.0, 16.0),
63 Size::Xl => (44.0, 24.0, 18.0),
64 }
65 }
66}
67
68impl RenderOnce for Chip {
69 fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
70 let t = theme(cx);
71 let (height, pad_x, font) = self.metrics();
72 let accent = self.color.accent(t);
73
74 let (bg, fg, border) = if self.checked {
75 (self.color.soft(t), accent, accent)
76 } else {
77 (t.surface().hsla(), t.text().hsla(), t.border().hsla())
78 };
79 let hover_bg = t.surface_hover().hsla();
80
81 let mut el = div()
82 .id(self.id)
83 .flex()
84 .items_center()
85 .gap(px(6.0))
86 .h(px(height))
87 .px(px(pad_x))
88 .rounded(px(height))
89 .border_1()
90 .border_color(border)
91 .bg(bg)
92 .text_color(fg)
93 .text_size(px(font))
94 .font_weight(FontWeight::MEDIUM);
95 if self.checked {
96 el = el.child(SharedString::new_static("\u{2713}"));
97 } else {
98 el = el.hover(move |s| s.bg(hover_bg));
99 }
100 el = el.child(self.label);
101 if let Some(handler) = self.on_change {
102 el = el.on_click(handler);
103 }
104 el
105 }
106}