Skip to main content

fret_ui_headless/table/
column_visibility.rs

1use std::collections::HashMap;
2
3use super::{ColumnDef, ColumnId};
4
5/// TanStack-compatible column visibility map: `column_id -> visible`.
6///
7/// Columns default to visible when absent from the map.
8pub type ColumnVisibilityState = HashMap<ColumnId, bool>;
9
10pub fn is_column_visible(visibility: &ColumnVisibilityState, column: &ColumnId) -> bool {
11    visibility.get(column).copied().unwrap_or(true)
12}
13
14pub fn set_column_visible(
15    visibility: &mut ColumnVisibilityState,
16    column: &ColumnId,
17    visible: bool,
18) {
19    if visible {
20        visibility.remove(column);
21    } else {
22        visibility.insert(column.clone(), false);
23    }
24}
25
26pub fn toggle_column_visible(
27    visibility: &mut ColumnVisibilityState,
28    column: &ColumnId,
29    visible: Option<bool>,
30) {
31    let visible = visible.unwrap_or_else(|| !is_column_visible(visibility, column));
32    set_column_visible(visibility, column, visible);
33}
34
35pub fn toggled_column_visible(
36    visibility: &ColumnVisibilityState,
37    column: &ColumnId,
38    visible: Option<bool>,
39) -> ColumnVisibilityState {
40    let mut next = visibility.clone();
41    toggle_column_visible(&mut next, column, visible);
42    next
43}
44
45pub fn visible_columns<'c, TData>(
46    columns: &'c [&'c ColumnDef<TData>],
47    visibility: &ColumnVisibilityState,
48) -> Vec<&'c ColumnDef<TData>> {
49    columns
50        .iter()
51        .copied()
52        .filter(|c| is_column_visible(visibility, &c.id))
53        .collect()
54}
55
56#[cfg(test)]
57mod tests {
58    use super::*;
59
60    #[test]
61    fn is_column_visible_defaults_to_true() {
62        let visibility = ColumnVisibilityState::default();
63        assert!(is_column_visible(&visibility, &ColumnId::from("a")));
64    }
65
66    #[test]
67    fn visible_columns_filters_by_state() {
68        #[derive(Debug)]
69        struct Item;
70
71        let a = ColumnDef::<Item>::new("a");
72        let b = ColumnDef::<Item>::new("b");
73        let c = ColumnDef::<Item>::new("c");
74
75        let columns = vec![&a, &b, &c];
76        let mut visibility = ColumnVisibilityState::default();
77        visibility.insert(ColumnId::from("b"), false);
78
79        let out = visible_columns(columns.as_slice(), &visibility);
80        let ids = out.iter().map(|c| c.id.as_ref()).collect::<Vec<_>>();
81
82        assert_eq!(ids, vec!["a", "c"]);
83    }
84
85    #[test]
86    fn set_column_visible_removes_true_and_sets_false() {
87        let mut visibility = ColumnVisibilityState::default();
88        let a = ColumnId::from("a");
89
90        set_column_visible(&mut visibility, &a, false);
91        assert_eq!(visibility.get(&a).copied(), Some(false));
92
93        set_column_visible(&mut visibility, &a, true);
94        assert!(!visibility.contains_key(&a));
95        assert!(is_column_visible(&visibility, &a));
96    }
97
98    #[test]
99    fn toggle_column_visible_flips_default_visible() {
100        let mut visibility = ColumnVisibilityState::default();
101        let a = ColumnId::from("a");
102
103        assert!(is_column_visible(&visibility, &a));
104        toggle_column_visible(&mut visibility, &a, None);
105        assert!(!is_column_visible(&visibility, &a));
106        toggle_column_visible(&mut visibility, &a, None);
107        assert!(is_column_visible(&visibility, &a));
108    }
109}