orbital-base-components 0.1.1

Headless base primitives for Orbital — structure, semantics, and accessibility
Documentation
use std::collections::HashSet;

use super::types::TransferListItem;

pub fn move_checked(
    source: &mut Vec<TransferListItem>,
    target: &mut Vec<TransferListItem>,
    checked: &HashSet<String>,
) {
    let mut moving = Vec::new();
    source.retain(|item| {
        if checked.contains(&item.id) && !item.disabled {
            moving.push(item.clone());
            false
        } else {
            true
        }
    });
    target.extend(moving);
}

pub fn move_all(source: &mut Vec<TransferListItem>, target: &mut Vec<TransferListItem>) {
    let mut moving = Vec::new();
    source.retain(|item| {
        if item.disabled {
            true
        } else {
            moving.push(item.clone());
            false
        }
    });
    target.extend(moving);
}

pub fn selectable_ids(items: &[TransferListItem]) -> HashSet<String> {
    items
        .iter()
        .filter(|item| !item.disabled)
        .map(|item| item.id.clone())
        .collect()
}

pub fn toggle_all(items: &[TransferListItem], checked: &mut HashSet<String>, select: bool) {
    if select {
        checked.extend(selectable_ids(items));
    } else {
        checked.clear();
    }
}

pub fn selected_count(items: &[TransferListItem], checked: &HashSet<String>) -> usize {
    items
        .iter()
        .filter(|item| checked.contains(&item.id))
        .count()
}

#[cfg(test)]
mod tests {
    use super::*;

    fn item(id: &str, disabled: bool) -> TransferListItem {
        TransferListItem {
            id: id.to_string(),
            label: id.to_string(),
            disabled,
        }
    }

    #[test]
    fn move_all_leaves_disabled_rows_in_source() {
        let mut left = vec![item("open", false), item("locked", true)];
        let mut right = Vec::new();
        move_all(&mut left, &mut right);
        assert_eq!(left.len(), 1);
        assert_eq!(left[0].id, "locked");
        assert_eq!(right.len(), 1);
        assert_eq!(right[0].id, "open");
    }

    #[test]
    fn move_checked_moves_only_selected_enabled_rows() {
        let mut left = vec![item("a", false), item("b", true), item("c", false)];
        let mut right = Vec::new();
        let checked = HashSet::from(["a".to_string(), "b".to_string()]);
        move_checked(&mut left, &mut right, &checked);
        assert_eq!(left.len(), 2);
        assert_eq!(left[0].id, "b");
        assert_eq!(left[1].id, "c");
        assert_eq!(right.len(), 1);
        assert_eq!(right[0].id, "a");
    }
}