Skip to main content

rosace_theme/
lib.rs

1//! `rosace-theme` — design-token system for the ROSACE UI framework.
2//!
3//! # Overview
4//!
5//! This crate provides the complete theming layer:
6//!
7//! - [`Color`] / [`ColorScheme`] — f32 RGBA colors and semantic color roles.
8//! - [`Typography`] — Material Design 3 type scale.
9//! - [`Spacing`] — named spacing tokens.
10//! - [`BorderRadius`] — named corner-radius tokens.
11//! - [`Shadows`] — named elevation/shadow tokens.
12//! - [`ThemeData`] — all tokens in one struct.
13//! - [`RosaceTheme`] — trait for custom themes.
14//! - [`built_in`] — [`light_theme()`] and [`dark_theme()`] factory functions.
15//! - [`use_theme()`] / [`set_theme()`] — global theme access via a reactive atom.
16//!
17//! [`light_theme()`]: built_in::light_theme
18//! [`dark_theme()`]: built_in::dark_theme
19
20pub mod built_in;
21pub mod color;
22pub mod provider;
23pub mod radius;
24pub mod shadow;
25pub mod spacing;
26pub mod theme;
27pub mod themes;
28pub mod typography;
29
30// Flat re-exports for convenience.
31pub use color::{Color, ColorScheme};
32pub use provider::{set_theme, use_theme, set_animations, ThemeMode, use_theme_mode, set_theme_mode, sync_system_theme, register_theme_pair};
33pub use radius::BorderRadius;
34pub use shadow::{ShadowLayer, Shadows};
35pub use spacing::Spacing;
36pub use theme::{AnimationConfig, ThemeData, RosaceTheme, AppBarStyle, TitleAlign};
37pub use themes::Themes;
38pub use typography::{FontFamily, FontWeight, TextStyle, Typography};
39
40// ---------------------------------------------------------------------------
41// Integration-level tests
42// ---------------------------------------------------------------------------
43
44#[cfg(test)]
45mod tests {
46    use super::*;
47
48    #[test]
49    fn color_lerp_integration() {
50        let red   = Color::rgb(1.0, 0.0, 0.0);
51        let blue  = Color::rgb(0.0, 0.0, 1.0);
52        let mid   = red.lerp(blue, 0.5);
53        assert!((mid.r - 0.5).abs() < 1e-6);
54        assert!((mid.b - 0.5).abs() < 1e-6);
55    }
56
57    #[test]
58    fn color_from_hex_integration() {
59        let c = Color::from_hex(0xFF0000); // pure red
60        assert!((c.r - 1.0).abs() < 1e-5);
61        assert!(c.g.abs() < 1e-5);
62        assert!(c.b.abs() < 1e-5);
63        assert_eq!(c.a, 1.0);
64    }
65
66    #[test]
67    fn spacing_defaults_integration() {
68        let s = Spacing::default();
69        assert_eq!(s.xs, 4.0);
70        assert_eq!(s.sm, 8.0);
71    }
72
73    #[test]
74    fn border_radius_defaults_integration() {
75        let r = BorderRadius::default();
76        assert_eq!(r.none, 0.0);
77        assert_eq!(r.full, 9999.0);
78    }
79
80    #[test]
81    fn light_theme_is_dark_false() {
82        let theme = built_in::light_theme();
83        assert!(!theme.is_dark);
84    }
85
86    #[test]
87    fn dark_theme_is_dark_true() {
88        let theme = built_in::dark_theme();
89        assert!(theme.is_dark);
90    }
91
92    #[test]
93    fn typography_scale_order() {
94        let typo = Typography::default();
95        assert!(typo.display_large.size > typo.headline_large.size);
96        assert!(typo.headline_large.size > typo.body_large.size);
97    }
98
99    #[test]
100    fn use_theme_returns_valid_theme_integration() {
101        let theme = use_theme();
102        assert!(theme.spacing.md > 0.0);
103        assert!(theme.radius.md >= 0.0);
104        // Typography sanity check
105        assert!(theme.typography.display_large.size > 0.0);
106    }
107}