yew_bootstrap/component/
list_group.rs

1use yew::prelude::*;
2use crate::util::Color;
3use super::*;
4
5/// The variant style of a [ListGroup]
6#[derive(Copy, Clone, Debug, PartialEq, Eq)]
7pub enum ListGroupVariant {
8    /// Default style, with rounded corners and outer borders.
9    Default,
10    /// Flush style, removes rounding and border.
11    Flush,
12}
13
14impl Default for ListGroupVariant {
15    fn default() -> Self {
16        ListGroupVariant::Default
17    }
18}
19
20/// A size threshold to trigger a property at
21#[derive(Clone, Debug, PartialEq, Eq)]
22pub enum SizeTrigger {
23    /// Trigger at the given size boundary
24    AtSize(ContainerSize),
25    /// Always active
26    Always,
27    /// Never active
28    Never,
29}
30
31/// # Properties of [ListGroup]
32#[derive(Properties, Clone, PartialEq)]
33pub struct ListGroupProps {
34    /// Inner items (displayed in the [ListGroup]).
35    #[prop_or_default]
36    pub children: ChildrenWithProps<ListGroupItem>,
37    /// Extra CSS classes to include, in addition to the defaults.
38    #[prop_or_default]
39    pub class: Classes,
40    /// Display variant to use, see [ListGroupVariant] for all options.
41    #[prop_or_default]
42    pub variant: ListGroupVariant,
43    /// Whether to number the list.
44    #[prop_or_default]
45    pub numbered: bool,
46    /// Control when the list is displayed horizontally. Always, or at a certain container size.
47    #[prop_or(SizeTrigger::Never)]
48    pub horizontal: SizeTrigger,
49}
50
51/// # ListGroup component
52/// A list of items with various properties, including support for numbering, actions, and item
53/// colors.
54///
55/// Items are expected to be instances of [ListGroupItem]
56///
57/// See [ListGroupProps] for a list of properties.
58///
59/// ## Example
60/// Example of a simple list group:
61///
62/// ```rust
63/// use yew::prelude::*;
64/// use yew_bootstrap::component::{ListGroup, ListGroupItem};
65/// fn test() -> Html {
66///     html! {
67///         <ListGroup>
68///             <ListGroupItem>{"First"}</ListGroupItem>
69///             <ListGroupItem active=true>{"Second"}</ListGroupItem>
70///             <ListGroupItem>{"Third"}</ListGroupItem>
71///         </ListGroup>
72///     }
73/// }
74///
75#[function_component]
76pub fn ListGroup(props: &ListGroupProps) -> Html {
77    let mut classes = Classes::from("list-group");
78
79    classes.extend(&props.class);
80
81    match props.variant {
82        ListGroupVariant::Default => (),
83        ListGroupVariant::Flush => classes.push("list-group-flush"),
84    };
85
86    match &props.horizontal {
87        SizeTrigger::Never => (),
88        SizeTrigger::Always => classes.push("list-group-horizontal"),
89        SizeTrigger::AtSize(size) => classes.push(format!("list-group-horizontal-{}", size.to_string())),
90    }
91
92    if props.numbered {
93        classes.push("list-group-numbered")
94    }
95
96    html! {
97        <div class={classes}>
98            { for props.children.iter() }
99        </div>
100    }
101}
102
103/// # Properties for [ListGroupItem]
104#[derive(Properties, Clone, PartialEq)]
105pub struct ListGroupItemProps {
106    /// Inner components (displayed in the [ListGroupItem]).
107    #[prop_or_default]
108    pub children: Children,
109    /// Extra CSS classes to include, in addition to the defaults.
110    #[prop_or_default]
111    pub class: Classes,
112    /// Optional color to use for the background and border of this item.
113    #[prop_or_default]
114    pub style: Option<Color>,
115    /// Whether this item is the currently active one
116    #[prop_or_default]
117    pub active: bool,
118    /// Whether this item is disabled
119    #[prop_or_default]
120    pub disabled: bool,
121    /// Whether this item is actionable, enables hover and click reactivity.
122    #[prop_or_default]
123    pub action: bool,
124    /// URL to direct to when the list item is clicked
125    #[prop_or_default]
126    pub url: Option<AttrValue>,
127    /// Event called when the list item is clicked
128    #[prop_or_default]
129    pub onclick: Callback<MouseEvent>,
130}
131
132/// # ListGroupItem
133/// Used with [ListGroup] to create grouped lists of items.
134///
135/// See [ListGroupItemProps] for a list of properties.
136///
137/// ## Example
138/// Example of a simple list group:
139///
140/// ```rust
141/// use yew::prelude::*;
142/// use yew_bootstrap::component::{ListGroup, ListGroupItem};
143/// use yew_bootstrap::util::Color;
144/// fn test() -> Html {
145///     html! {
146///         <ListGroup>
147///             <ListGroupItem style={Color::Light}>{"First"}</ListGroupItem>
148///             <ListGroupItem active=true>{"Second"}</ListGroupItem>
149///             <ListGroupItem disabled=true>{"Third"}</ListGroupItem>
150///         </ListGroup>
151///     }
152/// }
153///
154#[function_component]
155pub fn ListGroupItem(props: &ListGroupItemProps) -> Html {
156    let mut classes = Classes::from("list-group-item");
157
158    classes.extend(&props.class);
159
160    if props.active {
161        classes.push("active");
162    }
163    if props.disabled {
164        classes.push("disabled");
165    }
166    if let Some(style) = &props.style {
167        classes.push(format!("list-group-item-{}", style));
168    }
169
170    if props.action && props.url.is_some() {
171        classes.push("list-group-item-action");
172        html! {
173            <a class={classes} href={&props.url} onclick={props.onclick.clone()}>
174                {props.children.clone()}
175            </a>
176        }
177    } else if props.action {
178        classes.push("list-group-item-action");
179        html! {
180            <button class={classes} onclick={props.onclick.clone()}>
181                {props.children.clone()}
182            </button>
183        }
184    } else {
185        html! {
186            <div class={classes}>
187                {props.children.clone()}
188            </div>
189        }
190    }
191}