use dioxus::prelude::*;
use crate::core::{use_dnd, DropEffect, ZoneId};
use crate::pointer::PointerDraggable;
pub struct Selection<K: Clone + PartialEq + 'static> {
items: Signal<Vec<K>>,
}
impl<K: Clone + PartialEq + 'static> Copy for Selection<K> {}
impl<K: Clone + PartialEq + 'static> Clone for Selection<K> {
fn clone(&self) -> Self {
*self
}
}
impl<K: Clone + PartialEq + 'static> PartialEq for Selection<K> {
fn eq(&self, other: &Self) -> bool {
self.items == other.items
}
}
impl<K: Clone + PartialEq + 'static> Selection<K> {
pub fn from_signal(items: Signal<Vec<K>>) -> Self {
Self { items }
}
pub fn is_selected(&self, key: &K) -> bool {
self.items.read().contains(key)
}
pub fn select_only(&mut self, key: K) {
self.items.set(vec![key]);
}
pub fn toggle(&mut self, key: K) {
let mut items = self.items.write();
if let Some(ix) = items.iter().position(|k| *k == key) {
items.remove(ix);
} else {
items.push(key);
}
}
pub fn clear(&mut self) {
self.items.write().clear();
}
pub fn items(&self) -> Vec<K> {
self.items.read().clone()
}
pub fn len(&self) -> usize {
self.items.read().len()
}
pub fn is_empty(&self) -> bool {
self.items.read().is_empty()
}
pub fn click(&mut self, key: K, modifiers: Modifiers) {
if modifiers.contains(Modifiers::CONTROL) || modifiers.contains(Modifiers::META) {
self.toggle(key);
} else {
self.select_only(key);
}
}
}
pub fn use_selection<K: Clone + PartialEq + 'static>() -> Selection<K> {
Selection {
items: use_signal(Vec::new),
}
}
#[component]
pub fn SelectableDraggable<K: Clone + PartialEq + 'static>(
item: K,
selection: Selection<K>,
#[props(default)]
zone: Option<ZoneId>,
#[props(default)]
effect: DropEffect,
#[props(default)]
label: Option<String>,
#[props(extends = div, extends = GlobalAttributes)] attributes: Vec<Attribute>,
children: Element,
) -> Element {
let _ = use_dnd::<Vec<K>>(); let selected = selection.is_selected(&item);
let payload = if selected {
selection.items()
} else {
vec![item.clone()]
};
let click_key = item.clone();
let mut selection = selection;
rsx! {
div {
"data-selected": selected,
onclick: move |evt: MouseEvent| {
selection.click(click_key.clone(), evt.modifiers());
},
..attributes,
PointerDraggable::<Vec<K>> {
payload,
zone,
effect,
label,
{children}
}
}
}
}
#[component]
pub fn SelectionCount<K: Clone + PartialEq + 'static>(
#[props(default)]
phantom: std::marker::PhantomData<K>,
) -> Element {
let _ = phantom;
let dnd = use_dnd::<Vec<K>>();
let n = dnd.payload().map(|p| p.len()).unwrap_or(0);
rsx! {
span { "{n} item(s)" }
}
}