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}