use std::ops::Not;
use vertigo::{Computed, DomNode, Value, bind, computed_tuple, dom, render::render_list};
pub struct Select<T: Clone + PartialEq + 'static> {
pub value: Value<T>,
pub options: Computed<Vec<T>>,
}
impl<T> Select<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 on_change = bind!(value, |new_value: String| {
value.set(new_value.into());
});
let empty = computed_tuple!(value, options).render_value_option(|(value, options)| {
options
.contains(&value)
.not()
.then(|| dom! { <option value="" selected="selected" /> })
});
let list = render_list(options, |item| item.to_string(), {
let value = value.clone();
move |item: &Computed<T>| {
let item = item.clone();
let text_item = item.map(|item| item.to_string());
let selected = computed_tuple!(item, value)
.map(|(item, value)| (item == value).then(|| "selected".to_string()));
dom! { <option value={&text_item} {selected}>{text_item}</option> }
}
});
dom! {
<select {on_change}>
{empty}
{list}
</select>
}
}
}