yew_bootstrap/component/
progress.rs

1use yew::prelude::*;
2use gloo_console::warn;
3
4use crate::util::Color;
5
6/// # Progress component
7///
8/// See [ProgressProps] for a listing of properties
9///
10/// # Example of simple Progress bar
11/// ``` rust
12/// use yew::prelude::*;
13/// use yew_bootstrap::component::{Progress, ProgressBar};
14/// use yew_bootstrap::util::Color;
15/// fn test() -> Html {
16///     html!{
17///         <Progress>
18///           <ProgressBar style={Some(Color::Primary)} value=25/>
19///         </Progress>
20///     }
21/// }
22/// ```
23///
24/// # Example of multiple bars in the same progress
25/// ``` rust
26/// use yew::prelude::*;
27/// use yew_bootstrap::component::{Progress, ProgressBar};
28/// use yew_bootstrap::util::Color;
29/// fn test() -> Html {
30///     html!{
31///         <Progress>
32///             <ProgressBar style={Some(Color::Primary)} value=15/>
33///             <ProgressBar style={Some(Color::Info)} value=30/>
34///             <ProgressBar style={Some(Color::Warning)} value=20 striped={true}/>
35///         </Progress>
36///     }
37/// }
38/// ```
39
40/// Properties for [Progress]
41#[derive(Properties, Clone, PartialEq)]
42pub struct ProgressProps {
43    #[prop_or_default]
44    pub children: Children,
45
46    /// Additional class
47    #[prop_or_default]
48    pub class: Classes,
49
50    /// Height of the select in pts, default None
51    #[prop_or(None)]
52    pub height: Option<i32>,
53}
54
55/// Properties for [ProgressBar]
56#[derive(Properties, Clone, PartialEq)]
57pub struct ProgressBarProps {
58    /// Optional color for the bar
59    #[prop_or_default]
60    pub style: Option<Color>,
61
62    /// Current value, between min and max
63    pub value: i32,
64
65    /// Minimum value, default 0
66    #[prop_or(0)]
67    pub min: i32,
68
69    /// Maximum value, default 100
70    #[prop_or(100)]
71    pub max: i32,
72
73    /// Striped, default false
74    #[prop_or_default]
75    pub striped: bool,
76
77    /// Animated, this forces striped
78    #[prop_or_default]
79    pub animated: bool,
80
81    /// Optional label placed on the bar
82    #[prop_or_default]
83    pub label: AttrValue,
84
85    /// Additional class
86    #[prop_or_default]
87    pub class: Classes,
88}
89
90
91/// # Progress component, it can contain [ProgressBar] children
92#[function_component]
93pub fn Progress(props: &ProgressProps) -> Html {
94    let height = props.height.map(|val| format!("height: {val}px;"));
95
96    html! {
97        <div class={classes!("progress", props.class.clone())} style={height} >
98            { for props.children.iter() }
99        </div>
100    }
101}
102
103/// # ProgressBar component, contained inside a [Progress] parent
104#[function_component]
105pub fn ProgressBar(props: &ProgressBarProps) -> Html {
106    if props.min >= props.max {
107        warn!(format!("ProgressBar: min ({}) needs to be less than max ({})", props.min, props.max));
108    }
109
110    if props.value < props.min || props.value > props.max {
111        warn!(format!("ProgressBar: value is {}, should be between {} and {}", props.value, props.min, props.max));
112    }
113
114    let width = if props.min < props.max { 100 * (props.value - props.min) / (props.max - props.min) } else { props.min };
115    let width = format!("width: {width}%;");
116
117    let mut progress_classes = props.class.clone();
118    if let Some(color) = &props.style {
119        progress_classes.push(format!("bg-{color}"))
120    }
121    if props.striped || props.animated {
122        progress_classes.push("progress-bar-striped")
123    }
124    if props.animated {
125        progress_classes.push("progress-bar-animated")
126    }
127
128    html! {
129        <div
130            class={classes!("progress-bar", progress_classes)}
131            role={"progressbar"}
132            style={width}
133            aria-valuenow={props.value.to_string()}
134            aria-valuemin={props.min.to_string()}
135            aria-valuemax={props.max.to_string()}
136        >
137            {props.label.clone()}
138        </div>
139    }
140}