use vertigo::{
Computed, Css, DomNode, Value, bind, bind_rc, computed_tuple, css, dom, render::render_list,
transaction,
};
pub struct MultiSelect<T: Clone + PartialEq + 'static> {
pub value: Value<Vec<T>>,
pub options: Computed<Vec<T>>,
}
impl<T> MultiSelect<T>
where
T: Clone + From<String> + PartialEq + ToString + 'static,
{
pub fn into_component(self) -> Self {
self
}
pub fn mount(&self) -> DomNode {
let Self { value, options } = self;
let toggle = bind_rc!(value, |item: &T| {
value.change(|value| {
if let Some(idx) = value.iter().position(|i| i == item) {
value.remove(idx);
} else {
value.push(item.clone());
}
});
});
let list = render_list(options, |item| item.to_string(), {
let toggle = toggle.clone();
let value = value.clone();
move |item: &Computed<T>| {
let item = item.clone();
let text_item = item.map(|item| item.to_string());
let on_click = bind!(toggle, item, |_| transaction(|ctx| toggle(&item.get(ctx))));
let css = computed_tuple!(item, value).map(|(item, value)| {
if value.contains(&item) {
css! {"
border-style: inset;
font-weight: bold;
color: green;
"}
} else {
Css::default()
}
});
dom! {
<button {css} {on_click}>{text_item}</button>
}
}
});
let list_css = css! {"
display: flex;
flex-wrap: wrap;
"};
dom! {
<div css={list_css}>
{list}
</div>
}
}
}