yew_bs/components/
table.rs

1use yew::prelude::*;
2use crate::components::common::Variant;
3#[derive(Properties, PartialEq)]
4pub struct TableProps {
5    #[prop_or_default]
6    pub children: Children,
7    #[prop_or_default]
8    pub striped: bool,
9    #[prop_or_default]
10    pub bordered: bool,
11    #[prop_or_default]
12    pub borderless: bool,
13    #[prop_or_default]
14    pub hover: bool,
15    #[prop_or_default]
16    pub size: Option<TableSize>,
17    #[prop_or_default]
18    pub variant: Option<Variant>,
19    #[prop_or_default]
20    pub responsive: bool,
21    #[prop_or_default]
22    pub responsive_breakpoint: Option<ResponsiveBreakpoint>,
23    #[prop_or_default]
24    pub class: Option<AttrValue>,
25    #[prop_or_default]
26    pub node_ref: NodeRef,
27    #[prop_or_default]
28    pub caption: Option<AttrValue>,
29}
30#[derive(Clone, Copy, PartialEq, Debug)]
31pub enum TableSize {
32    Small,
33    Large,
34}
35#[derive(Clone, Copy, PartialEq, Debug)]
36pub enum ResponsiveBreakpoint {
37    Sm,
38    Md,
39    Lg,
40    Xl,
41    Xxl,
42}
43impl ResponsiveBreakpoint {
44    pub fn as_str(&self) -> &'static str {
45        match self {
46            ResponsiveBreakpoint::Sm => "sm",
47            ResponsiveBreakpoint::Md => "md",
48            ResponsiveBreakpoint::Lg => "lg",
49            ResponsiveBreakpoint::Xl => "xl",
50            ResponsiveBreakpoint::Xxl => "xxl",
51        }
52    }
53}
54/// Bootstrap Table component
55#[function_component(Table)]
56pub fn table(props: &TableProps) -> Html {
57    let mut table_classes = Classes::new();
58    table_classes.push("table");
59    if props.striped {
60        table_classes.push("table-striped");
61    }
62    if props.bordered {
63        table_classes.push("table-bordered");
64    }
65    if props.borderless {
66        table_classes.push("table-borderless");
67    }
68    if props.hover {
69        table_classes.push("table-hover");
70    }
71    if let Some(size) = props.size {
72        match size {
73            TableSize::Small => table_classes.push("table-sm"),
74            TableSize::Large => table_classes.push("table-lg"),
75        }
76    }
77    if let Some(variant) = &props.variant {
78        table_classes.push(format!("table-{}", variant.as_str()));
79    }
80    if let Some(class) = &props.class {
81        table_classes.push(class.to_string());
82    }
83    let content = html! {
84        < table class = { table_classes } ref = { props.node_ref.clone() } > if let
85        Some(caption) = & props.caption { < caption > { caption } </ caption > } { for
86        props.children.iter() } </ table >
87    };
88    if props.responsive {
89        let mut wrapper_classes = Classes::new();
90        wrapper_classes.push("table-responsive");
91        if let Some(breakpoint) = props.responsive_breakpoint {
92            wrapper_classes.push(format!("table-responsive-{}", breakpoint.as_str()));
93        }
94        html! {
95            < div class = { wrapper_classes } > { content } </ div >
96        }
97    } else {
98        content
99    }
100}
101/// Props for the TableHead component
102#[derive(Properties, PartialEq)]
103pub struct TableHeadProps {
104    /// Table head children (typically TableRow components)
105    #[prop_or_default]
106    pub children: Children,
107    /// Whether this is a dark header
108    #[prop_or_default]
109    pub dark: bool,
110    /// Whether this is a light header
111    #[prop_or_default]
112    pub light: bool,
113    /// Additional CSS classes
114    #[prop_or_default]
115    pub class: Option<AttrValue>,
116    /// Additional HTML attributes
117    #[prop_or_default]
118    pub node_ref: NodeRef,
119}
120/// Bootstrap TableHead component
121#[function_component(TableHead)]
122pub fn table_head(props: &TableHeadProps) -> Html {
123    let mut classes = Classes::new();
124    if props.dark {
125        classes.push("table-dark");
126    }
127    if props.light {
128        classes.push("table-light");
129    }
130    if let Some(class) = &props.class {
131        classes.push(class.to_string());
132    }
133    html! {
134        < thead class = { classes } ref = { props.node_ref.clone() } > { for props
135        .children.iter() } </ thead >
136    }
137}
138/// Props for the TableBody component
139#[derive(Properties, PartialEq)]
140pub struct TableBodyProps {
141    /// Table body children (typically TableRow components)
142    #[prop_or_default]
143    pub children: Children,
144    /// Additional CSS classes
145    #[prop_or_default]
146    pub class: Option<AttrValue>,
147    /// Additional HTML attributes
148    #[prop_or_default]
149    pub node_ref: NodeRef,
150}
151/// Bootstrap TableBody component
152#[function_component(TableBody)]
153pub fn table_body(props: &TableBodyProps) -> Html {
154    let mut classes = Classes::new();
155    if let Some(class) = &props.class {
156        classes.push(class.to_string());
157    }
158    html! {
159        < tbody class = { classes } ref = { props.node_ref.clone() } > { for props
160        .children.iter() } </ tbody >
161    }
162}
163/// Props for the TableRow component
164#[derive(Properties, PartialEq)]
165pub struct TableRowProps {
166    /// Table row children (typically TableCell components)
167    #[prop_or_default]
168    pub children: Children,
169    /// Whether this is an active row
170    #[prop_or_default]
171    pub active: bool,
172    /// Row color variant
173    #[prop_or_default]
174    pub variant: Option<Variant>,
175    /// Additional CSS classes
176    #[prop_or_default]
177    pub class: Option<AttrValue>,
178    /// Additional HTML attributes
179    #[prop_or_default]
180    pub node_ref: NodeRef,
181}
182/// Bootstrap TableRow component
183#[function_component(TableRow)]
184pub fn table_row(props: &TableRowProps) -> Html {
185    let mut classes = Classes::new();
186    if props.active {
187        classes.push("table-active");
188    }
189    if let Some(variant) = &props.variant {
190        classes.push(format!("table-{}", variant.as_str()));
191    }
192    if let Some(class) = &props.class {
193        classes.push(class.to_string());
194    }
195    html! {
196        < tr class = { classes } ref = { props.node_ref.clone() } > { for props.children
197        .iter() } </ tr >
198    }
199}
200/// Props for the TableCell component
201#[derive(Properties, PartialEq)]
202pub struct TableCellProps {
203    /// Table cell children
204    #[prop_or_default]
205    pub children: Children,
206    /// Whether this is a header cell
207    #[prop_or_default]
208    pub header: bool,
209    /// Whether this is an active cell
210    #[prop_or_default]
211    pub active: bool,
212    /// Cell color variant
213    #[prop_or_default]
214    pub variant: Option<Variant>,
215    /// Column span
216    #[prop_or_default]
217    pub colspan: Option<u8>,
218    /// Row span
219    #[prop_or_default]
220    pub rowspan: Option<u8>,
221    /// Additional CSS classes
222    #[prop_or_default]
223    pub class: Option<AttrValue>,
224    /// Additional HTML attributes
225    #[prop_or_default]
226    pub node_ref: NodeRef,
227}
228/// Bootstrap TableCell component
229#[function_component(TableCell)]
230pub fn table_cell(props: &TableCellProps) -> Html {
231    let mut classes = Classes::new();
232    if props.active {
233        classes.push("table-active");
234    }
235    if let Some(variant) = &props.variant {
236        classes.push(format!("table-{}", variant.as_str()));
237    }
238    if let Some(class) = &props.class {
239        classes.push(class.to_string());
240    }
241    let cell_type = if props.header { "th" } else { "td" };
242    html! {
243        <@ { cell_type } class = { classes } ref = { props.node_ref.clone() } colspan = {
244        props.colspan.map(| c | c.to_string()) } rowspan = { props.rowspan.map(| r | r
245        .to_string()) } > { for props.children.iter() } </@>
246    }
247}