use std::fmt::Display;
use std::str::FromStr;
use wasm_bindgen::JsCast;
use yew::prelude::*;
use super::radio_list_item::*;
use crate::components::style::LocalStyle;
#[cfg(test)]
use crate::utils::WeakScope;
use crate::*;
#[derive(Properties, Default)]
pub struct RadioListProps<T>
where
T: Clone + Display + FromStr + PartialEq + 'static,
{
pub children: ChildrenWithProps<RadioListItem<T>>,
pub disabled: bool,
pub on_change: Callback<T>,
pub selected: T,
#[prop_or_default]
pub class: Option<&'static str>,
#[prop_or_default]
pub name: Option<&'static str>,
#[cfg(test)]
#[prop_or_default]
pub weak_link: WeakScope<RadioList<T>>,
}
impl<T> PartialEq for RadioListProps<T>
where
T: Clone + Display + FromStr + PartialEq + 'static,
{
fn eq(&self, other: &Self) -> bool {
self.children == other.children
&& self.disabled == other.disabled
&& self.selected == other.selected
&& self.class == other.class
}
}
pub enum RadioListMsg {
Change(String),
}
pub struct RadioList<T>
where
T: Clone + Display + FromStr + PartialEq + 'static,
{
selected: T,
}
impl<T> Component for RadioList<T>
where
T: Clone + Display + FromStr + PartialEq + 'static,
{
type Message = RadioListMsg;
type Properties = RadioListProps<T>;
fn create(ctx: &Context<Self>) -> Self {
enable_weak_link_test!(ctx.props(), ctx.link());
Self {
selected: ctx.props().selected.clone(),
}
}
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
match msg {
RadioListMsg::Change(value) => {
if let Ok(x) = T::from_str(&value) {
self.selected = x.clone();
ctx.props().on_change.emit(x);
}
}
};
false
}
fn changed(&mut self, ctx: &Context<Self>, _old: &Self::Properties) -> bool {
self.selected = ctx.props().selected.clone();
true
}
fn view(&self, ctx: &Context<Self>) -> Html {
let on_change = ctx.link().callback(move |event: InputEvent| {
RadioListMsg::Change(
event
.target()
.unwrap()
.unchecked_into::<web_sys::HtmlInputElement>()
.value(),
)
});
let class = match ctx.props().class {
Some(x) => format!("radio-list-item {}", x),
None => "radio-list-item".to_owned(),
};
html_template! {
<LocalStyle href={ css!("containers/radio-list") } />
{
ctx.props()
.children
.iter()
.enumerate()
.map(|(idx, child)| {
self.render_item(ctx, idx, child, &class, on_change.clone(), &self.selected)
})
.collect::<Html>()
}
}
}
}
impl<T> RadioList<T>
where
T: Clone + Display + FromStr + PartialEq + 'static,
{
fn render_item(
&self,
ctx: &Context<Self>,
idx: usize,
child: yew::virtual_dom::VChild<RadioListItem<T>>,
class: &str,
on_change: Callback<InputEvent>,
selected: &T,
) -> Html {
let val = child.props.value.clone();
html! {
<div class={ class.to_string() }>
<input
id={ format!("radio-list-{}", idx) }
name={ ctx.props().name.unwrap_or("radio-list") }
type="radio"
value={ format!("{}", val) }
class="parameter"
oninput={ on_change }
disabled={ ctx.props().disabled }
checked={ selected == &val } />
{ child }
</div>
}
}
}