use super::*;
#[component]
pub fn euv_checkbox_group(node: VirtualNode<EuvCheckboxGroupProps>) -> VirtualNode {
let EuvCheckboxGroupProps {
options,
values,
label: label_text,
on_change,
}: EuvCheckboxGroupProps = node.try_get_props().unwrap_or_default();
let checked_values: Vec<String> = values.get();
let items: Vec<VirtualNode> = options
.into_iter()
.map(|option: EuvCheckboxGroupOption| {
let is_checked: bool = checked_values
.iter()
.any(|value: &String| value.as_str() == option.value);
checkbox_item(option, is_checked, values, on_change.clone())
})
.collect();
html! {
div {
class: c_euv_checkbox_group()
if !label_text.is_empty() {
div {
class: c_euv_checkbox_group_label()
label_text
}
}
items
}
}
}
fn checkbox_item(
option: EuvCheckboxGroupOption,
is_checked: bool,
values: Signal<Vec<String>>,
on_change: Option<Rc<dyn Fn(Vec<String>)>>,
) -> VirtualNode {
let disabled: bool = option.disabled;
let handler: Option<Rc<dyn Fn(Event)>> = if disabled {
None
} else {
checkbox_change(values, option.value, on_change)
};
html! {
label {
class: c_euv_checkbox_group_item()
input {
type: "checkbox"
value: option.value
checked: boolean_attr(is_checked)
disabled: boolean_attr(disabled)
class: c_euv_checkbox_group_input()
onchange: handler
}
span {
class: c_euv_checkbox_group_box()
class: if is_checked {
c_euv_checkbox_group_box_checked()
} else {
c_euv_checkbox_group_box_unchecked()
}
if is_checked {
"✓"
}
}
span {
class: c_euv_checkbox_group_text()
option.label
}
}
}
}
fn checkbox_change(
values: Signal<Vec<String>>,
option_value: &'static str,
on_change: Option<Rc<dyn Fn(Vec<String>)>>,
) -> Option<Rc<dyn Fn(Event)>> {
Some(Rc::new(move |event: Event| {
let is_checked: bool = event
.target()
.and_then(|target: EventTarget| target.dyn_into::<HtmlInputElement>().ok())
.map(|input: HtmlInputElement| input.checked())
.unwrap_or(true);
let mut next: Vec<String> = values.get();
if is_checked {
if !next
.iter()
.any(|value: &String| value.as_str() == option_value)
{
next.push(String::from(option_value));
}
} else {
next.retain(|value: &String| value.as_str() != option_value);
}
values.set(next.clone());
if let Some(callback) = &on_change {
callback(next);
}
}))
}
fn boolean_attr(flag: bool) -> &'static str {
if flag { "true" } else { "" }
}