Skip to main content

edc_web_components/components/
multi_state_selector.rs

1use patternfly_yew::prelude::*;
2use yew::prelude::*;
3
4#[derive(Clone, Debug, PartialEq, Properties)]
5pub struct MultiStateSelectorProps {
6  pub selectable_items: Vec<(String, bool)>,
7  pub on_selected: Callback<Vec<(String, bool)>>,
8  #[prop_or("All".to_string())]
9  pub none_selected_label: String,
10  #[prop_or("All".to_string())]
11  pub all_selected_label: String,
12}
13
14#[component]
15pub fn MultiStateSelector(props: &MultiStateSelectorProps) -> Html {
16  let onclick = use_callback(
17    (props.selectable_items.clone(), props.on_selected.clone()),
18    |index, (selectable_items, on_selected)| {
19      let mut selectable_items = selectable_items.clone();
20
21      let item: &mut (String, bool) = selectable_items.get_mut(index).unwrap();
22      item.1 = !item.1;
23
24      on_selected.emit(selectable_items.clone());
25    },
26  );
27
28  let actions = props
29    .selectable_items
30    .iter()
31    .enumerate()
32    .map(|(index, (label, selected))| {
33      html_nested!(
34        <MenuAction onclick={onclick.reform(move |_| index)} {selected}>{ &label }</MenuAction>
35      )
36    });
37
38  let all_selected = props.selectable_items.iter().all(|(_, selected)| *selected);
39  let none_selected = props
40    .selectable_items
41    .iter()
42    .all(|(_, selected)| !*selected);
43
44  let text = if all_selected || none_selected {
45    if none_selected {
46      props.none_selected_label.clone()
47    } else {
48      props.all_selected_label.clone()
49    }
50  } else {
51    props
52      .selectable_items
53      .iter()
54      .filter_map(|(label, selected)| if *selected { Some(label.clone()) } else { None })
55      .collect::<Vec<String>>()
56      .join(", ")
57  };
58
59  html!(<Dropdown {text}>{ for actions }</Dropdown>)
60}