vertigo_forms/select/multi_select.rs
1use vertigo::{Computed, Css, DomNode, Value, bind, bind_rc, css, dom, render::render_list};
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 + PartialEq + 'static> {
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 render_list(
59 &options,
60 |item| item.to_string(),
61 bind!(toggle, |item| {
62 let text_item = item.to_string();
63 let on_click = bind!(toggle, item, |_| toggle(&item));
64 let css = if value.contains(item) {
65 css! {"
66 border-style: inset;
67 font-weight: bold;
68 color: green;
69 "}
70 } else {
71 Css::default()
72 };
73 dom! {
74 <button {css} {on_click}>{text_item}</button>
75 }
76 })
77 )
78 )
79 })
80 );
81
82 let list_css = css! {"
83 display: flex;
84 flex-wrap: wrap;
85 "};
86
87 dom! {
88 <div css={list_css}>
89 {list}
90 </div>
91 }
92 }
93}