dioxus_tabular/
column.rs

1use crate::{ColumnContext, Row};
2use dioxus::prelude::*;
3
4/// Describes how a single column renders, filters, and sorts rows.
5///
6/// This is the main trait you implement to define a column's behavior. Each column
7/// is a self-contained unit that can:
8/// - Render its header and cells
9/// - Filter rows based on custom logic
10/// - Sort rows with custom comparison
11/// - Hold its own reactive state via `Signal`
12///
13/// # Type Parameter
14///
15/// - `R`: The row type this column works with (must implement [`Row`])
16///
17/// # Example
18///
19/// ```
20/// use dioxus::prelude::*;
21/// use dioxus_tabular::*;
22///
23/// #[derive(Clone, PartialEq)]
24/// struct Product {
25///     id: u32,
26///     name: String,
27///     price: u32,
28/// }
29///
30/// impl Row for Product {
31///     fn key(&self) -> impl Into<String> {
32///         self.id.to_string()
33///     }
34/// }
35///
36/// #[derive(Clone, PartialEq)]
37/// struct Price(u32);
38///
39/// impl GetRowData<Price> for Product {
40///     fn get(&self) -> Price {
41///         Price(self.price)
42///     }
43/// }
44///
45/// // A column that displays and sorts by price
46/// #[derive(Clone, PartialEq)]
47/// struct PriceColumn;
48///
49/// impl<R: Row + GetRowData<Price>> TableColumn<R> for PriceColumn {
50///     fn column_name(&self) -> String {
51///         "price".into()
52///     }
53///
54///     fn render_header(&self, _context: ColumnContext, attributes: Vec<Attribute>) -> Element {
55///         rsx! { th { ..attributes, "Price" } }
56///     }
57///
58///     fn render_cell(&self, _context: ColumnContext, row: &R, attributes: Vec<Attribute>) -> Element {
59///         rsx! { td { ..attributes, "¥{row.get().0}" } }
60///     }
61///
62///     fn compare(&self, a: &R, b: &R) -> std::cmp::Ordering {
63///         a.get().0.cmp(&b.get().0)
64///     }
65/// }
66/// ```
67///
68/// # Filtering Example
69///
70/// ```
71/// # use dioxus::prelude::*;
72/// # use dioxus_tabular::*;
73/// # #[derive(Clone, PartialEq)]
74/// # struct Product { price: u32, id: u32 }
75/// # impl Row for Product {
76/// #     fn key(&self) -> impl Into<String> { self.id.to_string() }
77/// # }
78/// # #[derive(Clone, PartialEq)]
79/// # struct Price(u32);
80/// # impl GetRowData<Price> for Product {
81/// #     fn get(&self) -> Price { Price(self.price) }
82/// # }
83/// #[derive(Clone, PartialEq)]
84/// struct PriceColumn {
85///     min_price: Signal<u32>,
86/// }
87///
88/// impl<R: Row + GetRowData<Price>> TableColumn<R> for PriceColumn {
89///     fn column_name(&self) -> String {
90///         "price".into()
91///     }
92///
93///     fn render_header(&self, _context: ColumnContext, attributes: Vec<Attribute>) -> Element {
94///         rsx! { th { ..attributes, "Price" } }
95///     }
96///
97///     fn render_cell(&self, _context: ColumnContext, row: &R, attributes: Vec<Attribute>) -> Element {
98///         rsx! { td { ..attributes, "¥{row.get().0}" } }
99///     }
100///
101///     // Only show rows with price >= min_price
102///     fn filter(&self, row: &R) -> bool {
103///         row.get().0 >= *self.min_price.read()
104///     }
105/// }
106/// ```
107pub trait TableColumn<R: Row>: Clone + PartialEq + 'static {
108    /// Returns the unique name of this column.
109    ///
110    /// This name is used as a key for the column and should be unique within a table.
111    fn column_name(&self) -> String;
112
113    /// Renders the column header.
114    ///
115    /// Use `context.sort_info()` to display sort state, and spread `attributes` onto your header element.
116    /// Typically returns a `<th>` element.
117    fn render_header(&self, context: ColumnContext, attributes: Vec<Attribute>) -> Element;
118
119    /// Renders a cell for the given row.
120    ///
121    /// Access row data via `GetRowData::get()`, and spread `attributes` onto your cell element.
122    /// Typically returns a `<td>` element.
123    fn render_cell(&self, context: ColumnContext, row: &R, attributes: Vec<Attribute>) -> Element;
124
125    /// Determines whether a row should be displayed.
126    ///
127    /// Return `true` to include the row, `false` to filter it out.
128    /// All column filters are combined with AND logic.
129    /// Default: includes all rows.
130    fn filter(&self, row: &R) -> bool {
131        let _ = row;
132        true
133    }
134
135    /// Compares two rows for sorting.
136    ///
137    /// Return `Ordering::Less` if `a < b`, `Ordering::Greater` if `a > b`, or `Ordering::Equal`.
138    /// Used for multi-column sorting when this column is in the sort list.
139    /// Default: considers all rows equal (no sorting).
140    fn compare(&self, a: &R, b: &R) -> std::cmp::Ordering {
141        let _ = (a, b);
142        std::cmp::Ordering::Equal
143    }
144}