jinya_ui/widgets/form/
dropdown.rs1use yew::prelude::*;
2use yew::{Callback, Component, ComponentLink, Html};
3
4pub fn get_css<'a>() -> &'a str {
5 "
7.jinya-dropdown__color-container {
8 width: 100%;
9}
10
11.jinya-dropdown__color-container--default {
12 --state-color: var(--primary-color);
13 --select-arrow: var(--background-image-select-primary);
14}
15
16.jinya-dropdown__color-container--negative {
17 --state-color: var(--negative-color);
18 --select-arrow: var(--background-image-select-negative);
19}
20
21.jinya-dropdown__color-container--positive {
22 --state-color: var(--positive-color);
23 --select-arrow: var(--background-image-select-positive);
24}
25
26.jinya-dropdown__color-container--disabled {
27 --state-color: var(--disabled-border-color);
28 --select-arrow: var(--background-image-select-disabled);
29}
30
31.jinya-dropdown__container {
32 display: inline-block;
33 border: 2px solid var(--state-color);
34 border-radius: 5px;
35 padding: 0.5rem 0.75rem 0.25rem;
36 position: relative;
37 margin-top: 0.75rem;
38 width: 100%;
39 box-sizing: border-box;
40}
41
42.jinya-dropdown__select:disabled {
43 cursor: not-allowed;
44}
45
46.jinya-dropdown__select {
47 font-size: var(--font-size-16);
48 color: var(--state-color);
49 background: var(--white);
50 font-family: var(--font-family);
51 border: none;
52 padding: 0;
53 width: 100%;
54 /* for Firefox */
55 -moz-appearance: none;
56 /* for Chrome */
57 -webkit-appearance: none;
58 background-image: var(--select-arrow);
59 background-repeat: no-repeat;
60 background-position-x: right;
61 background-position-y: center;
62 outline: none;
63}
64
65.jinya-dropdown__select:invalid {
66 outline: none;
67 box-shadow: none;
68 border: none;
69}
70
71.jinya-dropdown__label {
72 display: block;
73 font-size: var(--font-size-12);
74 color: var(--state-color);
75 position: absolute;
76 top: -0.75rem;
77 background: var(--white);
78 padding-left: 0.25rem;
79 padding-right: 0.25rem;
80 box-sizing: border-box;
81 left: 0.5rem;
82 z-index: 0;
83}
84
85.jinya-dropdown__validation-message {
86 display: block;
87 font-size: var(--font-size-12);
88 color: var(--state-color);
89}
90"
91}
92
93#[derive(Clone, PartialEq)]
94pub enum DropdownState {
95 Default,
96 Negative,
97 Positive,
98}
99
100#[derive(Clone, PartialEq, Properties)]
101pub struct DropdownItem {
102 pub value: String,
103 pub text: String,
104}
105
106pub struct Dropdown {
107 link: ComponentLink<Self>,
108 label: String,
109 on_select: Callback<String>,
110 state: DropdownState,
111 dropdown_type: String,
112 validation_message: String,
113 items: Vec<DropdownItem>,
114 placeholder: Option<String>,
115 disabled: bool,
116 value: String,
117}
118
119#[derive(Clone, PartialEq, Properties)]
120pub struct DropdownProps {
121 pub label: String,
122 pub on_select: Callback<String>,
123 #[prop_or(DropdownState::Default)]
124 pub state: DropdownState,
125 #[prop_or("text".to_string())]
126 pub dropdown_type: String,
127 #[prop_or("".to_string())]
128 pub validation_message: String,
129 pub items: Vec<DropdownItem>,
130 #[prop_or(None)]
131 pub placeholder: Option<String>,
132 #[prop_or(false)]
133 pub disabled: bool,
134 pub value: String,
135}
136
137pub enum Msg {
138 Change(ChangeData),
139}
140
141impl Default for DropdownState {
142 fn default() -> Self {
143 DropdownState::Default
144 }
145}
146
147impl Dropdown {
148 fn get_dropdown_container_class(&self) -> String {
149 let class = match self.state {
150 DropdownState::Default => {
151 "jinya-dropdown__color-container jinya-dropdown__color-container--default"
152 }
153 DropdownState::Negative => {
154 "jinya-dropdown__color-container jinya-dropdown__color-container--negative"
155 }
156 DropdownState::Positive => {
157 "jinya-dropdown__color-container jinya-dropdown__color-container--positive"
158 }
159 }
160 .to_string();
161
162 if self.disabled {
163 "jinya-dropdown__color-container jinya-dropdown__color-container--disabled".to_string()
164 } else {
165 class
166 }
167 }
168}
169
170impl Component for Dropdown {
171 type Message = Msg;
172 type Properties = DropdownProps;
173
174 fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
175 Dropdown {
176 link,
177 label: props.label,
178 on_select: props.on_select,
179 state: props.state,
180 placeholder: props.placeholder,
181 dropdown_type: props.dropdown_type,
182 validation_message: props.validation_message,
183 items: props.items,
184 disabled: props.disabled,
185 value: props.value,
186 }
187 }
188
189 fn update(&mut self, msg: Self::Message) -> bool {
190 match msg {
191 Msg::Change(data) => {
192 let value = match data {
193 ChangeData::Select(element) => element.value(),
194 _ => unreachable!(),
195 };
196 self.on_select.emit(value);
197 }
198 }
199
200 false
201 }
202
203 fn change(&mut self, _props: Self::Properties) -> bool {
204 self.label = _props.label;
205 self.on_select = _props.on_select;
206 self.state = _props.state;
207 self.placeholder = _props.placeholder;
208 self.validation_message = _props.validation_message;
209 self.dropdown_type = _props.dropdown_type;
210 self.items = _props.items;
211 self.disabled = _props.disabled;
212 self.value = _props.value;
213
214 true
215 }
216
217 fn view(&self) -> Html {
218 let id = super::super::super::id_generator::generate_id();
219 html! {
220 <div class=self.get_dropdown_container_class()>
221 <div class="jinya-dropdown__container">
222 <label for=id class="jinya-dropdown__label">{&self.label}</label>
223 <select class="jinya-dropdown__select" disabled=self.disabled onchange=self.link.callback(|data: ChangeData| Msg::Change(data))>
224 {if self.placeholder.is_some() {
225 html! {
226 <option value="">{self.placeholder.as_ref().unwrap()}</option>
227 }
228 } else {
229 html! {}
230 }}
231 {for self.items.iter().map(|mut item| {
232 html! {
233 <option value=&item.value selected={self.value == item.value}>{&item.text}</option>
234 }
235 })}
236 </select>
237 </div>
238 <span class="jinya-dropdown__validation-message">{&self.validation_message}</span>
239 </div>
240 }
241 }
242}