1use crate::{prelude::*, Label};
2use gpui::{prelude::*, Div, RenderOnce, Stateful};
3
4#[derive(Default, PartialEq)]
5pub enum InputVariant {
6 #[default]
7 Ghost,
8 Filled,
9}
10
11#[derive(RenderOnce)]
12pub struct Input {
13 placeholder: SharedString,
14 value: String,
15 state: InteractionState,
16 variant: InputVariant,
17 disabled: bool,
18 is_active: bool,
19}
20
21impl Component for Input {
22 type Rendered = Stateful<Div>;
23
24 fn render(self, cx: &mut WindowContext) -> Self::Rendered {
25 let (input_bg, input_hover_bg, input_active_bg) = match self.variant {
26 InputVariant::Ghost => (
27 cx.theme().colors().ghost_element_background,
28 cx.theme().colors().ghost_element_hover,
29 cx.theme().colors().ghost_element_active,
30 ),
31 InputVariant::Filled => (
32 cx.theme().colors().element_background,
33 cx.theme().colors().element_hover,
34 cx.theme().colors().element_active,
35 ),
36 };
37
38 let placeholder_label = Label::new(self.placeholder.clone()).color(if self.disabled {
39 TextColor::Disabled
40 } else {
41 TextColor::Placeholder
42 });
43
44 let label = Label::new(self.value.clone()).color(if self.disabled {
45 TextColor::Disabled
46 } else {
47 TextColor::Default
48 });
49
50 div()
51 .id("input")
52 .h_7()
53 .w_full()
54 .px_2()
55 .border()
56 .border_color(cx.theme().styles.system.transparent)
57 .bg(input_bg)
58 .hover(|style| style.bg(input_hover_bg))
59 .active(|style| style.bg(input_active_bg))
60 .flex()
61 .items_center()
62 .child(div().flex().items_center().text_ui_sm().map(move |this| {
63 if self.value.is_empty() {
64 this.child(placeholder_label)
65 } else {
66 this.child(label)
67 }
68 }))
69 }
70}
71
72impl Input {
73 pub fn new(placeholder: impl Into<SharedString>) -> Self {
74 Self {
75 placeholder: placeholder.into(),
76 value: "".to_string(),
77 state: InteractionState::default(),
78 variant: InputVariant::default(),
79 disabled: false,
80 is_active: false,
81 }
82 }
83
84 pub fn value(mut self, value: String) -> Self {
85 self.value = value;
86 self
87 }
88
89 pub fn state(mut self, state: InteractionState) -> Self {
90 self.state = state;
91 self
92 }
93
94 pub fn variant(mut self, variant: InputVariant) -> Self {
95 self.variant = variant;
96 self
97 }
98
99 pub fn disabled(mut self, disabled: bool) -> Self {
100 self.disabled = disabled;
101 self
102 }
103
104 pub fn is_active(mut self, is_active: bool) -> Self {
105 self.is_active = is_active;
106 self
107 }
108}