jinya_ui/widgets/form/
textarea.rs

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