freya_components/
loader.rs

1use freya_animation::prelude::*;
2use freya_core::prelude::*;
3use torin::size::Size;
4
5use crate::{
6    get_theme,
7    theming::component_themes::CircularLoaderThemePartial,
8};
9
10/// Circular loader component.
11///
12/// # Example
13///
14/// ```rust
15/// # use freya::prelude::*;
16/// fn app() -> impl IntoElement {
17///     CircularLoader::new()
18/// }
19///
20/// # use freya_testing::prelude::*;
21/// # launch_doc(|| {
22/// #   rect().spacing(8.).center().expanded().child(app())
23/// # }, "./images/gallery_circular_loader.png").render();
24/// ```
25///
26/// # Preview
27/// ![Circular Loader Preview][circular_loader]
28#[cfg_attr(feature = "docs",
29    doc = embed_doc_image::embed_image!("circular_loader", "images/gallery_circular_loader.png")
30)]
31#[derive(PartialEq)]
32pub struct CircularLoader {
33    pub(crate) theme: Option<CircularLoaderThemePartial>,
34    size: f32,
35    key: DiffKey,
36}
37
38impl KeyExt for CircularLoader {
39    fn write_key(&mut self) -> &mut DiffKey {
40        &mut self.key
41    }
42}
43
44impl Default for CircularLoader {
45    fn default() -> Self {
46        Self::new()
47    }
48}
49
50impl CircularLoader {
51    pub fn new() -> Self {
52        Self {
53            size: 32.,
54            theme: None,
55            key: DiffKey::None,
56        }
57    }
58
59    pub fn size(mut self, size: f32) -> Self {
60        self.size = size;
61        self
62    }
63}
64
65impl Render for CircularLoader {
66    fn render(&self) -> impl IntoElement {
67        let theme = get_theme!(&self.theme, circular_loader);
68
69        let animation = use_animation(|conf| {
70            conf.on_creation(OnCreation::Run);
71            conf.on_finish(OnFinish::restart());
72            AnimNum::new(0.0, 360.0).time(650)
73        });
74
75        svg(Bytes::from_static(
76            r#"<svg viewBox="0 0 600 600" xmlns="http://www.w3.org/2000/svg">
77                <circle class="spin" cx="300" cy="300" fill="none"
78                r="250" stroke-width="64" stroke="{color}"
79                stroke-dasharray="256 1400"
80                stroke-linecap="round" />
81            </svg>"#
82                .as_bytes(),
83        ))
84        .a11y_focusable(true)
85        .a11y_role(AccessibilityRole::ProgressIndicator)
86        .width(Size::px(self.size))
87        .height(Size::px(self.size))
88        .stroke(theme.primary_color)
89        .rotate(animation.get().value())
90    }
91
92    fn render_key(&self) -> DiffKey {
93        self.key.clone().or(self.default_key())
94    }
95}