Skip to main content

freya_components/
loader.rs

1use freya_animation::prelude::*;
2use freya_core::prelude::*;
3use torin::size::Size;
4
5use crate::{
6    cache::AssetAge,
7    define_theme,
8    get_theme,
9    svg_viewer::SvgViewer,
10};
11
12define_theme! {
13    %[component]
14    pub CircularLoader {
15        %[fields]
16        primary_color: Color,
17    }
18}
19
20/// Circular loader component.
21///
22/// # Example
23///
24/// ```rust
25/// # use freya::prelude::*;
26/// fn app() -> impl IntoElement {
27///     CircularLoader::new()
28/// }
29/// ```
30///
31/// See the [interactive components demo](https://freyaui.dev/demo).
32#[derive(PartialEq)]
33pub struct CircularLoader {
34    pub(crate) theme: Option<CircularLoaderThemePartial>,
35    size: f32,
36    accessibility: AccessibilityData,
37    key: DiffKey,
38}
39
40impl KeyExt for CircularLoader {
41    fn key_mut(&mut self) -> &mut DiffKey {
42        &mut self.key
43    }
44}
45
46impl AccessibilityExt for CircularLoader {
47    fn accessibility_data_mut(&mut self) -> &mut AccessibilityData {
48        &mut self.accessibility
49    }
50}
51
52impl Default for CircularLoader {
53    fn default() -> Self {
54        Self::new()
55    }
56}
57
58impl CircularLoader {
59    pub fn new() -> Self {
60        Self {
61            size: 32.,
62            theme: None,
63            accessibility: AccessibilityData::default(),
64            key: DiffKey::None,
65        }
66    }
67
68    pub fn size(mut self, size: f32) -> Self {
69        self.size = size;
70        self
71    }
72}
73
74impl Component for CircularLoader {
75    fn render(&self) -> impl IntoElement {
76        let theme = get_theme!(
77            &self.theme,
78            CircularLoaderThemePreference,
79            "circular_loader"
80        );
81
82        let animation = use_animation(|conf| {
83            conf.on_creation(OnCreation::Run);
84            conf.on_finish(OnFinish::restart());
85            AnimNum::new(0.0, 360.0).time(650)
86        });
87
88        SvgViewer::new(
89            r#"<svg viewBox="0 0 600 600" xmlns="http://www.w3.org/2000/svg">
90                <circle class="spin" cx="300" cy="300" fill="none"
91                r="250" stroke-width="64" stroke="{color}"
92                stroke-dasharray="256 1400"
93                stroke-linecap="round" />
94            </svg>"#
95                .as_bytes(),
96        )
97        .show_loader(false)
98        .asset_age(AssetAge::zero())
99        .accessibility(self.accessibility.clone())
100        .a11y_role(AccessibilityRole::ProgressIndicator)
101        .width(Size::px(self.size))
102        .height(Size::px(self.size))
103        .stroke(theme.primary_color)
104        .rotation(animation.get().value())
105    }
106
107    fn render_key(&self) -> DiffKey {
108        self.key.clone().or(self.default_key())
109    }
110}