vertigo_forms/select/multi_select.rs
1use vertigo::{Computed, Css, DomNode, Value, bind, bind_rc, css, dom};
2
3/// Select component based on vector of `T` values,
4/// which allows to have multiple options selected at once.
5///
6/// Example:
7/// ```
8/// use vertigo::{DomNode, dom, Value};
9/// use vertigo_forms::MultiSelect;
10///
11/// let value = Value::new(vec!["foo".to_string()]);
12/// let options = Value::new(
13/// vec![
14/// "foo".to_string(),
15/// "bar".to_string(),
16/// "baz".to_string(),
17/// ]
18/// );
19///
20/// dom! {
21/// <MultiSelect
22/// value={value.clone()}
23/// options={options}
24/// />
25/// };
26/// ```
27pub struct MultiSelect<T: Clone> {
28 pub value: Value<Vec<T>>,
29 pub options: Computed<Vec<T>>,
30}
31
32impl<T> MultiSelect<T>
33where
34 T: Clone + From<String> + PartialEq + ToString + 'static,
35{
36 pub fn into_component(self) -> Self {
37 self
38 }
39
40 pub fn mount(&self) -> DomNode {
41 let Self { value, options } = self;
42 let toggle = bind_rc!(value, |item: &T| {
43 value.change(|value| {
44 if let Some(idx) = value.iter().position(|i| i == item) {
45 value.remove(idx);
46 } else {
47 value.push(item.clone());
48 }
49 });
50 });
51
52 let list = bind!(
53 options,
54 toggle,
55 value.render_value(move |value| {
56 bind!(
57 toggle,
58 options.render_list(
59 |item| item.to_string(),
60 bind!(toggle, |item| {
61 let text_item = item.to_string();
62 let on_click = bind!(toggle, item, |_| toggle(&item));
63 let css = if value.contains(item) {
64 css! {"
65 border-style: inset;
66 font-weight: bold;
67 color: green;
68 "}
69 } else {
70 Css::default()
71 };
72 dom! {
73 <button {css} {on_click}>{text_item}</button>
74 }
75 })
76 )
77 )
78 })
79 );
80
81 let list_css = css! {"
82 display: flex;
83 flex-wrap: wrap;
84 "};
85
86 dom! {
87 <div css={list_css}>
88 {list}
89 </div>
90 }
91 }
92}