1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
//! # Theming
//!
//! Freya has built-in support for Theming.
//!
//! > ⚠️ Currently, extending the base theme is not supported.
//!
//! ### Accessing the current theme
//! You can access the whole current theme via the `use_get_theme` hook.
//!
//! ```rust, no_run
//! fn app(cx: Scope) -> Element {
//! render!(
//! ThemeProvider {
//! Component { }
//! }
//! )
//! }
//!
//! #[allow(non_snake_case)]
//! fn Component(cx: Scope) -> Element {
//! let theme = use_get_theme(cx);
//!
//! let button_theme = &theme.button;
//!
//! render!(
//! rect {
//! background: "{button_theme.background}",
//! }
//! )
//! }
//! ```
//!
//! ## Custom default theme
//! By default, the selected theme is `LIGHT_THEME`. You can use the alternative, `DARK_THEME`.
//!
//! ```rust, no_run
//! fn app(cx: Scope) -> Element {
//! render!(
//! ThemeProvider {
//! theme: LIGHT_THEME,
//! Component { }
//! }
//! )
//! }
//!
//! #[allow(non_snake_case)]
//! fn Component(cx: Scope) -> Element {
//! let theme = use_get_theme(cx);
//!
//! let button_theme = &theme.button;
//!
//! render!(
//! rect {
//! background: "{button_theme.background}",
//! }
//! )
//! }
//! ```
//!
//! ## Change theme
//! Changing the selected theme at runtime is possible by using the `use_theme` hook.
//!
//! ```rust, no_run
//! fn app(cx: Scope) -> Element {
//! render!(
//! ThemeProvider {
//! Component { }
//! }
//! )
//! }
//!
//! #[allow(non_snake_case)]
//! fn Component(cx: Scope) -> Element {
//! let theme = use_theme(cx);
//!
//! let onclick = |_| {
//! *theme.write() = LIGHT_THEME;
//! };
//!
//! render!(
//! Button {
//! onclick: onclick,
//! label {
//! "Use Light theme"
//! }
//! }
//! )
//! }
//! ```
//!
//! ## Change theme for an individual component
//!
//! Most built-in components have their own theme "override."
//! You can specify which values to override like this:
//!
//! ```rust,no_run
//! fn app(cx: Scope) -> Element {
//! render! {
//! Button {
//! theme: ButtonThemeWith {
//! background: Some("blue").into(),
//! font_theme: FontThemeWith {
//! Some("white").into(),
//! ..Default::default()
//! },
//! ..Default::default()
//! },
//! label { "I'm blue now" }
//! }
//! }
//! }
//! ```
//!
//! We need to use a different "type" of theme.
//! In the "ThemeWith" structs, each field is optional, so that the component knows what to override and
//! what to keep.
//! Additionally, we need to also spread `..Default::default`, to make all the other fields `None`.
//!
//! To make this less verbose, you can use the `theme_with!` macro:
//!
//! ```rust,no_run
//! fn app(cx: Scope) -> Element {
//! render! {
//! Button {
//! theme: theme_with!(ButtonTheme {
//! background: "blue".into(),
//! font_theme: theme_with!(FontTheme {
//! "white".into(),
//! }),
//! }),
//! label { "I'm blue now" }
//! }
//! }
//! }
//! ```
//!
//! >️ ⚠️ The comma after the last field in the `theme_with!` macro is required.
//! As you can see, it removes the need for the "With" suffix, because that's already in the macro name.
//! More importantly, though, it wraps each file in a `Some`, and adds the spread.
//!
//!
//! ## Custom theme
//!
//! Themes can be built from scratch or extended from others, like here with `LIGHT_THEME`:
//!
//! ```rust, no_run
//!
//! const CUSTOM_THEME: Theme = Theme {
//! button: ButtonTheme {
//! background: Cow::Borrowed("rgb(230, 0, 0)"),
//! hover_background: Cow::Borrowed("rgb(150, 0, 0)"),
//! font_theme: FontTheme {
//! color: Cow::Borrowed("white"),
//! },
//! ..LIGHT_THEME.button
//! },
//! ..LIGHT_THEME
//! };
//!
//! fn app(cx: Scope) -> Element {
//! render!(
//! ThemeProvider {
//! theme: CUSTOM_THEME,
//! rect {
//! width: "100%",
//! height: "100%",
//! Button {
//! label {
//! "Report"
//! }
//! }
//! }
//! }
//! )
//! }
//! ```