use super::*;
use indexmap::IndexMap;
use paste::paste;
use std::{borrow::Cow, fmt};
#[derive(Default, PartialEq, Debug, Clone)]
pub struct Style {
values: IndexMap<Cow<'static, str>, String>,
}
impl fmt::Display for Style {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.values
.iter()
.map(|(k, v)| format!("{}: {};", k, v))
.collect::<String>()
.fmt(f)
}
}
macro_rules! setter_functions {
( @more_fns $prop_ty:ident and ) => {
paste! {
pub fn [<and_ $prop_ty:snake>](mut self, val: impl FnOnce($prop_ty) -> $prop_ty) -> Self
where
$prop_ty: Default + StyleUpdater,
{
self = val($prop_ty::default()).update_style(self);
self
}
}
};
( $( $prop_ty:ident $( +$ext:ident )? $(,)? )+ ) => {
$(
paste! {
pub fn [<$prop_ty:snake>](mut self, val: impl Into<$prop_ty>) -> Self
where
$prop_ty: StyleUpdater,
{
self = val.into().update_style(self);
self
}
pub fn [<try_ $prop_ty:snake>](self, val: Option<impl Into<$prop_ty>>) -> Self {
if let Some(val) = val {
self.[<$prop_ty:snake>](val)
} else {
self
}
}
}
$( setter_functions!(@more_fns $prop_ty $ext); )?
)+
}
}
impl Style {
pub fn new() -> Self {
Self::default()
}
pub fn to_css(&self) -> Option<String> {
self.values
.iter()
.fold(Option::None, |mut css, (key, value)| {
*css.get_or_insert(String::default()) += &format!("{}: {};", key, value);
css
})
}
pub fn insert(mut self, key: impl Into<Cow<'static, str>>, value: impl ToString) -> Self {
self.values.insert(key.into(), value.to_string());
self
}
pub fn try_insert(
self,
key: impl Into<Cow<'static, str>>,
value: Option<impl ToString>,
) -> Self {
if let Some(val) = value {
self.insert(key, val)
} else {
self
}
}
pub fn merge(mut self, other: impl StyleUpdater) -> Self {
self = other.update_style(self);
self
}
pub fn try_merge(self, other: Option<impl StyleUpdater>) -> Self {
if let Some(other) = other {
self.merge(other)
} else {
self
}
}
setter_functions! {
Opacity,
Gap,
AlignContent,
AlignItems,
JustifyContent,
JustifySelf,
AlignSelf,
FlexWrap,
FlexBasis,
FlexDirection,
FlexOrder,
FlexGrow,
FlexShrink,
Display,
Visibility,
Cursor,
Background +and,
Border +and,
Margin +and,
Padding +and,
Size +and,
Transition +and,
BoxShadow +and,
Position +and,
Text +and,
Font +and,
}
}
pub trait StyleUpdater {
fn update_style(self, style: Style) -> Style;
}
impl StyleUpdater for Style {
fn update_style(self, mut style: Style) -> Style {
style.values.extend(self.values);
style
}
}
pub fn style() -> Style {
Style::default()
}