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
// ------------- CSSValue -------------

/// CSS property value.
///
/// # Example
///
/// ```rust,no_run
///style! {
///    "padding" => px(12),
///    "background-color" => if disabled { CSSValue::Ignored } else { "green".into() },
///    "display" => CSSValue::Some("block".to_string()),
///}
/// ```
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum CSSValue {
    /// The whole CSS property is ignored (i.e. not rendered).
    Ignored,
    /// Rendered CSS property value.
    Some(String),
}

impl<T: ToString> From<T> for CSSValue {
    fn from(value: T) -> Self {
        CSSValue::Some(value.to_string())
    }
}

// ----------- ToCSSValue impls ------------

// impl ToCSSValue for CSSValue
#[doc(hidden)]
pub trait ToCSSValueForCSSValue {
    fn to_css_value(self) -> CSSValue;
}

impl ToCSSValueForCSSValue for CSSValue {
    fn to_css_value(self) -> CSSValue {
        self
    }
}

// impl<T: ToString> ToCSSValue for T
#[doc(hidden)]
pub trait ToCSSValueForToString {
    fn to_css_value(&self) -> CSSValue;
}

impl<T: ToString> ToCSSValueForToString for T {
    fn to_css_value(&self) -> CSSValue {
        CSSValue::Some(self.to_string())
    }
}

// impl<T: ToString> ToCSSValue for Option<T>
#[doc(hidden)]
pub trait ToCSSValueForOptionToString {
    fn to_css_value(&self) -> CSSValue;
}

impl<T: ToString> ToCSSValueForOptionToString for Option<T> {
    fn to_css_value(&self) -> CSSValue {
        self.as_ref()
            .map_or(CSSValue::Ignored, |t| CSSValue::Some(t.to_string()))
    }
}

// ------------- AtValue -------------

/// Attribute value.
///
/// # Example
///
/// ```rust,no_run
///attrs! {
///    At::Disabled => false.as_at_value(),  // same as `=> AtValue::Ignored`
///    At::Value => model.message,
///    At::AutoFocus => AtValue::None,
///}
/// ```
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum AtValue {
    /// The whole attribute is ignored (i.e. not rendered).
    Ignored,
    /// Attribute value is not used (i.e. rendered as empty string).
    None,
    /// Rendered attribute value.
    Some(String),
}

impl<T: ToString> From<T> for AtValue {
    fn from(value: T) -> Self {
        AtValue::Some(value.to_string())
    }
}

// `&` because `attrs!` macro automatically adds prefix `&` before values for more ergonomic API
// (otherwise it would fail when you use for example a Model's property in View functions as `AtValue`)
impl From<&AtValue> for AtValue {
    fn from(value: &AtValue) -> Self {
        value.clone()
    }
}

// -- AsAtValue --

pub trait AsAtValue {
    fn as_at_value(&self) -> AtValue;
}

impl AsAtValue for bool {
    fn as_at_value(&self) -> AtValue {
        match self {
            true => AtValue::None,
            false => AtValue::Ignored,
        }
    }
}