adui_dioxus/components/
config_provider.rs

1use crate::theme::{Theme, ThemeProvider, ThemeTokens};
2use dioxus::prelude::*;
3
4/// Global size for components when they do not specify an explicit size.
5#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
6pub enum ComponentSize {
7    Small,
8    #[default]
9    Middle,
10    Large,
11}
12
13/// Simple locale flag for components that need basic language switching.
14#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
15pub enum Locale {
16    /// Simplified Chinese.
17    #[default]
18    ZhCN,
19    /// English (US).
20    EnUS,
21}
22
23/// Global configuration shared by components.
24///
25/// This is intentionally much smaller than Ant Design's ConfigProvider. We only
26/// keep fields that are immediately useful for the current component set.
27#[derive(Clone, Debug, PartialEq)]
28pub struct ConfigContextValue {
29    pub size: ComponentSize,
30    pub disabled: bool,
31    pub prefix_cls: String,
32    pub locale: Locale,
33}
34
35impl Default for ConfigContextValue {
36    fn default() -> Self {
37        Self {
38            size: ComponentSize::Middle,
39            disabled: false,
40            prefix_cls: "adui".to_string(),
41            locale: Locale::ZhCN,
42        }
43    }
44}
45
46/// Props for `ConfigProvider`.
47#[derive(Props, Clone, PartialEq)]
48pub struct ConfigProviderProps {
49    /// Global default size for components.
50    #[props(optional)]
51    pub size: Option<ComponentSize>,
52    /// Global disabled flag. When `true`, interactive components should treat
53    /// themselves as disabled unless explicitly overridden.
54    #[props(optional)]
55    pub disabled: Option<bool>,
56    /// Global CSS class name prefix. Defaults to `"adui"`.
57    #[props(optional)]
58    pub prefix_cls: Option<String>,
59    /// Global locale flag to control basic UI language for components that
60    /// integrate with date/time or other text-heavy features.
61    #[props(optional)]
62    pub locale: Option<Locale>,
63    /// Optional initial theme. If omitted, the current ThemeProvider behaviour
64    /// is preserved.
65    #[props(optional)]
66    pub theme: Option<Theme>,
67    pub children: Element,
68}
69
70/// Provide ConfigContext for descendant components. ConfigProvider wraps
71/// ThemeProvider so that size / disabled / prefix can live alongside tokens.
72#[component]
73pub fn ConfigProvider(props: ConfigProviderProps) -> Element {
74    let parent = try_use_context::<ConfigContextValue>().unwrap_or_default();
75
76    let value = ConfigContextValue {
77        size: props.size.unwrap_or(parent.size),
78        disabled: props.disabled.unwrap_or(parent.disabled),
79        prefix_cls: props.prefix_cls.clone().unwrap_or(parent.prefix_cls),
80        locale: props.locale.unwrap_or(parent.locale),
81    };
82
83    // We still rely on ThemeProvider for concrete tokens & CSS variables, so
84    // we forward the optional theme prop. If there is already a ThemeProvider
85    // above, it will simply override this one.
86    use_context_provider(|| value.clone());
87
88    rsx! {
89        ThemeProvider { theme: props.theme.clone(), {props.children} }
90    }
91}
92
93/// Hook for components to read global config.
94pub fn use_config() -> ConfigContextValue {
95    try_use_context::<ConfigContextValue>().unwrap_or_default()
96}
97
98/// Lightweight helper to compute control dimensions from global config and
99/// theme tokens. This does not live in the context to keep it testable and
100/// stateless.
101pub fn control_heights(config: &ConfigContextValue, tokens: &ThemeTokens) -> (f32, f32, f32) {
102    let base = tokens.control_height;
103    let small = tokens.control_height_small;
104    let large = tokens.control_height_large;
105    match config.size {
106        ComponentSize::Small => (small, small, base),
107        ComponentSize::Large => (large, large, base),
108        ComponentSize::Middle => (base, small, large),
109    }
110}