mirror of
https://github.com/yewstack/yew.git
synced 2025-12-08 21:26:25 +00:00
Remove ToHtml trait (#3453)
* remove ToHtml trait * re-add display impls * make Vec::clone expilit * fix doc * fix conflicting impls Into<Html> and Display can't be implemented on the same type * update docs * blanket impl won't work here * bring back `Vec<VNode>: IntoPropValue<VNode>` * macro tests * Revert "fix conflicting impls" This reverts commit 52f3c1fa8174489ba9cc783d708a49cc7b9c90a4. These impls are fine now * make examples compile * .clone() should be before .into() * Rc VList * Make use of ImplicitClone and AttrValue in example (There is more work to do but it's complicated so I will do it in another PR) * Impl ImplicitClone on VChild --------- Co-authored-by: Cecile Tonglet <cecile.tonglet@cecton.com>
This commit is contained in:
parent
7f45af3a66
commit
0eb167ac78
@ -2,6 +2,7 @@ use std::rc::Rc;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum_macros::{Display, EnumIter};
|
||||
use yew::html::IntoPropValue;
|
||||
use yew::prelude::*;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
@ -42,8 +43,8 @@ impl Filter {
|
||||
}
|
||||
}
|
||||
|
||||
impl ToHtml for Filter {
|
||||
fn to_html(&self) -> Html {
|
||||
impl IntoPropValue<Html> for Filter {
|
||||
fn into_prop_value(self) -> Html {
|
||||
html! {<>{self.to_string()}</>}
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ pub struct Props {
|
||||
#[prop_or_default]
|
||||
pub hide: bool,
|
||||
pub on_hover: Callback<Hovered>,
|
||||
pub name: String,
|
||||
pub name: AttrValue,
|
||||
#[prop_or_default]
|
||||
pub children: Children,
|
||||
}
|
||||
|
||||
@ -73,9 +73,8 @@ impl List {
|
||||
.filter(|c| !c.props.hide)
|
||||
.enumerate()
|
||||
.map(|(i, mut c)| {
|
||||
let mut props = (*c.props).clone();
|
||||
props.name = format!("#{} - {}", i + 1, props.name);
|
||||
c.props = Rc::new(props);
|
||||
let props = Rc::make_mut(&mut c.props);
|
||||
props.name = format!("#{} - {}", i + 1, props.name).into();
|
||||
c
|
||||
})
|
||||
.collect::<Html>()
|
||||
|
||||
@ -8,7 +8,7 @@ use std::fmt;
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
|
||||
use yew::html::{ImplicitClone, Scope};
|
||||
use yew::html::{ImplicitClone, IntoPropValue, Scope};
|
||||
use yew::prelude::*;
|
||||
|
||||
pub struct WeakComponentLink<COMP: Component>(Rc<RefCell<Option<Scope<COMP>>>>);
|
||||
@ -40,14 +40,16 @@ impl<COMP: Component> PartialEq for WeakComponentLink<COMP> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum Hovered {
|
||||
Header,
|
||||
Item(String),
|
||||
Item(AttrValue),
|
||||
List,
|
||||
None,
|
||||
}
|
||||
|
||||
impl ImplicitClone for Hovered {}
|
||||
|
||||
impl fmt::Display for Hovered {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
@ -63,8 +65,8 @@ impl fmt::Display for Hovered {
|
||||
}
|
||||
}
|
||||
|
||||
impl ToHtml for Hovered {
|
||||
fn to_html(&self) -> yew::Html {
|
||||
impl IntoPropValue<Html> for &Hovered {
|
||||
fn into_prop_value(self) -> Html {
|
||||
html! {<>{self.to_string()}</>}
|
||||
}
|
||||
}
|
||||
|
||||
@ -139,7 +139,7 @@ impl Component for App {
|
||||
{ &self.time }
|
||||
</div>
|
||||
<div id="messages">
|
||||
{ for self.messages.iter().map(|message| html! { <p>{ message }</p> }) }
|
||||
{ for self.messages.iter().map(|message| html! { <p>{ *message }</p> }) }
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
||||
@ -105,7 +105,7 @@ fn App() -> Html {
|
||||
.iter()
|
||||
.map(|message| {
|
||||
key += 1;
|
||||
html! { <p key={ key }>{ message }</p> }
|
||||
html! { <p key={ key }>{ *message }</p> }
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use strum_macros::{Display, EnumIter};
|
||||
use yew::html::IntoPropValue;
|
||||
use yew::prelude::*;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
@ -142,8 +143,8 @@ impl Filter {
|
||||
}
|
||||
}
|
||||
|
||||
impl ToHtml for Filter {
|
||||
fn to_html(&self) -> yew::Html {
|
||||
impl IntoPropValue<Html> for Filter {
|
||||
fn into_prop_value(self) -> yew::Html {
|
||||
html! { <>{self.to_string()}</> }
|
||||
}
|
||||
}
|
||||
|
||||
@ -463,16 +463,7 @@ error[E0277]: the trait bound `(): IntoPropValue<String>` is not satisfied
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: the following other types implement trait `IntoPropValue<T>`:
|
||||
<&'static [(K, V)] as IntoPropValue<implicit_clone::unsync::IMap<K, V>>>
|
||||
<&'static [T] as IntoPropValue<implicit_clone::unsync::IArray<T>>>
|
||||
<&'static str as IntoPropValue<Classes>>
|
||||
<&'static str as IntoPropValue<Option<String>>>
|
||||
<&'static str as IntoPropValue<Option<implicit_clone::unsync::IString>>>
|
||||
<&'static str as IntoPropValue<String>>
|
||||
<&'static str as IntoPropValue<implicit_clone::unsync::IString>>
|
||||
<&T as IntoPropValue<Option<T>>>
|
||||
and $N others
|
||||
= help: the trait `IntoPropValue<VNode>` is implemented for `()`
|
||||
note: required by a bound in `ChildPropertiesBuilder::string`
|
||||
--> tests/html_macro/component-fail.rs:4:17
|
||||
|
|
||||
@ -706,7 +697,9 @@ error[E0277]: the trait bound `yew::virtual_dom::VText: IntoPropValue<ChildrenRe
|
||||
117 | html! { <ChildContainer>{ "Not allowed" }</ChildContainer> };
|
||||
| ^^^^^^^^^^^^^^ the trait `IntoPropValue<ChildrenRenderer<VChild<Child>>>` is not implemented for `yew::virtual_dom::VText`
|
||||
|
|
||||
= help: the trait `IntoPropValue<ChildrenRenderer<VNode>>` is implemented for `yew::virtual_dom::VText`
|
||||
= help: the following other types implement trait `IntoPropValue<T>`:
|
||||
<yew::virtual_dom::VText as IntoPropValue<ChildrenRenderer<VNode>>>
|
||||
<yew::virtual_dom::VText as IntoPropValue<VNode>>
|
||||
note: required by a bound in `ChildContainerPropertiesBuilder::children`
|
||||
--> tests/html_macro/component-fail.rs:24:17
|
||||
|
|
||||
|
||||
@ -434,16 +434,7 @@ error[E0277]: the trait bound `(): IntoPropValue<Option<implicit_clone::unsync::
|
||||
43 | html! { <input type={()} /> };
|
||||
| ^^ the trait `IntoPropValue<Option<implicit_clone::unsync::IString>>` is not implemented for `()`
|
||||
|
|
||||
= help: the following other types implement trait `IntoPropValue<T>`:
|
||||
<&'static [(K, V)] as IntoPropValue<implicit_clone::unsync::IMap<K, V>>>
|
||||
<&'static [T] as IntoPropValue<implicit_clone::unsync::IArray<T>>>
|
||||
<&'static str as IntoPropValue<Classes>>
|
||||
<&'static str as IntoPropValue<Option<String>>>
|
||||
<&'static str as IntoPropValue<Option<implicit_clone::unsync::IString>>>
|
||||
<&'static str as IntoPropValue<String>>
|
||||
<&'static str as IntoPropValue<implicit_clone::unsync::IString>>
|
||||
<&T as IntoPropValue<Option<T>>>
|
||||
and $N others
|
||||
= help: the trait `IntoPropValue<VNode>` is implemented for `()`
|
||||
|
||||
error[E0277]: the trait bound `(): IntoPropValue<Option<implicit_clone::unsync::IString>>` is not satisfied
|
||||
--> tests/html_macro/element-fail.rs:44:27
|
||||
@ -451,16 +442,7 @@ error[E0277]: the trait bound `(): IntoPropValue<Option<implicit_clone::unsync::
|
||||
44 | html! { <input value={()} /> };
|
||||
| ^^ the trait `IntoPropValue<Option<implicit_clone::unsync::IString>>` is not implemented for `()`
|
||||
|
|
||||
= help: the following other types implement trait `IntoPropValue<T>`:
|
||||
<&'static [(K, V)] as IntoPropValue<implicit_clone::unsync::IMap<K, V>>>
|
||||
<&'static [T] as IntoPropValue<implicit_clone::unsync::IArray<T>>>
|
||||
<&'static str as IntoPropValue<Classes>>
|
||||
<&'static str as IntoPropValue<Option<String>>>
|
||||
<&'static str as IntoPropValue<Option<implicit_clone::unsync::IString>>>
|
||||
<&'static str as IntoPropValue<String>>
|
||||
<&'static str as IntoPropValue<implicit_clone::unsync::IString>>
|
||||
<&T as IntoPropValue<Option<T>>>
|
||||
and $N others
|
||||
= help: the trait `IntoPropValue<VNode>` is implemented for `()`
|
||||
|
||||
error[E0277]: the trait bound `(): IntoPropValue<Option<implicit_clone::unsync::IString>>` is not satisfied
|
||||
--> tests/html_macro/element-fail.rs:45:22
|
||||
@ -468,16 +450,7 @@ error[E0277]: the trait bound `(): IntoPropValue<Option<implicit_clone::unsync::
|
||||
45 | html! { <a href={()} /> };
|
||||
| ^^ the trait `IntoPropValue<Option<implicit_clone::unsync::IString>>` is not implemented for `()`
|
||||
|
|
||||
= help: the following other types implement trait `IntoPropValue<T>`:
|
||||
<&'static [(K, V)] as IntoPropValue<implicit_clone::unsync::IMap<K, V>>>
|
||||
<&'static [T] as IntoPropValue<implicit_clone::unsync::IArray<T>>>
|
||||
<&'static str as IntoPropValue<Classes>>
|
||||
<&'static str as IntoPropValue<Option<String>>>
|
||||
<&'static str as IntoPropValue<Option<implicit_clone::unsync::IString>>>
|
||||
<&'static str as IntoPropValue<String>>
|
||||
<&'static str as IntoPropValue<implicit_clone::unsync::IString>>
|
||||
<&T as IntoPropValue<Option<T>>>
|
||||
and $N others
|
||||
= help: the trait `IntoPropValue<VNode>` is implemented for `()`
|
||||
|
||||
error[E0277]: the trait bound `NotToString: IntoPropValue<Option<implicit_clone::unsync::IString>>` is not satisfied
|
||||
--> tests/html_macro/element-fail.rs:46:28
|
||||
@ -493,7 +466,7 @@ error[E0277]: the trait bound `NotToString: IntoPropValue<Option<implicit_clone:
|
||||
<&'static str as IntoPropValue<Option<implicit_clone::unsync::IString>>>
|
||||
<&'static str as IntoPropValue<String>>
|
||||
<&'static str as IntoPropValue<implicit_clone::unsync::IString>>
|
||||
<&T as IntoPropValue<Option<T>>>
|
||||
<&String as IntoPropValue<VNode>>
|
||||
and $N others
|
||||
|
||||
error[E0277]: the trait bound `Option<NotToString>: IntoPropValue<Option<implicit_clone::unsync::IString>>` is not satisfied
|
||||
@ -510,6 +483,7 @@ error[E0277]: the trait bound `Option<NotToString>: IntoPropValue<Option<implici
|
||||
<Option<Rc<str>> as IntoPropValue<Option<implicit_clone::unsync::IString>>>
|
||||
<Option<String> as IntoPropValue<Option<implicit_clone::unsync::IString>>>
|
||||
<Option<VChild<T>> as IntoPropValue<Option<ChildrenRenderer<C>>>>
|
||||
<Option<VNode> as IntoPropValue<VNode>>
|
||||
|
||||
error[E0277]: the trait bound `Option<{integer}>: IntoPropValue<Option<implicit_clone::unsync::IString>>` is not satisfied
|
||||
--> tests/html_macro/element-fail.rs:48:22
|
||||
@ -525,6 +499,7 @@ error[E0277]: the trait bound `Option<{integer}>: IntoPropValue<Option<implicit_
|
||||
<Option<Rc<str>> as IntoPropValue<Option<implicit_clone::unsync::IString>>>
|
||||
<Option<String> as IntoPropValue<Option<implicit_clone::unsync::IString>>>
|
||||
<Option<VChild<T>> as IntoPropValue<Option<ChildrenRenderer<C>>>>
|
||||
<Option<VNode> as IntoPropValue<VNode>>
|
||||
|
||||
error[E0277]: expected a `Fn<(MouseEvent,)>` closure, found `{integer}`
|
||||
--> tests/html_macro/element-fail.rs:51:28
|
||||
@ -613,16 +588,7 @@ error[E0277]: the trait bound `(): IntoPropValue<yew::NodeRef>` is not satisfied
|
||||
56 | html! { <input ref={()} /> };
|
||||
| ^^ the trait `IntoPropValue<yew::NodeRef>` is not implemented for `()`
|
||||
|
|
||||
= help: the following other types implement trait `IntoPropValue<T>`:
|
||||
<&'static [(K, V)] as IntoPropValue<implicit_clone::unsync::IMap<K, V>>>
|
||||
<&'static [T] as IntoPropValue<implicit_clone::unsync::IArray<T>>>
|
||||
<&'static str as IntoPropValue<Classes>>
|
||||
<&'static str as IntoPropValue<Option<String>>>
|
||||
<&'static str as IntoPropValue<Option<implicit_clone::unsync::IString>>>
|
||||
<&'static str as IntoPropValue<String>>
|
||||
<&'static str as IntoPropValue<implicit_clone::unsync::IString>>
|
||||
<&T as IntoPropValue<Option<T>>>
|
||||
and $N others
|
||||
= help: the trait `IntoPropValue<VNode>` is implemented for `()`
|
||||
= note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0277]: the trait bound `Option<yew::NodeRef>: IntoPropValue<yew::NodeRef>` is not satisfied
|
||||
@ -639,6 +605,7 @@ error[E0277]: the trait bound `Option<yew::NodeRef>: IntoPropValue<yew::NodeRef>
|
||||
<Option<Rc<str>> as IntoPropValue<Option<implicit_clone::unsync::IString>>>
|
||||
<Option<String> as IntoPropValue<Option<implicit_clone::unsync::IString>>>
|
||||
<Option<VChild<T>> as IntoPropValue<Option<ChildrenRenderer<C>>>>
|
||||
<Option<VNode> as IntoPropValue<VNode>>
|
||||
= note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0277]: expected a `Fn<(MouseEvent,)>` closure, found `yew::Callback<String>`
|
||||
@ -682,7 +649,7 @@ error[E0277]: the trait bound `NotToString: IntoPropValue<Option<implicit_clone:
|
||||
<&'static str as IntoPropValue<Option<implicit_clone::unsync::IString>>>
|
||||
<&'static str as IntoPropValue<String>>
|
||||
<&'static str as IntoPropValue<implicit_clone::unsync::IString>>
|
||||
<&T as IntoPropValue<Option<T>>>
|
||||
<&String as IntoPropValue<VNode>>
|
||||
and $N others
|
||||
|
||||
error[E0277]: the trait bound `(): IntoPropValue<yew::NodeRef>` is not satisfied
|
||||
@ -691,16 +658,7 @@ error[E0277]: the trait bound `(): IntoPropValue<yew::NodeRef>` is not satisfied
|
||||
62 | html! { <input ref={()} /> };
|
||||
| ^^ the trait `IntoPropValue<yew::NodeRef>` is not implemented for `()`
|
||||
|
|
||||
= help: the following other types implement trait `IntoPropValue<T>`:
|
||||
<&'static [(K, V)] as IntoPropValue<implicit_clone::unsync::IMap<K, V>>>
|
||||
<&'static [T] as IntoPropValue<implicit_clone::unsync::IArray<T>>>
|
||||
<&'static str as IntoPropValue<Classes>>
|
||||
<&'static str as IntoPropValue<Option<String>>>
|
||||
<&'static str as IntoPropValue<Option<implicit_clone::unsync::IString>>>
|
||||
<&'static str as IntoPropValue<String>>
|
||||
<&'static str as IntoPropValue<implicit_clone::unsync::IString>>
|
||||
<&T as IntoPropValue<Option<T>>>
|
||||
and $N others
|
||||
= help: the trait `IntoPropValue<VNode>` is implemented for `()`
|
||||
= note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0277]: the trait bound `implicit_clone::unsync::IString: From<{integer}>` is not satisfied
|
||||
|
||||
@ -193,10 +193,11 @@ where
|
||||
/// ```
|
||||
/// # let children = Children::new(Vec::new());
|
||||
/// # use yew::{classes, html, Children};
|
||||
/// # let _ =
|
||||
/// children.map(|children| {
|
||||
/// html! {
|
||||
/// <div class={classes!("container")}>
|
||||
/// {children}
|
||||
/// {children.clone()}
|
||||
/// </div>
|
||||
/// }
|
||||
/// })
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
use std::borrow::Cow;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
use implicit_clone::unsync::{IArray, IMap};
|
||||
pub use implicit_clone::ImplicitClone;
|
||||
|
||||
use super::ToHtml;
|
||||
use crate::callback::Callback;
|
||||
use crate::html::{BaseComponent, ChildrenRenderer, Component, NodeRef, Scope};
|
||||
use crate::virtual_dom::{AttrValue, VChild, VList, VNode, VText};
|
||||
@ -130,13 +130,40 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IntoPropValue<VNode> for T
|
||||
impl<T> IntoPropValue<VNode> for VChild<T>
|
||||
where
|
||||
T: ToHtml,
|
||||
T: BaseComponent,
|
||||
{
|
||||
#[inline]
|
||||
fn into_prop_value(self) -> VNode {
|
||||
self.into_html()
|
||||
VNode::from(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoPropValue<VNode> for VList {
|
||||
#[inline]
|
||||
fn into_prop_value(self) -> VNode {
|
||||
VNode::VList(Rc::new(self))
|
||||
}
|
||||
}
|
||||
impl IntoPropValue<VNode> for VText {
|
||||
#[inline]
|
||||
fn into_prop_value(self) -> VNode {
|
||||
VNode::VText(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoPropValue<VNode> for () {
|
||||
#[inline]
|
||||
fn into_prop_value(self) -> VNode {
|
||||
VNode::default()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoPropValue<VNode> for ChildrenRenderer<VNode> {
|
||||
#[inline]
|
||||
fn into_prop_value(self) -> VNode {
|
||||
VNode::VList(Rc::new(self.into()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -168,6 +195,26 @@ impl<C: BaseComponent> IntoPropValue<VList> for VChild<C> {
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoPropValue<ChildrenRenderer<VNode>> for AttrValue {
|
||||
fn into_prop_value(self) -> ChildrenRenderer<VNode> {
|
||||
ChildrenRenderer::new(vec![VNode::VText(VText::new(self))])
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoPropValue<VNode> for Vec<VNode> {
|
||||
#[inline]
|
||||
fn into_prop_value(self) -> VNode {
|
||||
VNode::VList(Rc::new(VList::with_children(self, None)))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoPropValue<VNode> for Option<VNode> {
|
||||
#[inline]
|
||||
fn into_prop_value(self) -> VNode {
|
||||
self.unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_into_prop {
|
||||
(|$value:ident: $from_ty:ty| -> $to_ty:ty { $conversion:expr }) => {
|
||||
// implement V -> T
|
||||
@ -231,6 +278,57 @@ impl<K: Eq + std::hash::Hash + ImplicitClone + 'static, V: PartialEq + ImplicitC
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_into_prop_value_via_display {
|
||||
($from_ty: ty) => {
|
||||
impl IntoPropValue<VNode> for $from_ty {
|
||||
#[inline(always)]
|
||||
fn into_prop_value(self) -> VNode {
|
||||
VText::from(self).into()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// go through AttrValue::from where possible
|
||||
macro_rules! impl_into_prop_value_via_attr_value {
|
||||
($from_ty: ty) => {
|
||||
impl IntoPropValue<VNode> for $from_ty {
|
||||
#[inline(always)]
|
||||
fn into_prop_value(self) -> VNode {
|
||||
VText::new(self).into()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// These are a selection of types implemented via display.
|
||||
impl_into_prop_value_via_display!(bool);
|
||||
impl_into_prop_value_via_display!(char);
|
||||
impl_into_prop_value_via_display!(&String);
|
||||
impl_into_prop_value_via_display!(&str);
|
||||
impl_into_prop_value_via_display!(Arc<str>);
|
||||
impl_into_prop_value_via_display!(Arc<String>);
|
||||
impl_into_prop_value_via_display!(Rc<String>);
|
||||
impl_into_prop_value_via_display!(u8);
|
||||
impl_into_prop_value_via_display!(u16);
|
||||
impl_into_prop_value_via_display!(u32);
|
||||
impl_into_prop_value_via_display!(u64);
|
||||
impl_into_prop_value_via_display!(u128);
|
||||
impl_into_prop_value_via_display!(usize);
|
||||
impl_into_prop_value_via_display!(i8);
|
||||
impl_into_prop_value_via_display!(i16);
|
||||
impl_into_prop_value_via_display!(i32);
|
||||
impl_into_prop_value_via_display!(i64);
|
||||
impl_into_prop_value_via_display!(i128);
|
||||
impl_into_prop_value_via_display!(isize);
|
||||
impl_into_prop_value_via_display!(f32);
|
||||
impl_into_prop_value_via_display!(f64);
|
||||
|
||||
impl_into_prop_value_via_attr_value!(String);
|
||||
impl_into_prop_value_via_attr_value!(AttrValue);
|
||||
impl_into_prop_value_via_attr_value!(Rc<str>);
|
||||
impl_into_prop_value_via_attr_value!(Cow<'static, str>);
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
@ -408,4 +506,30 @@ mod test {
|
||||
</Parent>
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn attr_value_children() {
|
||||
use crate::prelude::*;
|
||||
|
||||
#[derive(PartialEq, Properties)]
|
||||
pub struct ChildProps {
|
||||
#[prop_or_default]
|
||||
pub children: AttrValue,
|
||||
}
|
||||
|
||||
#[function_component]
|
||||
fn Child(_props: &ChildProps) -> Html {
|
||||
html!()
|
||||
}
|
||||
{
|
||||
let attr_value = AttrValue::from("foo");
|
||||
|
||||
let _ = html! { <Child>{attr_value}</Child> };
|
||||
}
|
||||
{
|
||||
let attr_value = AttrValue::from("foo");
|
||||
|
||||
let _ = html! { <Child>{&attr_value}</Child> };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,2 @@
|
||||
mod into_prop_value;
|
||||
mod to_html;
|
||||
|
||||
pub use into_prop_value::*;
|
||||
pub use to_html::*;
|
||||
|
||||
@ -1,203 +0,0 @@
|
||||
use std::borrow::Cow;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::html::{ChildrenRenderer, IntoPropValue};
|
||||
use crate::virtual_dom::{VChild, VList, VNode, VText};
|
||||
use crate::{AttrValue, BaseComponent, Html};
|
||||
|
||||
/// A trait implemented for types be rendered as a part of a Html.
|
||||
///
|
||||
/// Types that implements this trait can define a virtual dom layout that itself should be rendered
|
||||
/// into via `html!` and can be referenced / consumed as `{value}` in an `html!` macro invocation.
|
||||
pub trait ToHtml {
|
||||
/// Converts this type to a [`Html`].
|
||||
fn to_html(&self) -> Html;
|
||||
|
||||
/// Converts this type into a [`Html`].
|
||||
fn into_html(self) -> Html
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.to_html()
|
||||
}
|
||||
}
|
||||
|
||||
// Implementations for common data types.
|
||||
|
||||
impl<T> ToHtml for Option<T>
|
||||
where
|
||||
T: ToHtml,
|
||||
{
|
||||
#[inline(always)]
|
||||
fn to_html(&self) -> Html {
|
||||
self.as_ref().map(ToHtml::to_html).unwrap_or_default()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn into_html(self) -> Html {
|
||||
self.map(ToHtml::into_html).unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ToHtml for Vec<T>
|
||||
where
|
||||
T: ToHtml,
|
||||
{
|
||||
#[inline(always)]
|
||||
fn to_html(&self) -> Html {
|
||||
Html::VList(Rc::new(VList::with_children(
|
||||
self.iter().map(ToHtml::to_html).collect(),
|
||||
None,
|
||||
)))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn into_html(self) -> Html {
|
||||
Html::VList(Rc::new(VList::with_children(
|
||||
self.into_iter().map(ToHtml::into_html).collect(),
|
||||
None,
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
impl ToHtml for Option<VNode> {
|
||||
#[inline(always)]
|
||||
fn to_html(&self) -> Html {
|
||||
self.clone().into_html()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn into_html(self) -> Html {
|
||||
self.unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
impl ToHtml for Vec<VNode> {
|
||||
#[inline(always)]
|
||||
fn to_html(&self) -> Html {
|
||||
self.clone().into_html()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn into_html(self) -> Html {
|
||||
Html::VList(Rc::new(VList::with_children(self, None)))
|
||||
}
|
||||
}
|
||||
|
||||
impl ToHtml for VText {
|
||||
#[inline(always)]
|
||||
fn to_html(&self) -> Html {
|
||||
self.clone().into()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn into_html(self) -> Html {
|
||||
Html::VText(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToHtml for VList {
|
||||
#[inline(always)]
|
||||
fn to_html(&self) -> Html {
|
||||
self.clone().into()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn into_html(self) -> Html {
|
||||
Html::VList(Rc::new(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl ToHtml for ChildrenRenderer<VNode> {
|
||||
#[inline(always)]
|
||||
fn to_html(&self) -> Html {
|
||||
self.clone().into()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn into_html(self) -> Html {
|
||||
self.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ToHtml for VChild<T>
|
||||
where
|
||||
T: BaseComponent,
|
||||
{
|
||||
#[inline(always)]
|
||||
fn to_html(&self) -> Html {
|
||||
self.clone().into()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn into_html(self) -> Html {
|
||||
VNode::VComp(Rc::new(self.into()))
|
||||
}
|
||||
}
|
||||
|
||||
impl ToHtml for () {
|
||||
#[inline(always)]
|
||||
fn to_html(&self) -> Html {
|
||||
VNode::default()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn into_html(self) -> Html {
|
||||
VNode::default()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ToHtml for &'_ T
|
||||
where
|
||||
T: ToHtml,
|
||||
{
|
||||
fn to_html(&self) -> Html {
|
||||
(*self).to_html()
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_to_html_via_display {
|
||||
($from_ty: ty) => {
|
||||
impl ToHtml for $from_ty {
|
||||
#[inline(always)]
|
||||
fn to_html(&self) -> Html {
|
||||
Html::VText(VText::from(self))
|
||||
}
|
||||
}
|
||||
|
||||
// Mirror ToHtml to Children implementation.
|
||||
impl IntoPropValue<ChildrenRenderer<VNode>> for $from_ty {
|
||||
#[inline(always)]
|
||||
fn into_prop_value(self) -> ChildrenRenderer<VNode> {
|
||||
ChildrenRenderer::new(vec![VText::from(self).into()])
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// These are a selection of types implemented via display.
|
||||
impl_to_html_via_display!(bool);
|
||||
impl_to_html_via_display!(char);
|
||||
impl_to_html_via_display!(String);
|
||||
impl_to_html_via_display!(&str);
|
||||
impl_to_html_via_display!(Rc<str>);
|
||||
impl_to_html_via_display!(Rc<String>);
|
||||
impl_to_html_via_display!(Arc<str>);
|
||||
impl_to_html_via_display!(Arc<String>);
|
||||
impl_to_html_via_display!(AttrValue);
|
||||
impl_to_html_via_display!(Cow<'_, str>);
|
||||
impl_to_html_via_display!(u8);
|
||||
impl_to_html_via_display!(u16);
|
||||
impl_to_html_via_display!(u32);
|
||||
impl_to_html_via_display!(u64);
|
||||
impl_to_html_via_display!(u128);
|
||||
impl_to_html_via_display!(usize);
|
||||
impl_to_html_via_display!(i8);
|
||||
impl_to_html_via_display!(i16);
|
||||
impl_to_html_via_display!(i32);
|
||||
impl_to_html_via_display!(i64);
|
||||
impl_to_html_via_display!(i128);
|
||||
impl_to_html_via_display!(isize);
|
||||
impl_to_html_via_display!(f32);
|
||||
impl_to_html_via_display!(f64);
|
||||
@ -336,7 +336,7 @@ pub mod prelude {
|
||||
pub use crate::functional::*;
|
||||
pub use crate::html::{
|
||||
create_portal, BaseComponent, Children, ChildrenWithProps, Classes, Component, Context,
|
||||
Html, HtmlResult, NodeRef, Properties, ToHtml,
|
||||
Html, HtmlResult, NodeRef, Properties,
|
||||
};
|
||||
pub use crate::macros::{classes, html, html_nested};
|
||||
pub use crate::suspense::Suspense;
|
||||
|
||||
@ -183,6 +183,8 @@ pub struct VChild<COMP: BaseComponent> {
|
||||
key: Option<Key>,
|
||||
}
|
||||
|
||||
impl<COMP: BaseComponent> implicit_clone::ImplicitClone for VChild<COMP> {}
|
||||
|
||||
impl<COMP: BaseComponent> Clone for VChild<COMP> {
|
||||
fn clone(&self) -> Self {
|
||||
VChild {
|
||||
|
||||
@ -10,7 +10,7 @@ The `#[function_component]` attribute also works with generic functions for crea
|
||||
|
||||
```rust
|
||||
use std::fmt::Display;
|
||||
use yew::{function_component, html, Properties, Html, ToHtml};
|
||||
use yew::{function_component, html, Properties, Html};
|
||||
|
||||
#[derive(Properties, PartialEq)]
|
||||
pub struct Props<T>
|
||||
@ -23,11 +23,11 @@ where
|
||||
#[function_component]
|
||||
pub fn MyGenericComponent<T>(props: &Props<T>) -> Html
|
||||
where
|
||||
T: PartialEq + ToHtml,
|
||||
T: PartialEq + Clone + Into<Html>,
|
||||
{
|
||||
html! {
|
||||
<p>
|
||||
{ &props.data }
|
||||
{ props.data.clone().into() }
|
||||
</p>
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user