From 873935a171c86723874e881465d91cfba267f223 Mon Sep 17 00:00:00 2001 From: Cecile Tonglet Date: Sun, 4 Oct 2020 16:50:52 +0200 Subject: [PATCH 001/105] Initial commit Forked at: 7e6d6c43f0aa98d78ae34654d49e1cf84d252cce Parent branch: yewstack/master From d8c480c1df86757f5df06f878175f94bffd47ca9 Mon Sep 17 00:00:00 2001 From: Cecile Tonglet Date: Sun, 4 Oct 2020 16:54:50 +0200 Subject: [PATCH 002/105] Add feature flag for now --- yew-macro/Cargo.toml | 1 + yew-macro/src/html_tree/html_tag/tag_attributes.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/yew-macro/Cargo.toml b/yew-macro/Cargo.toml index 651de15889b..eb43ba6b69e 100644 --- a/yew-macro/Cargo.toml +++ b/yew-macro/Cargo.toml @@ -32,3 +32,4 @@ yew = { path = "../yew" } [features] doc_test = [] std_web = [] +class_macro = [] diff --git a/yew-macro/src/html_tree/html_tag/tag_attributes.rs b/yew-macro/src/html_tree/html_tag/tag_attributes.rs index 6ecc2f91081..3fb77a312d0 100644 --- a/yew-macro/src/html_tree/html_tag/tag_attributes.rs +++ b/yew-macro/src/html_tree/html_tag/tag_attributes.rs @@ -325,8 +325,11 @@ impl Parse for TagAttributes { } } + #[cfg(not(feature = "class_macro"))] let classes = Self::remove_attr_nonoptional(&mut attributes, "class")? .map(|a| Self::map_classes(a.value)); + #[cfg(feature = "class_macro")] + let classes = None; let value = Self::remove_attr(&mut attributes, "value"); let kind = Self::remove_attr(&mut attributes, "type"); let checked = Self::remove_attr_nonoptional(&mut attributes, "checked")?.map(|v| v.value); From 3234c4113b0f330239f2a5ab499098bd2f8b0a4b Mon Sep 17 00:00:00 2001 From: Cecile Tonglet Date: Sun, 4 Oct 2020 17:05:14 +0200 Subject: [PATCH 003/105] WIP Forked at: 7e6d6c43f0aa98d78ae34654d49e1cf84d252cce Parent branch: yewstack/master --- yew/Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/yew/Cargo.toml b/yew/Cargo.toml index a76af002c89..d40cf6a829f 100644 --- a/yew/Cargo.toml +++ b/yew/Cargo.toml @@ -141,6 +141,9 @@ agent = ["bincode"] yaml = ["serde_yaml"] msgpack = ["rmp-serde"] cbor = ["serde_cbor"] +class_macro = [ + "yew-macro/class_macro" +] [package.metadata.docs.rs] features = ["yaml", "cbor", "toml", "msgpack", "doc_test"] From 46c09787977ddf68571a4fb0ab9c9a5c66aced9c Mon Sep 17 00:00:00 2001 From: Cecile Tonglet Date: Sun, 4 Oct 2020 18:48:00 +0200 Subject: [PATCH 004/105] Add macro classes!() Forked at: 7e6d6c43f0aa98d78ae34654d49e1cf84d252cce Parent branch: yewstack/master --- yew-macro/src/html_classes/mod.rs | 52 ++++++++++++ yew-macro/src/html_tree/html_tag/mod.rs | 2 +- .../src/html_tree/html_tag/tag_attributes.rs | 2 +- yew-macro/src/html_tree/mod.rs | 2 +- yew-macro/src/lib.rs | 8 ++ yew/src/lib.rs | 2 +- yew/src/virtual_dom/vtag.rs | 85 +++++++++++-------- 7 files changed, 113 insertions(+), 40 deletions(-) create mode 100644 yew-macro/src/html_classes/mod.rs diff --git a/yew-macro/src/html_classes/mod.rs b/yew-macro/src/html_classes/mod.rs new file mode 100644 index 00000000000..dfe2711ee17 --- /dev/null +++ b/yew-macro/src/html_classes/mod.rs @@ -0,0 +1,52 @@ +use proc_macro2::{TokenStream}; +use quote::{quote, ToTokens}; +use syn::parse::{Parse, ParseStream, Result}; +// TODO: should probably move those classes to module html_classes +use crate::html_tree::html_tag::tag_attributes::{ClassesForm, TagAttributes}; +use crate::stringify::Stringify; + +/// Same as HtmlRoot but always returns a VNode. +pub struct HtmlClasses(ClassesForm); +impl Parse for HtmlClasses { + fn parse(input: ParseStream) -> Result { + Ok(HtmlClasses(TagAttributes::map_classes(input.parse()?))) + } +} +impl ToTokens for HtmlClasses { + fn to_tokens(&self, tokens: &mut TokenStream) { + let new_tokens = match &self.0 { + ClassesForm::Tuple(classes) => { + let n = classes.len(); + Some(quote! { + let mut __yew_classes = ::yew::virtual_dom::Classes::with_capacity(#n); + #(__yew_classes.push(#classes);)* + __yew_classes + }) + } + ClassesForm::Single(classes) => match classes.try_into_lit() { + Some(lit) => { + if lit.value().is_empty() { + None + } else { + let sr = lit.stringify(); + Some(quote! { + #sr + }) + } + } + None => { + Some(quote! { + ::std::convert::Into::<::yew::virtual_dom::Classes>::into(#classes) + }) + } + }, + }; + + if let Some(new_tokens) = new_tokens { + tokens.extend(quote! {{ + #[allow(clippy::useless_conversion, unused_braces)] + #new_tokens + }}); + } + } +} diff --git a/yew-macro/src/html_tree/html_tag/mod.rs b/yew-macro/src/html_tree/html_tag/mod.rs index 97e6154e9f4..bc3bfe8bee1 100644 --- a/yew-macro/src/html_tree/html_tag/mod.rs +++ b/yew-macro/src/html_tree/html_tag/mod.rs @@ -1,4 +1,4 @@ -mod tag_attributes; +pub(crate) mod tag_attributes; use super::{ HtmlChildrenTree, HtmlDashedName, HtmlProp as TagAttribute, HtmlPropSuffix as TagSuffix, diff --git a/yew-macro/src/html_tree/html_tag/tag_attributes.rs b/yew-macro/src/html_tree/html_tag/tag_attributes.rs index 3fb77a312d0..b3d873f19e5 100644 --- a/yew-macro/src/html_tree/html_tag/tag_attributes.rs +++ b/yew-macro/src/html_tree/html_tag/tag_attributes.rs @@ -263,7 +263,7 @@ impl TagAttributes { } } - fn map_classes(class_expr: Expr) -> ClassesForm { + pub(crate) fn map_classes(class_expr: Expr) -> ClassesForm { match class_expr { Expr::Tuple(ExprTuple { elems, .. }) => ClassesForm::Tuple(elems.into_iter().collect()), expr => ClassesForm::Single(Box::new(expr)), diff --git a/yew-macro/src/html_tree/mod.rs b/yew-macro/src/html_tree/mod.rs index f118fc2e682..b12df043d3b 100644 --- a/yew-macro/src/html_tree/mod.rs +++ b/yew-macro/src/html_tree/mod.rs @@ -5,7 +5,7 @@ mod html_iterable; mod html_list; mod html_node; mod html_prop; -mod html_tag; +pub(crate) mod html_tag; use crate::PeekValue; use html_block::HtmlBlock; diff --git a/yew-macro/src/lib.rs b/yew-macro/src/lib.rs index efd74022572..f2e4d63fd07 100644 --- a/yew-macro/src/lib.rs +++ b/yew-macro/src/lib.rs @@ -58,10 +58,12 @@ #![recursion_limit = "128"] mod derive_props; +mod html_classes; mod html_tree; mod stringify; use derive_props::DerivePropsInput; +use html_classes::HtmlClasses; use html_tree::{HtmlRoot, HtmlRootVNode}; use proc_macro::TokenStream; use quote::{quote, ToTokens}; @@ -103,3 +105,9 @@ pub fn html(input: TokenStream) -> TokenStream { let root = parse_macro_input!(input as HtmlRootVNode); TokenStream::from(quote! {#root}) } + +#[proc_macro] +pub fn classes(input: TokenStream) -> TokenStream { + let root = parse_macro_input!(input as HtmlClasses); + TokenStream::from(quote! {#root}) +} diff --git a/yew/src/lib.rs b/yew/src/lib.rs index d4d65664f70..d68f54d8e27 100644 --- a/yew/src/lib.rs +++ b/yew/src/lib.rs @@ -106,7 +106,7 @@ extern crate self as yew; /// [`Html`]: ./html/type.Html.html /// [`html_nested!`]: ./macro.html_nested.html /// [Yew Docs]: https://yew.rs/docs/en/concepts/html/ -pub use yew_macro::html; +pub use yew_macro::{html, classes}; /// This macro is similar to [`html!`], but preserves the component type instead /// of wrapping it in [`Html`]. diff --git a/yew/src/virtual_dom/vtag.rs b/yew/src/virtual_dom/vtag.rs index 0b3c95ef948..4c86155710f 100644 --- a/yew/src/virtual_dom/vtag.rs +++ b/yew/src/virtual_dom/vtag.rs @@ -561,7 +561,7 @@ where #[cfg(test)] mod tests { use super::*; - use crate::html; + use crate::{html, classes}; use std::any::TypeId; #[cfg(feature = "std_web")] use stdweb::web::{document, IElement}; @@ -682,18 +682,21 @@ mod tests { #[test] fn classes_from_local_variables() { + let classes = classes!(("class-1", "class-2")); let a = html! { -
+
}; let class_2 = "class-2"; + let classes = classes!(("class-1", class_2)); let b = html! { -
+
}; let class_2_fmt = format!("class-{}", 2); + let classes = classes!(("class-1", class_2_fmt)); let c = html! { -
+
}; assert_eq!(a, b); @@ -720,8 +723,9 @@ mod tests { #[test] fn supports_multiple_non_unique_classes_tuple() { + let classes = classes!(("class-1", "class-1 class-2")); let a = html! { -
+
}; if let VNode::VTag(vtag) = a { @@ -735,12 +739,15 @@ mod tests { #[test] fn supports_multiple_classes_string() { + // TODO double parenthesis + let classes = classes!(("class-1 class-2 class-3")); let a = html! { -
+
}; + let classes = classes!(("class-2 class-3 class-1")); let b = html! { -
+
}; assert_ne!(a, b); @@ -756,9 +763,9 @@ mod tests { #[test] fn supports_multiple_classes_slice() { - let classes = ["class-1", "class-2"]; + let classes = classes!(&["class-1", "class-2"][..]); let a = html! { -
+
}; if let VNode::VTag(vtag) = a { @@ -772,9 +779,9 @@ mod tests { #[test] fn supports_multiple_classes_one_value_slice() { - let classes = ["class-1 class-2", "class-1"]; + let classes = classes!(&["class-1 class-2", "class-1"][..]); let a = html! { -
+
}; if let VNode::VTag(vtag) = a { @@ -790,6 +797,7 @@ mod tests { fn supports_multiple_classes_vec() { let mut classes = vec!["class-1"]; classes.push("class-2"); + let classes = classes!(classes); let a = html! {
}; @@ -806,6 +814,7 @@ mod tests { #[test] fn supports_multiple_classes_one_value_vec() { let classes = vec!["class-1 class-2", "class-1"]; + let classes = classes!(classes); let a = html! {
}; @@ -821,11 +830,11 @@ mod tests { #[test] fn filter_empty_string_classes() { - let a = html! {
}; - let b = html! {
}; + let a = html! {
}; + let b = html! {
}; let c = html! {
}; let d_arr = [""]; - let d = html! {
}; + let d = html! {
}; macro_rules! has_class { ($vtag:expr) => { @@ -908,7 +917,7 @@ mod tests { #[test] fn keeps_order_of_classes() { let a = html! { -
+
}; if let VNode::VTag(vtag) = a { @@ -1077,39 +1086,39 @@ mod tests { fn tuple_different_types() { // check if tuples containing different types are compiling assert_class( - html! {
}, + html! {
}, "class-1 class-2 class-3 class-4", ); assert_class( - html! {
}, + html! {
}, "class-1 class-2 class-3 class-4", ); // check different string references let str = "some-class"; let string = str.to_string(); let string_ref = &string; - assert_class(html! {

}, "some-class"); - assert_class(html! {

}, "some-class"); - assert_class(html! {

}, "some-class"); - assert_class(html! {

}, "some-class"); - assert_class(html! {

}, "some-class"); - assert_class(html! {

}, "some-class"); - assert_class(html! {

}, "some-class"); - assert_class(html! {

}, "some-class"); - assert_class(html! {

}, "some-class"); + assert_class(html! {

}, "some-class"); + assert_class(html! {

}, "some-class"); + assert_class(html! {

}, "some-class"); + assert_class(html! {

}, "some-class"); + assert_class(html! {

}, "some-class"); + assert_class(html! {

}, "some-class"); + assert_class(html! {

}, "some-class"); + assert_class(html! {

}, "some-class"); + assert_class(html! {

}, "some-class"); // check with None - assert_class(html! {

::None /> }, ""); - assert_class(html! {

::None /> }, ""); + assert_class(html! {

::None) /> }, ""); + assert_class(html! {

::None) /> }, ""); // check with variables let some: Option<&'static str> = Some("some"); let none: Option<&'static str> = None; - assert_class(html! {

}, "some"); - assert_class(html! {

}, ""); + assert_class(html! {

}, "some"); + assert_class(html! {

}, ""); // check with variables of different type let some: Option = Some(false); let none: Option = None; - assert_class(html! {

}, "false"); - assert_class(html! {

}, ""); + assert_class(html! {

}, "false"); + assert_class(html! {

}, ""); } #[test] @@ -1122,7 +1131,8 @@ mod tests { #[cfg(feature = "web_sys")] document().body().unwrap().append_child(&parent).unwrap(); - let mut elem = html! {

}; + let classes = classes!(("class-1", "class-2", "class-3")); + let mut elem = html! {
}; elem.apply(&scope, &parent, NodeRef::default(), None); let vtag = if let VNode::VTag(vtag) = elem { @@ -1143,7 +1153,8 @@ mod tests { ); let ancestor = vtag; - let elem = html! {
}; + let classes = classes!(("class-3", "class-2", "class-1")); + let elem = html! {
}; let mut vtag = if let VNode::VTag(vtag) = elem { vtag } else { @@ -1178,7 +1189,8 @@ mod tests { #[cfg(feature = "web_sys")] document().body().unwrap().append_child(&parent).unwrap(); - let mut elem = html! {
}; + let classes = classes!(("class-1", "class-3")); + let mut elem = html! {
}; elem.apply(&scope, &parent, NodeRef::default(), None); let vtag = if let VNode::VTag(vtag) = elem { @@ -1199,7 +1211,8 @@ mod tests { ); let ancestor = vtag; - let elem = html! {
}; + let classes = classes!(("class-1", "class-2", "class-3")); + let elem = html! {
}; let mut vtag = if let VNode::VTag(vtag) = elem { vtag } else { From d25c6d6988cbc92d728f550eb8d1966424c7c0d2 Mon Sep 17 00:00:00 2001 From: Cecile Tonglet Date: Sun, 4 Oct 2020 18:52:09 +0200 Subject: [PATCH 005/105] WIP Forked at: 7e6d6c43f0aa98d78ae34654d49e1cf84d252cce Parent branch: yewstack/master --- yew-macro/src/html_classes/mod.rs | 10 ++++------ yew/src/virtual_dom/vtag.rs | 7 ++++++- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/yew-macro/src/html_classes/mod.rs b/yew-macro/src/html_classes/mod.rs index dfe2711ee17..180f405c18f 100644 --- a/yew-macro/src/html_classes/mod.rs +++ b/yew-macro/src/html_classes/mod.rs @@ -42,11 +42,9 @@ impl ToTokens for HtmlClasses { }, }; - if let Some(new_tokens) = new_tokens { - tokens.extend(quote! {{ - #[allow(clippy::useless_conversion, unused_braces)] - #new_tokens - }}); - } + tokens.extend(quote! {{ + #[allow(clippy::useless_conversion, unused_braces)] + #new_tokens + }}); } } diff --git a/yew/src/virtual_dom/vtag.rs b/yew/src/virtual_dom/vtag.rs index 4c86155710f..96cfcc56b60 100644 --- a/yew/src/virtual_dom/vtag.rs +++ b/yew/src/virtual_dom/vtag.rs @@ -843,24 +843,28 @@ mod tests { } if let VNode::VTag(vtag) = a { + // TODO: empty classes should leave class unset assert!(!has_class!(vtag)); } else { panic!("vtag expected"); } if let VNode::VTag(vtag) = b { + // TODO: empty classes should leave class unset assert!(!has_class!(vtag)); } else { panic!("vtag expected"); } if let VNode::VTag(vtag) = c { + // TODO: empty classes should leave class unset assert!(!has_class!(vtag)); } else { panic!("vtag expected"); } if let VNode::VTag(vtag) = d { + // TODO: empty classes should leave class unset assert!(!vtag.attributes.iter().any(|(k, _)| k == "class")); } else { panic!("vtag expected"); @@ -1041,7 +1045,8 @@ mod tests { #[cfg(feature = "web_sys")] document().body().unwrap().append_child(&parent).unwrap(); - let mut elem = html! {
}; + // TODO: should accept only a literal + let mut elem = html! {
}; elem.apply(&scope, &parent, NodeRef::default(), None); let vtag = assert_vtag(&mut elem); // test if the className has not been set From cb54f9ad30942b9ddf8f88b5b000139993e8ccdc Mon Sep 17 00:00:00 2001 From: Cecile Tonglet Date: Sun, 4 Oct 2020 20:10:24 +0200 Subject: [PATCH 006/105] rustfmt --- yew-macro/src/html_classes/mod.rs | 46 +++----- .../src/html_tree/html_tag/tag_attributes.rs | 3 +- yew/src/lib.rs | 2 +- yew/src/virtual_dom/vtag.rs | 107 ++++++++---------- 4 files changed, 64 insertions(+), 94 deletions(-) diff --git a/yew-macro/src/html_classes/mod.rs b/yew-macro/src/html_classes/mod.rs index 180f405c18f..d411b9e015c 100644 --- a/yew-macro/src/html_classes/mod.rs +++ b/yew-macro/src/html_classes/mod.rs @@ -1,45 +1,27 @@ use proc_macro2::{TokenStream}; use quote::{quote, ToTokens}; use syn::parse::{Parse, ParseStream, Result}; -// TODO: should probably move those classes to module html_classes -use crate::html_tree::html_tag::tag_attributes::{ClassesForm, TagAttributes}; -use crate::stringify::Stringify; +use syn::punctuated::Punctuated; +use syn::token::Comma; +use syn::Expr; + +/// List of HTML classes. +pub struct HtmlClasses(Punctuated::); -/// Same as HtmlRoot but always returns a VNode. -pub struct HtmlClasses(ClassesForm); impl Parse for HtmlClasses { fn parse(input: ParseStream) -> Result { - Ok(HtmlClasses(TagAttributes::map_classes(input.parse()?))) + Ok(HtmlClasses(Punctuated::::parse_terminated(input)?)) } } + impl ToTokens for HtmlClasses { fn to_tokens(&self, tokens: &mut TokenStream) { - let new_tokens = match &self.0 { - ClassesForm::Tuple(classes) => { - let n = classes.len(); - Some(quote! { - let mut __yew_classes = ::yew::virtual_dom::Classes::with_capacity(#n); - #(__yew_classes.push(#classes);)* - __yew_classes - }) - } - ClassesForm::Single(classes) => match classes.try_into_lit() { - Some(lit) => { - if lit.value().is_empty() { - None - } else { - let sr = lit.stringify(); - Some(quote! { - #sr - }) - } - } - None => { - Some(quote! { - ::std::convert::Into::<::yew::virtual_dom::Classes>::into(#classes) - }) - } - }, + let n = self.0.len(); + let classes = self.0.iter(); + let new_tokens = quote! { + let mut __yew_classes = ::yew::virtual_dom::Classes::with_capacity(#n); + #(__yew_classes.push(#classes);)* + __yew_classes }; tokens.extend(quote! {{ diff --git a/yew-macro/src/html_tree/html_tag/tag_attributes.rs b/yew-macro/src/html_tree/html_tag/tag_attributes.rs index b3d873f19e5..aad7cda5be3 100644 --- a/yew-macro/src/html_tree/html_tag/tag_attributes.rs +++ b/yew-macro/src/html_tree/html_tag/tag_attributes.rs @@ -263,7 +263,8 @@ impl TagAttributes { } } - pub(crate) fn map_classes(class_expr: Expr) -> ClassesForm { + #[cfg(not(feature = "class_macro"))] + fn map_classes(class_expr: Expr) -> ClassesForm { match class_expr { Expr::Tuple(ExprTuple { elems, .. }) => ClassesForm::Tuple(elems.into_iter().collect()), expr => ClassesForm::Single(Box::new(expr)), diff --git a/yew/src/lib.rs b/yew/src/lib.rs index d68f54d8e27..363a440cc99 100644 --- a/yew/src/lib.rs +++ b/yew/src/lib.rs @@ -106,7 +106,7 @@ extern crate self as yew; /// [`Html`]: ./html/type.Html.html /// [`html_nested!`]: ./macro.html_nested.html /// [Yew Docs]: https://yew.rs/docs/en/concepts/html/ -pub use yew_macro::{html, classes}; +pub use yew_macro::{classes, html}; /// This macro is similar to [`html!`], but preserves the component type instead /// of wrapping it in [`Html`]. diff --git a/yew/src/virtual_dom/vtag.rs b/yew/src/virtual_dom/vtag.rs index 96cfcc56b60..410166f1140 100644 --- a/yew/src/virtual_dom/vtag.rs +++ b/yew/src/virtual_dom/vtag.rs @@ -561,7 +561,7 @@ where #[cfg(test)] mod tests { use super::*; - use crate::{html, classes}; + use crate::{classes, html}; use std::any::TypeId; #[cfg(feature = "std_web")] use stdweb::web::{document, IElement}; @@ -682,21 +682,18 @@ mod tests { #[test] fn classes_from_local_variables() { - let classes = classes!(("class-1", "class-2")); let a = html! { -
+
}; let class_2 = "class-2"; - let classes = classes!(("class-1", class_2)); let b = html! { -
+
}; let class_2_fmt = format!("class-{}", 2); - let classes = classes!(("class-1", class_2_fmt)); let c = html! { -
+
}; assert_eq!(a, b); @@ -723,9 +720,8 @@ mod tests { #[test] fn supports_multiple_non_unique_classes_tuple() { - let classes = classes!(("class-1", "class-1 class-2")); let a = html! { -
+
}; if let VNode::VTag(vtag) = a { @@ -739,15 +735,11 @@ mod tests { #[test] fn supports_multiple_classes_string() { - // TODO double parenthesis - let classes = classes!(("class-1 class-2 class-3")); let a = html! { -
+
}; - - let classes = classes!(("class-2 class-3 class-1")); let b = html! { -
+
}; assert_ne!(a, b); @@ -831,41 +823,40 @@ mod tests { #[test] fn filter_empty_string_classes() { let a = html! {
}; - let b = html! {
}; + let b = html! {
}; let c = html! {
}; let d_arr = [""]; let d = html! {
}; - macro_rules! has_class { + macro_rules! get_class { ($vtag:expr) => { - $vtag.attributes.iter().any(|(k, _)| k == "class") + $vtag + .attributes + .iter() + .find_map(|(k, v)| if k == "class" { Some(v) } else { None }) }; } if let VNode::VTag(vtag) = a { - // TODO: empty classes should leave class unset - assert!(!has_class!(vtag)); + assert_eq!(get_class!(vtag), Some("")); } else { panic!("vtag expected"); } if let VNode::VTag(vtag) = b { - // TODO: empty classes should leave class unset - assert!(!has_class!(vtag)); + assert_eq!(get_class!(vtag), Some("")); } else { panic!("vtag expected"); } if let VNode::VTag(vtag) = c { - // TODO: empty classes should leave class unset - assert!(!has_class!(vtag)); + assert_eq!(get_class!(vtag), Some("")); } else { panic!("vtag expected"); } if let VNode::VTag(vtag) = d { - // TODO: empty classes should leave class unset - assert!(!vtag.attributes.iter().any(|(k, _)| k == "class")); + assert_eq!(get_class!(vtag), Some("")); } else { panic!("vtag expected"); } @@ -1035,24 +1026,6 @@ mod tests { html! { }; } - #[test] - fn it_does_not_set_empty_class_name() { - let scope = test_scope(); - let parent = document().create_element("div").unwrap(); - - #[cfg(feature = "std_web")] - document().body().unwrap().append_child(&parent); - #[cfg(feature = "web_sys")] - document().body().unwrap().append_child(&parent).unwrap(); - - // TODO: should accept only a literal - let mut elem = html! {
}; - elem.apply(&scope, &parent, NodeRef::default(), None); - let vtag = assert_vtag(&mut elem); - // test if the className has not been set - assert!(!vtag.reference.as_ref().unwrap().has_attribute("class")); - } - #[test] fn it_does_not_set_missing_class_name() { let scope = test_scope(); @@ -1091,11 +1064,11 @@ mod tests { fn tuple_different_types() { // check if tuples containing different types are compiling assert_class( - html! {
}, + html! {
}, "class-1 class-2 class-3 class-4", ); assert_class( - html! {
}, + html! {
}, "class-1 class-2 class-3 class-4", ); // check different string references @@ -1107,10 +1080,22 @@ mod tests { assert_class(html! {

}, "some-class"); assert_class(html! {

}, "some-class"); assert_class(html! {

}, "some-class"); - assert_class(html! {

}, "some-class"); - assert_class(html! {

}, "some-class"); - assert_class(html! {

}, "some-class"); - assert_class(html! {

}, "some-class"); + assert_class( + html! {

}, + "some-class", + ); + assert_class( + html! {

}, + "some-class", + ); + assert_class( + html! {

}, + "some-class", + ); + assert_class( + html! {

}, + "some-class", + ); // check with None assert_class(html! {

::None) /> }, ""); assert_class(html! {

::None) /> }, ""); @@ -1122,8 +1107,14 @@ mod tests { // check with variables of different type let some: Option = Some(false); let none: Option = None; - assert_class(html! {

}, "false"); - assert_class(html! {

}, ""); + assert_class( + html! {

}, + "false", + ); + assert_class( + html! {

}, + "", + ); } #[test] @@ -1136,8 +1127,7 @@ mod tests { #[cfg(feature = "web_sys")] document().body().unwrap().append_child(&parent).unwrap(); - let classes = classes!(("class-1", "class-2", "class-3")); - let mut elem = html! {

}; + let mut elem = html! {
}; elem.apply(&scope, &parent, NodeRef::default(), None); let vtag = if let VNode::VTag(vtag) = elem { @@ -1158,8 +1148,7 @@ mod tests { ); let ancestor = vtag; - let classes = classes!(("class-3", "class-2", "class-1")); - let elem = html! {
}; + let elem = html! {
}; let mut vtag = if let VNode::VTag(vtag) = elem { vtag } else { @@ -1194,8 +1183,7 @@ mod tests { #[cfg(feature = "web_sys")] document().body().unwrap().append_child(&parent).unwrap(); - let classes = classes!(("class-1", "class-3")); - let mut elem = html! {
}; + let mut elem = html! {
}; elem.apply(&scope, &parent, NodeRef::default(), None); let vtag = if let VNode::VTag(vtag) = elem { @@ -1216,8 +1204,7 @@ mod tests { ); let ancestor = vtag; - let classes = classes!(("class-1", "class-2", "class-3")); - let elem = html! {
}; + let elem = html! {
}; let mut vtag = if let VNode::VTag(vtag) = elem { vtag } else { From 8957f256e6d226bd9136f552e70b160066843554 Mon Sep 17 00:00:00 2001 From: Cecile Tonglet Date: Sun, 4 Oct 2020 20:11:08 +0200 Subject: [PATCH 007/105] WIP Forked at: 7e6d6c43f0aa98d78ae34654d49e1cf84d252cce Parent branch: yewstack/master --- yew/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yew/Cargo.toml b/yew/Cargo.toml index d40cf6a829f..62e092f2449 100644 --- a/yew/Cargo.toml +++ b/yew/Cargo.toml @@ -122,7 +122,7 @@ rmp-serde = "0.14.0" bincode = "1" [features] -default = ["services", "agent", "web_sys"] +default = ["services", "agent", "web_sys", "class_macro"] std_web = ["stdweb", "yew-macro/std_web"] web_sys = [ "console_error_panic_hook", From 8f2c68477539bc3f57980213cda618d6a50f1a62 Mon Sep 17 00:00:00 2001 From: Cecile Tonglet Date: Sun, 4 Oct 2020 20:12:25 +0200 Subject: [PATCH 008/105] CLEANUP Forked at: 7e6d6c43f0aa98d78ae34654d49e1cf84d252cce Parent branch: yewstack/master --- yew-macro/src/html_tree/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yew-macro/src/html_tree/mod.rs b/yew-macro/src/html_tree/mod.rs index b12df043d3b..f118fc2e682 100644 --- a/yew-macro/src/html_tree/mod.rs +++ b/yew-macro/src/html_tree/mod.rs @@ -5,7 +5,7 @@ mod html_iterable; mod html_list; mod html_node; mod html_prop; -pub(crate) mod html_tag; +mod html_tag; use crate::PeekValue; use html_block::HtmlBlock; From 5f0e4878d9f2cc0e31d93c278282ec59c9ef114c Mon Sep 17 00:00:00 2001 From: Cecile Tonglet Date: Sun, 4 Oct 2020 20:18:53 +0200 Subject: [PATCH 009/105] CLEANUP Forked at: 7e6d6c43f0aa98d78ae34654d49e1cf84d252cce Parent branch: yewstack/master --- yew-macro/src/html_tree/html_tag/tag_attributes.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/yew-macro/src/html_tree/html_tag/tag_attributes.rs b/yew-macro/src/html_tree/html_tag/tag_attributes.rs index aad7cda5be3..3fb77a312d0 100644 --- a/yew-macro/src/html_tree/html_tag/tag_attributes.rs +++ b/yew-macro/src/html_tree/html_tag/tag_attributes.rs @@ -263,7 +263,6 @@ impl TagAttributes { } } - #[cfg(not(feature = "class_macro"))] fn map_classes(class_expr: Expr) -> ClassesForm { match class_expr { Expr::Tuple(ExprTuple { elems, .. }) => ClassesForm::Tuple(elems.into_iter().collect()), From 81c60aca2dc3354fd4f3dc8cffe61ffa50e6341c Mon Sep 17 00:00:00 2001 From: Cecile Tonglet Date: Sun, 4 Oct 2020 20:38:49 +0200 Subject: [PATCH 010/105] CLEANUP Forked at: 7e6d6c43f0aa98d78ae34654d49e1cf84d252cce Parent branch: yewstack/master --- yew-macro/Cargo.toml | 1 - yew-macro/src/html_tree/html_tag/mod.rs | 45 +------------------ .../src/html_tree/html_tag/tag_attributes.rs | 21 +-------- yew/Cargo.toml | 5 +-- 4 files changed, 3 insertions(+), 69 deletions(-) diff --git a/yew-macro/Cargo.toml b/yew-macro/Cargo.toml index eb43ba6b69e..651de15889b 100644 --- a/yew-macro/Cargo.toml +++ b/yew-macro/Cargo.toml @@ -32,4 +32,3 @@ yew = { path = "../yew" } [features] doc_test = [] std_web = [] -class_macro = [] diff --git a/yew-macro/src/html_tree/html_tag/mod.rs b/yew-macro/src/html_tree/html_tag/mod.rs index bc3bfe8bee1..ec07e1ae2fa 100644 --- a/yew-macro/src/html_tree/html_tag/mod.rs +++ b/yew-macro/src/html_tree/html_tag/mod.rs @@ -12,7 +12,7 @@ use syn::buffer::Cursor; use syn::parse::{Parse, ParseStream, Result as ParseResult}; use syn::spanned::Spanned; use syn::{Block, Ident, Token}; -use tag_attributes::{ClassesForm, TagAttributes}; +use tag_attributes::TagAttributes; pub struct HtmlTag { tag_name: TagName, @@ -121,7 +121,6 @@ impl ToTokens for HtmlTag { }; let TagAttributes { - classes, attributes, booleans, kind, @@ -232,47 +231,6 @@ impl ToTokens for HtmlTag { Some(tokens) }; - let push_classes = match classes { - Some(ClassesForm::Tuple(classes)) => { - let n = classes.len(); - let sr = stringify::stringify_at_runtime(quote! { __yew_classes }); - Some(quote! { - let mut __yew_classes = ::yew::virtual_dom::Classes::with_capacity(#n); - #(__yew_classes.push(#classes);)* - - if !__yew_classes.is_empty() { - #vtag.__macro_push_attribute("class", #sr); - } else { - #vtag.__macro_push_attribute_placeholder("class"); - }; - }) - } - Some(ClassesForm::Single(classes)) => match classes.try_into_lit() { - Some(lit) => { - if lit.value().is_empty() { - None - } else { - let sr = lit.stringify(); - Some(quote! { - #vtag.__macro_push_attribute("class", #sr); - }) - } - } - None => { - let sr = stringify::stringify_at_runtime(quote! { __yew_classes }); - Some(quote! { - let __yew_classes = ::std::convert::Into::<::yew::virtual_dom::Classes>::into(#classes); - if !__yew_classes.is_empty() { - #vtag.__macro_push_attribute("class", #sr); - } else { - #vtag.__macro_push_attribute_placeholder("class"); - }; - }) - } - }, - None => None, - }; - let add_listeners = if listeners.is_empty() { None } else if listeners.iter().any(|attr| attr.question_mark.is_some()) { @@ -374,7 +332,6 @@ impl ToTokens for HtmlTag { #set_attributes #push_booleans - #push_classes #add_listeners #add_children diff --git a/yew-macro/src/html_tree/html_tag/tag_attributes.rs b/yew-macro/src/html_tree/html_tag/tag_attributes.rs index 3fb77a312d0..57db0480c8b 100644 --- a/yew-macro/src/html_tree/html_tag/tag_attributes.rs +++ b/yew-macro/src/html_tree/html_tag/tag_attributes.rs @@ -4,12 +4,11 @@ use lazy_static::lazy_static; use std::collections::HashSet; use std::iter::FromIterator; use syn::parse::{Parse, ParseStream, Result as ParseResult}; -use syn::{Expr, ExprTuple}; +use syn::Expr; pub struct TagAttributes { pub attributes: Vec, pub listeners: Vec, - pub classes: Option, pub booleans: Vec, pub value: Option, pub kind: Option, @@ -18,11 +17,6 @@ pub struct TagAttributes { pub key: Option, } -pub enum ClassesForm { - Tuple(Vec), - Single(Box), -} - lazy_static! { static ref BOOLEAN_SET: HashSet<&'static str> = { HashSet::from_iter( @@ -262,13 +256,6 @@ impl TagAttributes { None => Ok(None), } } - - fn map_classes(class_expr: Expr) -> ClassesForm { - match class_expr { - Expr::Tuple(ExprTuple { elems, .. }) => ClassesForm::Tuple(elems.into_iter().collect()), - expr => ClassesForm::Single(Box::new(expr)), - } - } } impl Parse for TagAttributes { @@ -325,11 +312,6 @@ impl Parse for TagAttributes { } } - #[cfg(not(feature = "class_macro"))] - let classes = Self::remove_attr_nonoptional(&mut attributes, "class")? - .map(|a| Self::map_classes(a.value)); - #[cfg(feature = "class_macro")] - let classes = None; let value = Self::remove_attr(&mut attributes, "value"); let kind = Self::remove_attr(&mut attributes, "type"); let checked = Self::remove_attr_nonoptional(&mut attributes, "checked")?.map(|v| v.value); @@ -338,7 +320,6 @@ impl Parse for TagAttributes { Ok(Self { attributes, - classes, listeners, checked, booleans, diff --git a/yew/Cargo.toml b/yew/Cargo.toml index 62e092f2449..a76af002c89 100644 --- a/yew/Cargo.toml +++ b/yew/Cargo.toml @@ -122,7 +122,7 @@ rmp-serde = "0.14.0" bincode = "1" [features] -default = ["services", "agent", "web_sys", "class_macro"] +default = ["services", "agent", "web_sys"] std_web = ["stdweb", "yew-macro/std_web"] web_sys = [ "console_error_panic_hook", @@ -141,9 +141,6 @@ agent = ["bincode"] yaml = ["serde_yaml"] msgpack = ["rmp-serde"] cbor = ["serde_cbor"] -class_macro = [ - "yew-macro/class_macro" -] [package.metadata.docs.rs] features = ["yaml", "cbor", "toml", "msgpack", "doc_test"] From 3ca20a8ab3cccba8d0e13c0d21af0704127965fa Mon Sep 17 00:00:00 2001 From: Cecile Tonglet Date: Sun, 4 Oct 2020 20:39:38 +0200 Subject: [PATCH 011/105] rustfmt --- yew-macro/src/html_classes/mod.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/yew-macro/src/html_classes/mod.rs b/yew-macro/src/html_classes/mod.rs index d411b9e015c..86b1452515b 100644 --- a/yew-macro/src/html_classes/mod.rs +++ b/yew-macro/src/html_classes/mod.rs @@ -1,4 +1,4 @@ -use proc_macro2::{TokenStream}; +use proc_macro2::TokenStream; use quote::{quote, ToTokens}; use syn::parse::{Parse, ParseStream, Result}; use syn::punctuated::Punctuated; @@ -6,11 +6,13 @@ use syn::token::Comma; use syn::Expr; /// List of HTML classes. -pub struct HtmlClasses(Punctuated::); +pub struct HtmlClasses(Punctuated); impl Parse for HtmlClasses { fn parse(input: ParseStream) -> Result { - Ok(HtmlClasses(Punctuated::::parse_terminated(input)?)) + Ok(HtmlClasses(Punctuated::::parse_terminated( + input, + )?)) } } From 57f734a61882744e3978c16e1ad1765e5fa56814 Mon Sep 17 00:00:00 2001 From: Cecile Tonglet Date: Sun, 4 Oct 2020 20:41:23 +0200 Subject: [PATCH 012/105] WIP Forked at: 7e6d6c43f0aa98d78ae34654d49e1cf84d252cce Parent branch: yewstack/master --- examples/crm/src/add_client.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/examples/crm/src/add_client.rs b/examples/crm/src/add_client.rs index fcd55671edf..ed2683092cf 100644 --- a/examples/crm/src/add_client.rs +++ b/examples/crm/src/add_client.rs @@ -1,5 +1,7 @@ use crate::Client; -use yew::{html, Callback, Component, ComponentLink, Html, InputData, Properties, ShouldRender}; +use yew::{ + classes, html, Callback, Component, ComponentLink, Html, InputData, Properties, ShouldRender, +}; #[derive(Debug)] pub enum Msg { @@ -74,19 +76,19 @@ impl Component for AddClientForm { <>