rustyle_css/components/
spinner.rs

1//! Spinner component styles
2//!
3//! Provides type-safe loading spinner styling with variants and sizes.
4
5use super::{ComponentStyle, Size, Variant};
6use crate::css::Color;
7use crate::tokens::ColorTokens;
8
9/// Spinner style configuration
10#[derive(Clone, Debug)]
11pub struct SpinnerStyle {
12    pub variant: Variant,
13    pub size: Size,
14    pub tokens: Option<SpinnerTokens>,
15}
16
17/// Spinner design tokens
18#[derive(Clone, Debug)]
19pub struct SpinnerTokens {
20    pub colors: ColorTokens,
21}
22
23impl SpinnerStyle {
24    /// Create a new spinner style
25    pub fn new(variant: Variant, size: Size) -> Self {
26        Self {
27            variant,
28            size,
29            tokens: None,
30        }
31    }
32
33    /// Set custom tokens
34    pub fn tokens(mut self, tokens: SpinnerTokens) -> Self {
35        self.tokens = Some(tokens);
36        self
37    }
38
39    fn color(&self) -> Color {
40        let default_colors = ColorTokens::default();
41        let colors = self
42            .tokens
43            .as_ref()
44            .map(|t| &t.colors)
45            .unwrap_or(&default_colors);
46
47        match &self.variant {
48            Variant::Primary => colors.primary.c500.clone(),
49            Variant::Secondary => colors.secondary.c500.clone(),
50            Variant::Success => colors.semantic.success.clone(),
51            Variant::Error => colors.semantic.error.clone(),
52            Variant::Warning => colors.semantic.warning.clone(),
53            Variant::Info => colors.semantic.info.clone(),
54        }
55    }
56
57    fn size_px(&self) -> String {
58        match &self.size {
59            Size::Small => "16px".to_string(),
60            Size::Medium => "24px".to_string(),
61            Size::Large => "32px".to_string(),
62            Size::ExtraLarge => "48px".to_string(),
63        }
64    }
65}
66
67impl ComponentStyle for SpinnerStyle {
68    fn to_css(&self) -> String {
69        let mut css = String::new();
70
71        css.push_str(&format!("color: {}; ", self.color().to_css()));
72        css.push_str(&format!("width: {}; ", self.size_px()));
73        css.push_str(&format!("height: {}; ", self.size_px()));
74        css.push_str("display: inline-block; ");
75        css.push_str("border: 2px solid currentColor; ");
76        css.push_str("border-right-color: transparent; ");
77        css.push_str("border-radius: 50%; ");
78        css.push_str("animation: spin 0.6s linear infinite; ");
79
80        css
81    }
82
83    fn class_name(&self) -> &str {
84        "rustyle-spinner"
85    }
86}
87
88impl Default for SpinnerStyle {
89    fn default() -> Self {
90        Self::new(Variant::Primary, Size::Medium)
91    }
92}