use super::*;
#[component]
pub fn euv_tree_select(node: VirtualNode<EuvTreeSelectProps>) -> VirtualNode {
let EuvTreeSelectProps {
nodes,
value,
placeholder,
label: label_text,
on_select,
}: EuvTreeSelectProps = node.try_get_props().unwrap_or_default();
let open: Signal<bool> = HookContext::use_hook(|| Signal::create(false));
let selected_value: String = value.get();
let selected_label: Option<&'static str> = tree_select_find_label(&nodes, &selected_value);
let trigger_text: &'static str = selected_label.unwrap_or(placeholder);
let has_selection: bool = selected_label.is_some();
let pick: Rc<dyn Fn(&'static str)> = tree_select_pick_handler(value, on_select, open);
html! {
div {
class: c_euv_tree_select()
if !label_text.is_empty() {
div {
class: c_form_label()
label_text
}
}
button {
type: "button"
class: c_euv_tree_select_trigger()
onclick: tree_select_toggle_handler(open)
span {
class: if has_selection {
c_euv_tree_select_value()
} else {
c_euv_tree_select_placeholder()
}
trigger_text
}
span {
class: c_euv_tree_select_caret()
"▾"
}
}
div {
class: c_euv_tree_select_panel()
class: if { open } {
c_euv_tree_select_panel_open()
} else {
c_euv_tree_select_panel_closed()
}
euv_tree {
nodes: nodes
selected: value
on_select: Some(pick)
default_expanded: true
}
}
}
}
}
pub fn tree_select_find_label(nodes: &[EuvTreeNode], value: &str) -> Option<&'static str> {
for node in nodes.iter() {
if node.value == value {
return Some(node.label);
}
if let Some(found) = tree_select_find_label(&node.children, value) {
return Some(found);
}
}
None
}
pub fn tree_select_toggle_handler<E: 'static>(open: Signal<bool>) -> Option<Rc<dyn Fn(E)>> {
Some(Rc::new(move |_: E| {
let is_open: bool = open.get();
open.set(!is_open);
}))
}
fn tree_select_pick_handler(
value: Signal<String>,
on_select: Option<Rc<dyn Fn(&'static str)>>,
open: Signal<bool>,
) -> Rc<dyn Fn(&'static str)> {
Rc::new(move |node_value: &'static str| {
tree_select_pick_node(value, on_select.clone(), open, node_value);
})
}
pub fn tree_select_pick_node(
value: Signal<String>,
on_select: Option<Rc<dyn Fn(&'static str)>>,
open: Signal<bool>,
node_value: &'static str,
) {
value.set(String::from(node_value));
if let Some(callback) = &on_select {
callback(node_value);
}
open.set(false);
}