use crate::common::ValueType; use crate::components::utils::create_unique_id; use leptos::prelude::*; use std::collections::HashMap; /// # Chip Component /// /// This component defines a single chip for use in the `ChipsList` component. It functions almost /// identically to the `Checkbox` component. It should only be created from within its parent /// `CheckboxList` component. /// /// Example usage: /// ``` /// view! { /// /// } /// ``` #[component] pub fn Chip( #[prop(into)] display_text: String, #[prop(into)] value: String, #[prop(into)] name: String, #[prop(into)] on_change: Callback<(), ()>, #[prop()] checked: Signal, #[prop(optional)] disabled: RwSignal, ) -> impl IntoView { // Generate a unique id - ensure that the value doesn't contain spaces. // Without this id, checkbox/radio inputs can interfere with each other. let id = create_unique_id(&name, &value); view! { } } /// # Chips List Component /// /// This defines a list of `Chip` components. The list of values is created based on the data from the /// `data_map` prop, which is found using the given `data_member`. /// /// Any values selected from the list are stored within the `data_map` immediately as part of a callback /// passed to the `on_change` prop for each individual `Chip` component. #[component] pub fn ChipsList( #[prop(into)] data_member: String, #[prop()] data_map: RwSignal>, #[prop()] displayed_text: Vec, #[prop()] values: Vec, #[prop(default = RwSignal::new(false))] disabled: RwSignal, #[prop(optional, into)] label: String, ) -> impl IntoView { view! {
{label}
{displayed_text.into_iter().zip(values) .into_iter() .map(|(text, value)| { let checked_signal = Signal::derive({ let item_name = value.clone(); let data_member = data_member.clone(); move || { data_map.get() .get(&data_member) .unwrap_or(&ValueType::List(None)) .as_list() .unwrap_or(Some(vec!())) .unwrap_or(vec!()) .contains(&ValueType::String(Some(item_name.clone()))) } }); let on_change = { let item_name = value.clone(); let data_member = data_member.clone(); move || { let result = ValueType::String(Some(item_name.clone())); data_map.update(|map| { // Attempt to get the value type from the hash map. match map.get_mut(&data_member) { Some(value_type) => { // Attempt to get the value as a list. match value_type.as_list().unwrap_or(None) { Some(mut list) => { // Attempt to find the selected value in the selected list. // If it's present, remove it, or vice versa. match list.iter().position(|val| *val == result) { Some(index) => { list.remove(index); }, None => { list.push(result); } }; // Update the existing value_type entry in the hash map. *value_type = ValueType::List(Some(list)); }, // Insert a new value_type entry. None => { *value_type = ValueType::List(Some(vec![result])); } }; }, // Insert a new value_type entry. None => { map.insert(data_member.clone(), ValueType::List(Some(vec![result]))); } }; }); } }; view! { } }) .collect_view() }
} }