Skip to main content

dioxus_ui_system/
config.rs

1//! Component configuration system
2//!
3//! Allows setting global defaults for all components, such as:
4//! - Default spacing
5//! - Default sizing
6//! - Default styling variants
7//!
8//! # Example
9//! ```rust,ignore
10//! use dioxus_ui_system::config::ComponentConfig;
11//!
12//! // Configure global defaults
13//! ComponentConfig::global()
14//!     .button_defaults(|b| b
15//!         .size(ButtonSize::Lg)
16//!         .variant(ButtonVariant::Secondary))
17//!     .card_defaults(|c| c
18//!         .padding("24px".to_string()));
19//! ```
20
21use std::sync::{Mutex, OnceLock};
22
23/// Global component configuration
24#[derive(Clone, Debug, Default)]
25pub struct Config {
26    /// Default button size ("sm", "md", "lg", "icon")
27    pub button_size: Option<String>,
28    /// Default button variant ("primary", "secondary", "ghost", "destructive", "link")
29    pub button_variant: Option<String>,
30    /// Default card padding
31    pub card_padding: Option<String>,
32    /// Default input size
33    pub input_size: Option<String>,
34    /// Default spacing scale unit
35    pub spacing_unit: Option<u8>,
36    /// Default border radius
37    pub border_radius: Option<String>,
38    /// Whether to apply transitions globally
39    pub enable_transitions: bool,
40}
41
42impl Config {
43    /// Create a new config with defaults
44    pub fn new() -> Self {
45        Self {
46            enable_transitions: true,
47            ..Default::default()
48        }
49    }
50
51    /// Set default button size
52    pub fn with_button_size(mut self, size: impl Into<String>) -> Self {
53        self.button_size = Some(size.into());
54        self
55    }
56
57    /// Set default button variant
58    pub fn with_button_variant(mut self, variant: impl Into<String>) -> Self {
59        self.button_variant = Some(variant.into());
60        self
61    }
62
63    /// Set default card padding
64    pub fn with_card_padding(mut self, padding: impl Into<String>) -> Self {
65        self.card_padding = Some(padding.into());
66        self
67    }
68
69    /// Set default input size
70    pub fn with_input_size(mut self, size: impl Into<String>) -> Self {
71        self.input_size = Some(size.into());
72        self
73    }
74
75    /// Set default spacing unit
76    pub fn with_spacing_unit(mut self, unit: u8) -> Self {
77        self.spacing_unit = Some(unit);
78        self
79    }
80
81    /// Set default border radius
82    pub fn with_border_radius(mut self, radius: impl Into<String>) -> Self {
83        self.border_radius = Some(radius.into());
84        self
85    }
86
87    /// Enable/disable transitions globally
88    pub fn with_transitions(mut self, enabled: bool) -> Self {
89        self.enable_transitions = enabled;
90        self
91    }
92}
93
94/// Global configuration singleton
95static GLOBAL_CONFIG: OnceLock<Mutex<Config>> = OnceLock::new();
96
97/// Initialize and get the global configuration
98pub fn global_config() -> std::sync::MutexGuard<'static, Config> {
99    GLOBAL_CONFIG
100        .get_or_init(|| Mutex::new(Config::new()))
101        .lock()
102        .expect("Config mutex poisoned")
103}
104
105/// Set the global configuration
106pub fn set_global_config(config: Config) {
107    let mut global = global_config();
108    *global = config;
109}
110
111/// Component configuration builder
112///
113/// Provides a fluent API for configuring global component defaults
114pub struct ComponentConfig;
115
116impl ComponentConfig {
117    /// Start building configuration
118    pub fn builder() -> ConfigBuilder {
119        ConfigBuilder::new()
120    }
121
122    /// Reset to default configuration
123    pub fn reset() {
124        set_global_config(Config::new());
125    }
126}
127
128/// Configuration builder with fluent API
129#[derive(Clone, Debug, Default)]
130pub struct ConfigBuilder {
131    config: Config,
132}
133
134impl ConfigBuilder {
135    /// Create a new config builder
136    pub fn new() -> Self {
137        Self {
138            config: Config::new(),
139        }
140    }
141
142    /// Build and apply the configuration
143    pub fn build(self) {
144        set_global_config(self.config);
145    }
146
147    /// Set default button size
148    pub fn button_size(mut self, size: impl Into<String>) -> Self {
149        self.config.button_size = Some(size.into());
150        self
151    }
152
153    /// Set default button variant
154    pub fn button_variant(mut self, variant: impl Into<String>) -> Self {
155        self.config.button_variant = Some(variant.into());
156        self
157    }
158
159    /// Set default card padding
160    pub fn card_padding(mut self, padding: impl Into<String>) -> Self {
161        self.config.card_padding = Some(padding.into());
162        self
163    }
164
165    /// Set default input size
166    pub fn input_size(mut self, size: impl Into<String>) -> Self {
167        self.config.input_size = Some(size.into());
168        self
169    }
170
171    /// Set default spacing unit
172    pub fn spacing_unit(mut self, unit: u8) -> Self {
173        self.config.spacing_unit = Some(unit);
174        self
175    }
176
177    /// Set default border radius
178    pub fn border_radius(mut self, radius: impl Into<String>) -> Self {
179        self.config.border_radius = Some(radius.into());
180        self
181    }
182
183    /// Enable/disable transitions
184    pub fn transitions(mut self, enabled: bool) -> Self {
185        self.config.enable_transitions = enabled;
186        self
187    }
188}
189
190/// Trait for components that can use global config
191pub trait ConfigurableComponent {
192    /// Get the component type name
193    fn component_type() -> &'static str;
194
195    /// Apply global defaults to props
196    fn apply_defaults(props: &mut Self);
197}
198
199/// Helper macro to get config value or default
200#[macro_export]
201macro_rules! config_or_default {
202    ($config_field:expr, $default:expr) => {
203        $config_field
204            .as_ref()
205            .map(|s| s.as_str())
206            .unwrap_or($default)
207    };
208}