diff --git a/examples/node_refs/src/main.rs b/examples/node_refs/src/main.rs
index f39bc399058..abba846e1dd 100644
--- a/examples/node_refs/src/main.rs
+++ b/examples/node_refs/src/main.rs
@@ -79,7 +79,7 @@ impl Component for App {
diff --git a/packages/yew-macro/src/html_tree/html_component.rs b/packages/yew-macro/src/html_tree/html_component.rs
index 015267acef3..3ec0ac4ba2c 100644
--- a/packages/yew-macro/src/html_tree/html_component.rs
+++ b/packages/yew-macro/src/html_tree/html_component.rs
@@ -106,32 +106,17 @@ impl ToTokens for HtmlComponent {
Some(quote! { ::yew::html::ChildrenRenderer::new(#children) })
};
let build_props = props.build_properties_tokens(&props_ty, children_renderer);
-
- let special_props = props.special();
- let node_ref = if let Some(node_ref) = &special_props.node_ref {
- let value = &node_ref.value;
- quote! { #value }
- } else {
- quote! { <::yew::html::NodeRef as ::std::default::Default>::default() }
- };
-
- let key = if let Some(key) = &special_props.key {
- let value = &key.value;
- quote_spanned! {value.span().resolved_at(Span::call_site())=>
- #[allow(clippy::useless_conversion)]
- Some(::std::convert::Into::<::yew::virtual_dom::Key>::into(#value))
- }
- } else {
- quote! { ::std::option::Option::None }
- };
- let use_close_tag = if let Some(close) = close {
- let close_ty = &close.ty;
- quote_spanned! {close_ty.span()=>
- let _ = |_:#close_ty| {};
- }
- } else {
- Default::default()
- };
+ let node_ref = props.special().wrap_node_ref_attr();
+ let key = props.special().wrap_key_attr();
+ let use_close_tag = close
+ .as_ref()
+ .map(|close| {
+ let close_ty = &close.ty;
+ quote_spanned! {close_ty.span()=>
+ let _ = |_:#close_ty| {};
+ }
+ })
+ .unwrap_or_default();
tokens.extend(quote_spanned! {ty_span=>
{
diff --git a/packages/yew-macro/src/html_tree/html_element.rs b/packages/yew-macro/src/html_tree/html_element.rs
index 8b981a10d1c..db4dfae77fb 100644
--- a/packages/yew-macro/src/html_tree/html_element.rs
+++ b/packages/yew-macro/src/html_tree/html_element.rs
@@ -112,37 +112,17 @@ impl ToTokens for HtmlElement {
booleans,
value,
checked,
- node_ref,
- key,
listeners,
+ special,
} = &props;
// attributes with special treatment
- let node_ref = node_ref
- .as_ref()
- .map(|attr| {
- let value = &attr.value;
- quote_spanned! {value.span().resolved_at(Span::call_site())=>
- ::yew::html::IntoPropValue::<::yew::html::NodeRef>
- ::into_prop_value(#value)
- }
- })
- .unwrap_or(quote! { ::std::default::Default::default() });
- let key = key
- .as_ref()
- .map(|attr| {
- let value = attr.value.optimize_literals();
- quote_spanned! {value.span().resolved_at(Span::call_site())=>
- ::std::option::Option::Some(
- ::std::convert::Into::<::yew::virtual_dom::Key>::into(#value)
- )
- }
- })
- .unwrap_or(quote! { ::std::option::Option::None });
+ let node_ref = special.wrap_node_ref_attr();
+ let key = special.wrap_key_attr();
let value = value
.as_ref()
- .map(wrap_attr_prop)
+ .map(|prop| wrap_attr_value(prop.value.optimize_literals()))
.unwrap_or(quote! { ::std::option::Option::None });
let checked = checked
.as_ref()
@@ -262,14 +242,7 @@ impl ToTokens for HtmlElement {
.collect::>();
try_into_static(&attrs).unwrap_or_else(|| {
let keys = attrs.iter().map(|(k, _)| quote! { #k });
- let values = attrs.iter().map(|(_, v)| {
- quote_spanned! {v.span()=>
- ::yew::html::IntoPropValue::<
- ::std::option::Option::<::yew::virtual_dom::AttrValue>
- >
- ::into_prop_value(#v)
- }
- });
+ let values = attrs.iter().map(|(_, v)| wrap_attr_value(v));
quote! {
::yew::virtual_dom::Attributes::Dynamic{
keys: &[#(#keys),*],
@@ -473,8 +446,7 @@ impl ToTokens for HtmlElement {
}
}
-fn wrap_attr_prop(prop: &Prop) -> TokenStream {
- let value = prop.value.optimize_literals();
+fn wrap_attr_value(value: T) -> TokenStream {
quote_spanned! {value.span()=>
::yew::html::IntoPropValue::<
::std::option::Option<
diff --git a/packages/yew-macro/src/props/element.rs b/packages/yew-macro/src/props/element.rs
index f80af1c2adb..50bc57bf201 100644
--- a/packages/yew-macro/src/props/element.rs
+++ b/packages/yew-macro/src/props/element.rs
@@ -26,8 +26,7 @@ pub struct ElementProps {
pub booleans: Vec,
pub value: Option,
pub checked: Option,
- pub node_ref: Option,
- pub key: Option,
+ pub special: SpecialProps,
}
impl Parse for ElementProps {
@@ -48,8 +47,7 @@ impl Parse for ElementProps {
.map(|prop| ClassesForm::from_expr(prop.value));
let value = props.pop("value");
let checked = props.pop("checked");
-
- let SpecialProps { node_ref, key } = props.special;
+ let special = props.special;
Ok(Self {
attributes: props.prop_list.into_vec(),
@@ -58,8 +56,7 @@ impl Parse for ElementProps {
checked,
booleans: booleans.into_vec(),
value,
- node_ref,
- key,
+ special,
})
}
}
diff --git a/packages/yew-macro/src/props/prop.rs b/packages/yew-macro/src/props/prop.rs
index 6fb4d7522fd..8dbd568efc2 100644
--- a/packages/yew-macro/src/props/prop.rs
+++ b/packages/yew-macro/src/props/prop.rs
@@ -2,13 +2,16 @@ use std::cmp::Ordering;
use std::convert::TryFrom;
use std::ops::{Deref, DerefMut};
-use proc_macro2::{Spacing, TokenTree};
+use proc_macro2::{Spacing, Span, TokenStream, TokenTree};
+use quote::{quote, quote_spanned};
use syn::parse::{Parse, ParseBuffer, ParseStream};
+use syn::spanned::Spanned;
use syn::token::Brace;
use syn::{braced, Block, Expr, ExprBlock, ExprPath, ExprRange, Stmt, Token};
use super::CHILDREN_LABEL;
use crate::html_tree::HtmlDashedName;
+use crate::stringify::Stringify;
pub struct Prop {
pub label: HtmlDashedName,
@@ -325,6 +328,33 @@ impl SpecialProps {
pub fn check_all(&self, f: impl FnMut(&Prop) -> syn::Result<()>) -> syn::Result<()> {
crate::join_errors(self.iter().map(f).filter_map(Result::err))
}
+
+ pub fn wrap_node_ref_attr(&self) -> TokenStream {
+ self.node_ref
+ .as_ref()
+ .map(|attr| {
+ let value = &attr.value;
+ quote_spanned! {value.span().resolved_at(Span::call_site())=>
+ ::yew::html::IntoPropValue::<::yew::html::NodeRef>
+ ::into_prop_value(#value)
+ }
+ })
+ .unwrap_or(quote! { ::std::default::Default::default() })
+ }
+
+ pub fn wrap_key_attr(&self) -> TokenStream {
+ self.key
+ .as_ref()
+ .map(|attr| {
+ let value = attr.value.optimize_literals();
+ quote_spanned! {value.span().resolved_at(Span::call_site())=>
+ ::std::option::Option::Some(
+ ::std::convert::Into::<::yew::virtual_dom::Key>::into(#value)
+ )
+ }
+ })
+ .unwrap_or(quote! { ::std::option::Option::None })
+ }
}
pub struct Props {
diff --git a/packages/yew-macro/tests/html_macro/component-fail.stderr b/packages/yew-macro/tests/html_macro/component-fail.stderr
index 3774f0a0182..2e068c63b21 100644
--- a/packages/yew-macro/tests/html_macro/component-fail.stderr
+++ b/packages/yew-macro/tests/html_macro/component-fail.stderr
@@ -386,11 +386,14 @@ note: required by a bound in `ChildPropertiesBuilder::string`
| ------ required by a bound in this
= note: this error originates in the derive macro `Properties` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0308]: mismatched types
+error[E0277]: the trait bound `(): IntoPropValue` is not satisfied
--> tests/html_macro/component-fail.rs:80:31
|
80 | html! { };
- | ^^ expected struct `NodeRef`, found `()`
+ | ^^
+ | |
+ | the trait `IntoPropValue` is not implemented for `()`
+ | required by a bound introduced by this call
error[E0277]: the trait bound `u32: IntoPropValue` is not satisfied
--> tests/html_macro/component-fail.rs:82:24
diff --git a/packages/yew-macro/tests/html_macro/component-pass.rs b/packages/yew-macro/tests/html_macro/component-pass.rs
index 707c08f5f7c..bc703f9a5f3 100644
--- a/packages/yew-macro/tests/html_macro/component-pass.rs
+++ b/packages/yew-macro/tests/html_macro/component-pass.rs
@@ -55,6 +55,7 @@ impl ::yew::Component for Container {
fn create(_ctx: &::yew::Context) -> Self {
::std::unimplemented!()
}
+
fn view(&self, _ctx: &::yew::Context) -> ::yew::Html {
::std::unimplemented!()
}
@@ -116,6 +117,7 @@ impl ::yew::Component for Child {
fn create(_ctx: &::yew::Context) -> Self {
::std::unimplemented!()
}
+
fn view(&self, _ctx: &::yew::Context) -> ::yew::Html {
::std::unimplemented!()
}
@@ -129,6 +131,7 @@ impl ::yew::Component for AltChild {
fn create(_ctx: &::yew::Context) -> Self {
::std::unimplemented!()
}
+
fn view(&self, _ctx: &::yew::Context) -> ::yew::Html {
::std::unimplemented!()
}
@@ -151,14 +154,14 @@ impl ::yew::Component for ChildContainer {
fn create(_ctx: &::yew::Context) -> Self {
::std::unimplemented!()
}
+
fn view(&self, _ctx: &::yew::Context) -> ::yew::Html {
::std::unimplemented!()
}
}
mod scoped {
- pub use super::Child;
- pub use super::Container;
+ pub use super::{Child, Container};
}
fn compile_pass() {
@@ -181,6 +184,7 @@ fn compile_pass() {
+ ::Properties as ::std::default::Default>::default() />
::Properties as ::std::default::Default>::default() />
>
};
diff --git a/packages/yew-macro/tests/html_macro/html-element-pass.rs b/packages/yew-macro/tests/html_macro/html-element-pass.rs
index c85989c96c9..3729c3ec362 100644
--- a/packages/yew-macro/tests/html_macro/html-element-pass.rs
+++ b/packages/yew-macro/tests/html_macro/html-element-pass.rs
@@ -51,6 +51,7 @@ fn compile_pass() {
::yew::html! {