jinya_ui/widgets/form/
input.rs

1use yew::prelude::*;
2use yew::{Callback, Component, ComponentLink, Html};
3
4pub fn get_css<'a>() -> &'a str {
5    // language=CSS
6    "
7.jinya-input__color-container {
8    width: 100%;
9}
10
11.jinya-input__color-container--default {
12    --state-color: var(--primary-color);
13}
14
15.jinya-input__color-container--negative {
16    --state-color: var(--negative-color);
17}
18
19.jinya-input__color-container--positive {
20    --state-color: var(--positive-color);
21}
22
23.jinya-input__color-container--disabled {
24    --state-color: var(--disabled-border-color);
25}
26
27.jinya-input__container {
28    display: inline-block;
29    border: 2px solid var(--state-color);
30    border-radius: 5px;
31    padding: 0.5rem 0.75rem 0.25rem;
32    position: relative;
33    margin-top: 0.75rem;
34    width: 100%;
35    box-sizing: border-box;
36}
37
38.jinya-input__input {
39    font-size: var(--font-size-16);
40    color: var(--state-color);
41    background: var(--white);
42    border: none;
43    padding: 0;
44    width: 100%;
45    outline: none;
46    font-family: var(--font-family);
47}
48
49.jinya-input__input:disabled {
50    cursor: not-allowed;
51}
52
53.jinya-input__input:invalid {
54    outline: none;
55    box-shadow: none;
56    border: none;
57}
58
59.jinya-input__label {
60    display: block;
61    font-size: var(--font-size-12);
62    color: var(--state-color);
63    position: absolute;
64    top: -0.75rem;
65    background: var(--white);
66    padding-left: 0.25rem;
67    padding-right: 0.25rem;
68    box-sizing: border-box;
69    left: 0.5rem;
70    z-index: 0;
71}
72
73.jinya-input__validation-message {
74    display: block;
75    font-size: var(--font-size-12);
76    color: var(--state-color);
77}
78"
79}
80
81#[derive(Clone, PartialEq)]
82pub enum InputState {
83    Default,
84    Negative,
85    Positive,
86}
87
88pub struct Input {
89    link: ComponentLink<Self>,
90    label: String,
91    on_input: Callback<String>,
92    state: InputState,
93    value: String,
94    input_type: String,
95    validation_message: String,
96    placeholder: String,
97    disabled: bool,
98}
99
100#[derive(Clone, PartialEq, Properties)]
101pub struct InputProps {
102    pub label: String,
103    pub on_input: Callback<String>,
104    #[prop_or(InputState::Default)]
105    pub state: InputState,
106    pub value: String,
107    #[prop_or("text".to_string())]
108    pub input_type: String,
109    #[prop_or("".to_string())]
110    pub validation_message: String,
111    #[prop_or("".to_string())]
112    pub placeholder: String,
113    #[prop_or(false)]
114    pub disabled: bool,
115}
116
117pub enum Msg {
118    Input(String),
119}
120
121impl Default for InputState {
122    fn default() -> Self {
123        InputState::Default
124    }
125}
126
127impl Input {
128    fn get_input_container_class(&self) -> String {
129        let class = match self.state {
130            InputState::Default => {
131                "jinya-input__color-container jinya-input__color-container--default"
132            }
133            InputState::Negative => {
134                "jinya-input__color-container jinya-input__color-container--negative"
135            }
136            InputState::Positive => {
137                "jinya-input__color-container jinya-input__color-container--positive"
138            }
139        }
140        .to_string();
141
142        if self.disabled {
143            "jinya-input__color-container jinya-input__color-container--disabled".to_string()
144        } else {
145            class
146        }
147    }
148}
149
150impl Component for Input {
151    type Message = Msg;
152    type Properties = InputProps;
153
154    fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
155        Input {
156            link,
157            label: props.label,
158            on_input: props.on_input,
159            state: props.state,
160            value: props.value,
161            input_type: props.input_type,
162            validation_message: props.validation_message,
163            placeholder: props.placeholder,
164            disabled: props.disabled,
165        }
166    }
167
168    fn update(&mut self, msg: Self::Message) -> bool {
169        match msg {
170            Msg::Input(value) => {
171                self.on_input.emit(value);
172            }
173        }
174
175        false
176    }
177
178    fn change(&mut self, _props: Self::Properties) -> bool {
179        self.label = _props.label;
180        self.on_input = _props.on_input;
181        self.state = _props.state;
182        self.value = _props.value;
183        self.validation_message = _props.validation_message;
184        self.input_type = _props.input_type;
185        self.placeholder = _props.placeholder;
186        self.disabled = _props.disabled;
187
188        true
189    }
190
191    fn view(&self) -> Html {
192        let id = super::super::super::id_generator::generate_id();
193        html! {
194            <div class=self.get_input_container_class()>
195                <div class="jinya-input__container">
196                    <label for=id class="jinya-input__label">{&self.label}</label>
197                    <input
198                        id=id
199                        type=self.input_type
200                        disabled=self.disabled
201                        placeholder=self.placeholder
202                        oninput=self.link.callback(|e: InputData| Msg::Input(e.value))
203                        value=self.value class="jinya-input__input"
204                    />
205                </div>
206                <span class="jinya-input__validation-message">{&self.validation_message}</span>
207            </div>
208        }
209    }
210}