gpui_component/searchable_list/
item.rs1use gpui::{
2 AnyElement, App, ElementId, InteractiveElement as _, IntoElement, ParentElement, RenderOnce,
3 StyleRefinement, Styled, Window, prelude::FluentBuilder,
4};
5
6use crate::{
7 ActiveTheme, Disableable, Icon, IconName, Selectable, Sizable, Size, StyleSized, StyledExt,
8 h_flex,
9};
10
11#[derive(IntoElement)]
18pub struct SearchableListItemElement {
19 id: ElementId,
20 size: Size,
21 style: StyleRefinement,
22 selected: bool,
24 checked: bool,
26 disabled: bool,
27 children: Vec<AnyElement>,
28 check_icon: Option<Icon>,
30}
31
32impl SearchableListItemElement {
33 pub fn new(ix: usize) -> Self {
34 Self {
35 id: ("searchable-list-item", ix).into(),
36 size: Size::default(),
37 style: StyleRefinement::default(),
38 selected: false,
39 checked: false,
40 disabled: false,
41 children: Vec::new(),
42 check_icon: Some(Icon::new(IconName::Check)),
43 }
44 }
45
46 pub fn checked(mut self, checked: bool) -> Self {
48 self.checked = checked;
49 self
50 }
51
52 pub fn check_icon(mut self, icon: impl Into<Icon>) -> Self {
54 self.check_icon = Some(icon.into());
55 self
56 }
57}
58
59impl ParentElement for SearchableListItemElement {
60 fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
61 self.children.extend(elements);
62 }
63}
64
65impl Disableable for SearchableListItemElement {
66 fn disabled(mut self, disabled: bool) -> Self {
67 self.disabled = disabled;
68 self
69 }
70}
71
72impl Selectable for SearchableListItemElement {
73 fn selected(mut self, selected: bool) -> Self {
74 self.selected = selected;
75 self
76 }
77
78 fn is_selected(&self) -> bool {
79 self.selected
80 }
81}
82
83impl Sizable for SearchableListItemElement {
84 fn with_size(mut self, size: impl Into<Size>) -> Self {
85 self.size = size.into();
86 self
87 }
88}
89
90impl Styled for SearchableListItemElement {
91 fn style(&mut self) -> &mut StyleRefinement {
92 &mut self.style
93 }
94}
95
96impl RenderOnce for SearchableListItemElement {
97 fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {
98 h_flex()
99 .id(self.id)
100 .relative()
101 .gap_x_1()
102 .py_1()
103 .px_2()
104 .rounded(cx.theme().radius)
105 .text_base()
106 .text_color(cx.theme().foreground)
107 .items_center()
108 .justify_between()
109 .input_text_size(self.size)
110 .list_size(self.size)
111 .refine_style(&self.style)
112 .when(!self.disabled, |this| {
113 this.when(!self.selected, |this| {
114 this.hover(|this| this.bg(cx.theme().accent.opacity(0.7)))
115 })
116 })
117 .when(self.selected, |this| this.bg(cx.theme().tokens.accent))
118 .when(self.disabled, |this| {
119 this.cursor_not_allowed()
120 .text_color(cx.theme().muted_foreground)
121 })
122 .child(
123 h_flex()
124 .w_full()
125 .items_center()
126 .justify_between()
127 .gap_x_1()
128 .child(h_flex().w_full().items_center().children(self.children))
129 .when_some(self.check_icon, |this, icon| {
130 this.child(
131 icon.xsmall()
132 .text_color(cx.theme().foreground)
133 .when(!self.checked, |this| this.invisible()),
134 )
135 }),
136 )
137 }
138}