patternfly_yew/components/
list.rs

1//! List
2use crate::icon::Icon;
3use crate::prelude::{AsClasses, ExtendClasses};
4use crate::utils::Raw;
5use yew::html::ChildrenRenderer;
6use yew::virtual_dom::VChild;
7use yew::{html::IntoPropValue, prelude::*, virtual_dom::AttrValue};
8
9#[derive(Copy, Clone, PartialEq, Eq)]
10pub enum ListType {
11    Basic,
12    Inline,
13    Ordered(ListOrder),
14    Plain,
15    Bordered,
16}
17
18impl AsClasses for ListType {
19    fn extend_classes(&self, classes: &mut Classes) {
20        match self {
21            ListType::Inline => {
22                classes.push(classes!("pf-m-inline"));
23            }
24            ListType::Plain => {
25                classes.push(classes!("pf-m-plain"));
26            }
27            ListType::Bordered => {
28                classes.push(classes!("pf-m-plain", "pf-m-bordered"));
29            }
30            _ => {}
31        }
32    }
33}
34
35impl Default for ListType {
36    fn default() -> Self {
37        Self::Basic
38    }
39}
40
41#[derive(Copy, Clone, Default, PartialEq, Eq)]
42pub enum ListOrder {
43    #[default]
44    Number,
45    LowercaseLetter,
46    UppercaseLetter,
47    LowercaseRomanNumber,
48    UppercaseRomanNumber,
49}
50
51impl IntoPropValue<Option<AttrValue>> for ListOrder {
52    fn into_prop_value(self) -> Option<AttrValue> {
53        Some(AttrValue::Static(match self {
54            Self::Number => "1",
55            Self::LowercaseLetter => "a",
56            Self::UppercaseLetter => "A",
57            Self::LowercaseRomanNumber => "i",
58            Self::UppercaseRomanNumber => "I",
59        }))
60    }
61}
62
63/// Properties for [`List`]
64#[derive(PartialEq, Properties)]
65pub struct ListProperties {
66    #[prop_or_default]
67    pub children: ChildrenRenderer<ListChildVariant>,
68    #[prop_or_default]
69    pub r#type: ListType,
70    #[prop_or_default]
71    pub icon_size: ListIconSize,
72}
73
74#[derive(Clone, Copy, Default, Eq, PartialEq, Debug)]
75pub enum ListIconSize {
76    #[default]
77    Default,
78    Large,
79}
80
81impl AsClasses for ListIconSize {
82    fn extend_classes(&self, classes: &mut Classes) {
83        match self {
84            Self::Default => {}
85            Self::Large => classes.extend(classes!("pf-m-icon-lg")),
86        }
87    }
88}
89
90/// List component
91///
92/// > A **list** component embeds a formatted list (bulleted or numbered list) into page content.
93///
94/// See: <https://www.patternfly.org/components/list>
95///
96/// ## Properties
97///
98/// Defined by [`ListProperties`].
99///
100/// ## Children
101///
102/// Requires to use [`ListItem`] as children.
103///
104/// ## Example
105///
106/// ```rust
107/// use yew::prelude::*;
108/// use patternfly_yew::prelude::*;
109///
110/// #[function_component(Example)]
111/// fn example() -> Html {
112///   html!(
113///     <List>
114///       <ListItem>{"Foo"}</ListItem>
115///       <ListItem>{"Bar"}</ListItem>
116///       // you can also inject a "raw" item, just be sure to add the `li` or `ListItem` element.
117///       <Raw>
118///         <li>{"Baz"}</li>
119///       </Raw>
120///     </List>
121///   )
122/// }
123/// ```
124#[function_component(List)]
125pub fn list(props: &ListProperties) -> Html {
126    let mut classes = Classes::from("pf-v5-c-list");
127
128    classes.extend_from(&props.r#type);
129    classes.extend_from(&props.icon_size);
130
131    let l = |items| match props.r#type {
132        ListType::Basic | ListType::Inline | ListType::Plain | ListType::Bordered => {
133            html! (<ul class={classes} role="list">{ items }</ul>)
134        }
135        ListType::Ordered(n) => {
136            html! (<ol type={n} class={classes} role="list">{ items }</ol>)
137        }
138    };
139
140    l(html! ({
141         for props.children.clone()
142    }))
143}
144
145#[derive(PartialEq, Properties)]
146pub struct ListItemProperties {
147    #[prop_or_default]
148    pub children: Html,
149    #[prop_or_default]
150    pub icon: Option<Icon>,
151}
152
153#[function_component(ListItem)]
154pub fn list_item(props: &ListItemProperties) -> Html {
155    match props.icon {
156        Some(icon) => {
157            let class = classes!("pf-v5-c-list__item");
158            html!(
159                <li {class}>
160                    <span class={classes!("pf-v5-c-list__item-icon")}>
161                        { icon }
162                    </span>
163                    <span class={classes!("pf-v5-c-list__item-text")}>
164                        { props.children.clone() }
165                    </span>
166                </li>
167            )
168        }
169        None => html!( <li> { props.children.clone() } </li> ),
170    }
171}
172
173#[derive(Clone, PartialEq)]
174pub enum ListChildVariant {
175    Item(VChild<ListItem>),
176    Raw(VChild<Raw>),
177}
178
179impl From<VChild<ListItem>> for ListChildVariant {
180    fn from(value: VChild<ListItem>) -> Self {
181        Self::Item(value)
182    }
183}
184
185impl From<VChild<Raw>> for ListChildVariant {
186    fn from(value: VChild<Raw>) -> Self {
187        Self::Raw(value)
188    }
189}
190
191impl From<ListChildVariant> for Html {
192    fn from(value: ListChildVariant) -> Self {
193        match value {
194            ListChildVariant::Item(child) => child.into(),
195            ListChildVariant::Raw(child) => child.into(),
196        }
197    }
198}