input.rs

  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}