Skip to main content

freya_components/theming/
hooks.rs

1use freya_core::{
2    prelude::{
3        Readable,
4        State,
5        WritableUtils,
6        provide_context,
7        provide_context_for_scope_id,
8        try_consume_context,
9        use_consume,
10        use_hook,
11    },
12    scope_id::ScopeId,
13};
14
15use crate::theming::component_themes::Theme;
16
17/// Provides a custom [`Theme`].
18/// If a [`Theme`] context already exists, it reuses it instead of creating a new one.
19pub fn use_init_theme(theme_cb: impl FnOnce() -> Theme) -> State<Theme> {
20    use_hook(|| {
21        if let Some(mut existing) = try_consume_context::<State<Theme>>() {
22            existing.set(theme_cb());
23            existing
24        } else {
25            let state = State::create(theme_cb());
26            provide_context(state);
27            state
28        }
29    })
30}
31
32/// Provides a custom [`Theme`] at the root scope.
33/// If a [`Theme`] context already exists at the root, it reuses it instead of creating a new one.
34pub fn use_init_root_theme(theme_cb: impl FnOnce() -> Theme) -> State<Theme> {
35    use_hook(|| {
36        if let Some(existing) = try_consume_context::<State<Theme>>() {
37            existing
38        } else {
39            let state = State::create_in_scope(theme_cb(), ScopeId::ROOT);
40            provide_context_for_scope_id(state, ScopeId::ROOT);
41            state
42        }
43    })
44}
45
46/// Subscribe to [`Theme`] changes.
47pub fn use_theme() -> State<Theme> {
48    use_consume::<State<Theme>>()
49}
50
51/// Subscribe to [`Theme`] changes, default theme will be used if there is no provided [`Theme`].
52///
53/// Primarily used by built-in components that have no control of whether they will inherit a [`Theme`] or not.
54pub fn get_theme_or_default() -> Readable<Theme> {
55    try_consume_context::<State<Theme>>()
56        .map(|v| v.into())
57        .unwrap_or_else(|| Theme::default().into())
58}
59
60/// Indicates what type of surface to use.
61#[derive(Clone, Copy, PartialEq, Debug, Default)]
62pub enum SurfaceThemeIndicator {
63    #[default]
64    Primary,
65    Opposite,
66}
67
68/// Provide a [SurfaceThemeIndicator] down to the components.
69pub fn use_init_surface_theme_indicator(theme: impl FnOnce() -> SurfaceThemeIndicator) {
70    use_hook(|| provide_context(theme()))
71}
72
73/// Get the inherited [SurfaceThemeIndicator].
74pub fn use_surface_theme_indicator() -> SurfaceThemeIndicator {
75    use_hook(|| try_consume_context().unwrap_or_default())
76}