vertigo_forms/select/
multi_select.rs1use vertigo::{
2 Computed, Css, DomNode, Value, bind, bind_rc, computed_tuple, css, dom, render::render_list,
3 transaction,
4};
5
6pub struct MultiSelect<T: Clone + PartialEq + 'static> {
31 pub value: Value<Vec<T>>,
32 pub options: Computed<Vec<T>>,
33}
34
35impl<T> MultiSelect<T>
36where
37 T: Clone + From<String> + PartialEq + ToString + 'static,
38{
39 pub fn into_component(self) -> Self {
40 self
41 }
42
43 pub fn mount(&self) -> DomNode {
44 let Self { value, options } = self;
45 let toggle = bind_rc!(value, |item: &T| {
46 value.change(|value| {
47 if let Some(idx) = value.iter().position(|i| i == item) {
48 value.remove(idx);
49 } else {
50 value.push(item.clone());
51 }
52 });
53 });
54
55 let list = render_list(options, |item| item.to_string(), {
56 let toggle = toggle.clone();
57 let value = value.clone();
58 move |item: &Computed<T>| {
59 let item = item.clone();
60 let text_item = item.map(|item| item.to_string());
61
62 let on_click = bind!(toggle, item, |_| transaction(|ctx| toggle(&item.get(ctx))));
63
64 let css = computed_tuple!(item, value).map(|(item, value)| {
65 if value.contains(&item) {
66 css! {"
67 border-style: inset;
68 font-weight: bold;
69 color: green;
70 "}
71 } else {
72 Css::default()
73 }
74 });
75
76 dom! {
77 <button {css} {on_click}>{text_item}</button>
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}