Skip to content

Accept more types in style! macro #273

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Nov 3, 2019
11 changes: 11 additions & 0 deletions examples/server_integration/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 24 additions & 0 deletions src/dom_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1430,4 +1430,28 @@ pub mod tests {

assert_eq!(expected, get_node_html(&node));
}

/// Test that `style!` macro accept types that have `to_css_value()` function
#[wasm_bindgen_test]
pub fn to_css_value_in_style() {
let display: &str = "flex";
let direction: String = "column".to_string();
let order: Option<u32> = None;
let gap: Option<&str> = Some("8px");

let style = style![
St::Display => display,
St::FlexDirection => direction,
St::Order => order,
St::Gap => gap,
];

let mut result_style = Style::empty();
result_style.add(St::Display, CSSValue::Some("flex".into()));
result_style.add(St::FlexDirection, CSSValue::Some("column".into()));
result_style.add(St::Order, CSSValue::Ignored);
result_style.add(St::Gap, CSSValue::Some("8px".into()));

assert_eq!(style, result_style)
}
}
41 changes: 36 additions & 5 deletions src/dom_types/values.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,42 @@ impl<T: ToString> From<T> for CSSValue {
}
}

// `&` because `style!` 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 `CSSValue`)
impl From<&CSSValue> for CSSValue {
fn from(value: &CSSValue) -> Self {
value.clone()
// ----------- 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()))
}
}

Expand Down
11 changes: 7 additions & 4 deletions src/shortcuts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,17 +243,20 @@ macro_rules! id {
};
}

// reference for workaround used by style! macro
// (https://github.com/dtolnay/case-studies/blob/master/autoref-specialization/README.md)
/// Provide a shortcut for creating styles.
#[macro_export]
macro_rules! style {
{ $($key:expr => $value:expr $(;)?$(,)?)* } => {
{
#[allow(unused_imports)]
use $crate::dom_types::values::{
ToCSSValueForCSSValue, ToCSSValueForOptionToString, ToCSSValueForToString
};
let mut vals = IndexMap::new();
$(
// We can handle arguments of multiple types by using this:
// Strings, &strs, bools, numbers etc.
// And cases like `CSSValue::Ignored`.
vals.insert($key.into(), (&$value).into());
vals.insert($key.into(), ($value).to_css_value());
)*
$crate::dom_types::Style::new(vals)
}
Expand Down
4 changes: 1 addition & 3 deletions src/vdom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,9 +228,7 @@ impl<Ms, Mdl, ElC: View<Ms> + 'static, GMs: 'static> App<Ms, Mdl, ElC, GMs> {
/// an initial render.
pub fn run(self) -> Self {
// Bootstrap the virtual DOM.
self.data
.main_el_vdom
.replace(Some(self.bootstrap_vdom()));
self.data.main_el_vdom.replace(Some(self.bootstrap_vdom()));

// Update the state on page load, based
// on the starting URL. Must be set up on the server as well.
Expand Down