css_style/
box_shadow.rs

1use crate::{unit::*, Color, Style, StyleUpdater};
2use derive_rich::Rich;
3use std::fmt;
4
5/// ```
6/// use css_style::{prelude::*, color, unit::em};
7/// use palette::rgb::Rgb;
8///
9/// style()
10///     // for single shadow
11///     .and_box_shadow(|conf| {
12///         conf.x(em(0.4))
13///             .y(em(-0.8))
14///             // rgb value f32 based, we can pass u32 hex value too e.g. 0xFFFFFFFF
15///             .color((0.5, 0.1, 0.1))
16///             // or we can use HTML colors
17///             .color(color::named::BLUEVIOLET)
18///             // shadow blur radius
19///             .blur(em(1.0))
20///             // spread radius
21///             .spread(em(2.0))
22///             // inset shadow
23///             .inset()
24///     })
25///     // for multiple shadows
26///     .and_box_shadow(|conf| {
27///         conf
28///             .push(|conf| {
29///                 conf.x(em(1.0))
30///                     .y(em(2.0))
31///                     .color(color::named::DIMGRAY)
32///             })
33///             .push(|conf| {
34///                 conf.x(em(-2.0))
35///                     .y(em(-4.0))
36///                     .color(color::named::RED)
37///             })
38///     });
39/// ```
40#[derive(Clone, Debug, PartialEq, From, Display)]
41pub enum BoxShadow {
42    One(ShadowValue),
43    #[display(
44        fmt = "{}",
45        "_0.iter().map(|s| s.to_string()).collect::<Vec<_>>().join(\", \")"
46    )]
47    Multiple(Vec<ShadowValue>),
48    #[display(fmt = "initial")]
49    Initial,
50    #[display(fmt = "inherit")]
51    Inherit,
52    #[display(fmt = "none")]
53    None,
54    #[display(fmt = "unset")]
55    Unset,
56}
57
58impl Default for BoxShadow {
59    fn default() -> Self {
60        BoxShadow::Multiple(vec![])
61    }
62}
63
64impl StyleUpdater for BoxShadow {
65    fn update_style(self, style: Style) -> Style {
66        style.insert("box-shadow", self)
67    }
68}
69
70impl BoxShadow {
71    fn shadow(mut self, conf: impl FnOnce(ShadowValue) -> ShadowValue) -> Self {
72        self = match self {
73            Self::One(shadow) => Self::One(conf(shadow)),
74            Self::Multiple(shadows) => {
75                Self::One(conf(shadows.into_iter().next().unwrap_or_default()))
76            }
77            _ => Self::One(conf(ShadowValue::default())),
78        };
79        self
80    }
81
82    pub fn new() -> Self {
83        BoxShadow::Multiple(vec![])
84    }
85
86    pub fn x(self, val: impl Into<Length>) -> Self {
87        self.shadow(|sh| sh.x(val))
88    }
89
90    pub fn y(self, val: impl Into<Length>) -> Self {
91        self.shadow(|sh| sh.y(val))
92    }
93
94    pub fn blur(self, val: impl Into<Length>) -> Self {
95        self.shadow(|sh| sh.blur(val))
96    }
97
98    pub fn try_blur(self, val: Option<impl Into<Length>>) -> Self {
99        self.shadow(|sh| sh.try_blur(val))
100    }
101
102    pub fn spread(self, val: impl Into<Length>) -> Self {
103        self.shadow(|sh| sh.spread(val))
104    }
105
106    pub fn try_spread(self, val: Option<impl Into<Length>>) -> Self {
107        self.shadow(|sh| sh.try_spread(val))
108    }
109
110    pub fn color(self, val: impl Into<Color>) -> Self {
111        self.shadow(|sh| sh.color(val))
112    }
113
114    pub fn try_color(self, val: Option<impl Into<Color>>) -> Self {
115        self.shadow(|sh| sh.try_color(val))
116    }
117
118    pub fn inset(self) -> Self {
119        self.shadow(|sh| sh.inset())
120    }
121
122    pub fn outset(self) -> Self {
123        self.shadow(|sh| sh.outset())
124    }
125
126    pub fn push(mut self, get_val: impl FnOnce(ShadowValue) -> ShadowValue) -> Self {
127        let val = get_val(ShadowValue::default());
128        self = match self {
129            Self::Multiple(mut vec) => {
130                vec.push(val);
131                Self::Multiple(vec)
132            }
133            _ => Self::Multiple(vec![val]),
134        };
135        self
136    }
137}
138
139#[derive(Rich, Clone, Debug, PartialEq)]
140pub struct ShadowValue {
141    #[rich(write)]
142    x: Length,
143    #[rich(write)]
144    y: Length,
145    #[rich(write, write(option))]
146    blur: Option<Length>,
147    #[rich(write, write(option))]
148    spread: Option<Length>,
149    #[rich(write, write(option))]
150    color: Option<Color>,
151    #[rich(value_fns = { inset = true, outset = false })]
152    inset: bool,
153}
154
155impl fmt::Display for ShadowValue {
156    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
157        if self.inset {
158            write!(f, "inset ")?;
159        }
160
161        write!(f, "{} {}", self.x, self.y)?;
162
163        match (self.blur.as_ref(), self.spread.as_ref()) {
164            (Some(blur), Some(spread)) => write!(f, " {} {}", blur, spread)?,
165            (Some(blur), None) => write!(f, " {}", blur)?,
166            // if there was no blur specified then use 0px
167            (None, Some(spread)) => write!(f, " {} {}", px(0), spread)?,
168            (None, None) => {}
169        };
170
171        if let Some(color) = self.color {
172            write!(f, " {}", color)?;
173        }
174
175        Ok(())
176    }
177}
178
179impl Default for ShadowValue {
180    fn default() -> Self {
181        Self {
182            x: px(0),
183            y: px(0),
184            blur: None,
185            spread: None,
186            color: None,
187            inset: false,
188        }
189    }
190}