patternfly_yew/components/table/
composable.rs1use crate::prelude::{Button, ButtonVariant};
2use yew::prelude::*;
3
4use super::*;
5
6const OUIA: Ouia = ouia!("Table");
7
8#[derive(Debug, Clone, PartialEq, Properties)]
10pub struct ComposableTableProperties {
11 #[prop_or_default]
12 pub class: Classes,
13 #[prop_or_default]
14 pub children: Html,
15 #[prop_or_default]
16 pub mode: TableMode,
17 #[prop_or_default]
18 pub sticky_header: bool,
19 #[prop_or_default]
20 pub grid: Option<TableGridMode>,
21 #[prop_or(true)]
22 pub borders: bool,
23 #[prop_or_default]
24 pub id: AttrValue,
25 #[prop_or_default]
27 pub ouia_id: Option<String>,
28 #[prop_or(OUIA.component_type())]
30 pub ouia_type: OuiaComponentType,
31 #[prop_or(OuiaSafe::TRUE)]
33 pub ouia_safe: OuiaSafe,
34}
35
36#[function_component(ComposableTable)]
46pub fn composable_table(props: &ComposableTableProperties) -> Html {
47 let ouia_id = use_memo(props.ouia_id.clone(), |id| {
48 id.clone().unwrap_or(OUIA.generated_id())
49 });
50 let mut class = classes!("pf-v5-c-table", props.class.clone());
51 if props.sticky_header {
52 class.push(classes!("pf-m-sticky-header"));
53 }
54 class.extend_from(&props.grid);
55
56 if !props.borders {
57 class.push(classes!("pf-m-no-border-rows"));
58 }
59
60 match props.mode {
61 TableMode::Compact => {
62 class.push(classes!("pf-m-compact"));
63 }
64 TableMode::CompactNoBorders => {
65 class.push(classes!("pf-m-compact", "pf-m-no-border-rows"));
66 }
67 TableMode::CompactExpandable => {
68 class.push(classes!("pf-m-compact"));
69 }
70 TableMode::Expandable => {
71 class.push(classes!("pf-m-expandable"));
72 }
73 TableMode::Default => {}
74 }
75
76 html! {
77 <table
78 id={&props.id}
79 {class}
80 role="grid"
81 data-ouia-component-id={(*ouia_id).clone()}
82 data-ouia-component-type={props.ouia_type}
83 data-ouia-safe={props.ouia_safe}
84 >
85 {props.children.clone()}
86 </table>
87
88 }
89}
90
91#[derive(Debug, Clone, PartialEq, Properties)]
92pub struct CaptionProperties {
93 #[prop_or_default]
94 pub children: Html,
95}
96
97#[function_component(Caption)]
98pub fn caption(props: &CaptionProperties) -> Html {
99 html! {
100 <caption class="pf-v5-c-table__caption">{props.children.clone()}</caption>
101 }
102}
103
104#[derive(Debug, Clone, PartialEq, Properties)]
105pub struct TableBodyProperties {
106 #[prop_or_default]
107 pub class: Classes,
108 #[prop_or_default]
109 pub children: Html,
110 #[prop_or_default]
111 pub expanded: bool,
112}
113
114#[function_component(TableBody)]
115pub fn table_body(props: &TableBodyProperties) -> Html {
116 let mut class = classes!("pf-v5-c-table__tbody", props.class.clone());
117 if props.expanded {
118 class.push("pf-m-expanded");
119 }
120 html! {
121 <tbody {class} role="rowgroup">
122 {props.children.clone()}
123 </tbody>
124 }
125}
126
127#[derive(Debug, Clone, PartialEq, Properties)]
128pub struct TableRowProperties {
129 #[prop_or_default]
130 pub class: Classes,
131 #[prop_or_default]
132 pub children: Html,
133 #[prop_or_default]
134 pub onclick: Option<Callback<MouseEvent>>,
135 #[prop_or_default]
136 pub selected: bool,
137 #[prop_or_default]
138 pub expandable: bool,
139 #[prop_or_default]
140 pub expanded: bool,
141 #[prop_or_default]
142 pub control_row: bool,
143}
144
145#[function_component(TableRow)]
146pub fn table_row(props: &TableRowProperties) -> Html {
147 let mut class = classes!("pf-v5-c-table__tr", props.class.clone());
148 if props.onclick.is_some() {
149 class.push("pf-m-clickable");
150 }
151 if props.selected {
152 class.push("pf-m-selected");
153 }
154 if props.expanded {
155 class.push("pf-m-expanded");
156 }
157 if props.expandable {
158 class.push("pf-v5-c-table__expandable-row");
159 }
160 if props.control_row {
161 class.push("pf-v5-c-table__control-row");
162 }
163 html! {
164 <tr class={class.clone()} role="row" onclick={props.onclick.clone()}>
165 {props.children.clone()}
166 </tr>
167 }
168}
169
170#[derive(Debug, Clone, PartialEq, Properties)]
171pub struct ExpandableRowContentProperties {
172 #[prop_or_default]
173 pub children: Html,
174 #[prop_or_default]
175 pub class: Classes,
176}
177
178#[function_component(ExpandableRowContent)]
179pub fn expandable_row_content(props: &ExpandableRowContentProperties) -> Html {
180 let class = classes!("pf-v5-c-table__expandable-row-content", props.class.clone());
181 html! {
182 <div {class}>
183 { props.children.clone() }
184 </div>
185 }
186}
187
188#[derive(Debug, Clone, PartialEq)]
189pub struct ExpandParams {
190 pub r#type: ExpandType,
191 pub expanded: bool,
192 pub ontoggle: Callback<()>,
193}
194
195#[derive(Debug, Clone, Copy, PartialEq, Eq)]
196pub enum ExpandType {
197 Row,
198 Column,
199}
200
201#[derive(Debug, Clone, PartialEq, Properties)]
202pub struct TableDataProperties {
203 #[prop_or_default]
204 pub class: Classes,
205 #[prop_or_default]
206 pub children: Html,
207 #[prop_or_default]
208 pub center: bool,
209 #[prop_or_default]
210 pub text_modifier: Option<TextModifier>,
211 #[prop_or_default]
212 pub expandable: Option<ExpandParams>,
213 #[prop_or_default]
214 pub data_label: Option<AttrValue>,
215 #[prop_or_default]
216 pub span_modifiers: Vec<SpanModifiers>,
217 #[prop_or_default]
218 pub colspan: Option<usize>,
219 #[prop_or_default]
220 pub action: bool,
221}
222
223#[function_component(TableData)]
224pub fn table_data(props: &TableDataProperties) -> Html {
225 let mut class = classes!("pf-v5-c-table__td", props.class.clone());
226 if props.center {
227 class.push(classes!("pf-m-center"))
228 }
229 if props.action {
230 class.push("pf-v5-c-table__action");
231 }
232 class.extend_from(&props.text_modifier);
233 class.extend_from(&props.span_modifiers);
234
235 let mut content = props.children.clone();
236 if let Some(expandable) = props.expandable.as_ref() {
237 let onclick = {
238 let ontoggle = expandable.ontoggle.clone();
239 Callback::from(move |_| ontoggle.emit(()))
240 };
241 class.push(match expandable.r#type {
242 ExpandType::Column => "pf-v5-c-table__compound-expansion-toggle",
243 ExpandType::Row => "pf-v5-c-table__toggle",
244 });
245 content = match expandable.r#type {
246 ExpandType::Column => {
247 if expandable.expanded {
248 class.push("pf-m-expanded");
249 }
250 html! {
251 <button class="pf-v5-c-table__button" {onclick}>
252 <span class="pf-v5-c-table__text">
253 { content }
254 </span>
255 </button>
256 }
257 }
258 ExpandType::Row => {
259 let mut button_class = classes!();
260 if expandable.expanded {
261 button_class.push("pf-m-expanded");
262 }
263 html! {
264 <Button
265 variant={ButtonVariant::Plain}
266 class={button_class}
267 {onclick}
268 aria_expanded={expandable.expanded.to_string()}
269 >
270 <div class="pf-v5-c-table__toggle-icon">
271 { Icon::AngleDown }
272 </div>
273 </Button>
274 }
275 }
276 };
277 }
278
279 let colspan = props.colspan.as_ref().map(|cols| cols.to_string());
280 html! {
281 <td {class} role="cell" data-label={props.data_label.clone()} {colspan}>
282 { content }
283 </td>
284 }
285}