mirror of
https://github.com/yewstack/yew.git
synced 2025-12-08 21:26:25 +00:00
Make virtual dom cloneable (#786)
This commit is contained in:
parent
3ffde502a7
commit
84a9ed0e09
@ -240,7 +240,7 @@ Properties are also pure Rust types with strict type-checking during the compila
|
|||||||
```rust
|
```rust
|
||||||
// my_button.rs
|
// my_button.rs
|
||||||
|
|
||||||
#[derive(Properties, PartialEq)]
|
#[derive(Clone, Properties, PartialEq)]
|
||||||
pub struct Properties {
|
pub struct Properties {
|
||||||
pub hidden: bool,
|
pub hidden: bool,
|
||||||
#[props(required)]
|
#[props(required)]
|
||||||
|
|||||||
@ -119,16 +119,9 @@ impl ToTokens for HtmlComponent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let set_children = if !children.is_empty() {
|
let set_children = if !children.is_empty() {
|
||||||
let children_len = children.len();
|
|
||||||
quote! {
|
quote! {
|
||||||
.children(::yew::html::ChildrenRenderer::new(
|
.children(::yew::html::ChildrenRenderer::new(
|
||||||
#children_len,
|
vec![#(#children.into(),)*]
|
||||||
::std::boxed::Box::new(move || {
|
|
||||||
#[allow(unused_must_use)]
|
|
||||||
|| -> ::std::vec::Vec<_> {
|
|
||||||
vec![#(#children.into(),)*]
|
|
||||||
}
|
|
||||||
}()),
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -172,7 +172,7 @@ impl ToTokens for HtmlTag {
|
|||||||
#(#set_classes)*
|
#(#set_classes)*
|
||||||
#(#set_node_ref)*
|
#(#set_node_ref)*
|
||||||
#vtag.add_attributes(vec![#(#attr_pairs),*]);
|
#vtag.add_attributes(vec![#(#attr_pairs),*]);
|
||||||
#vtag.add_listeners(vec![#(::std::boxed::Box::new(#listeners)),*]);
|
#vtag.add_listeners(vec![#(::std::rc::Rc::new(#listeners)),*]);
|
||||||
#vtag.add_children(vec![#(#children),*]);
|
#vtag.add_children(vec![#(#children),*]);
|
||||||
::yew::virtual_dom::VNode::from(#vtag)
|
::yew::virtual_dom::VNode::from(#vtag)
|
||||||
}});
|
}});
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
//! link: ComponentLink<Self>,
|
//! link: ComponentLink<Self>,
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! #[derive(Properties)]
|
//! #[derive(Clone, Properties)]
|
||||||
//! struct Props {
|
//! struct Props {
|
||||||
//! #[props(required)]
|
//! #[props(required)]
|
||||||
//! prop: String,
|
//! prop: String,
|
||||||
|
|||||||
@ -12,7 +12,7 @@ pub enum Msg {
|
|||||||
ChildClicked,
|
ChildClicked,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
pub struct Props {
|
pub struct Props {
|
||||||
pub limit: u32,
|
pub limit: u32,
|
||||||
#[props(required)]
|
#[props(required)]
|
||||||
|
|||||||
@ -10,7 +10,7 @@ pub enum Msg {
|
|||||||
Clicked,
|
Clicked,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
pub struct Props {
|
pub struct Props {
|
||||||
pub title: String,
|
pub title: String,
|
||||||
#[props(required)]
|
#[props(required)]
|
||||||
|
|||||||
@ -24,7 +24,7 @@ pub enum Msg {
|
|||||||
Increase,
|
Increase,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
pub struct Props {
|
pub struct Props {
|
||||||
pub initial: u32,
|
pub initial: u32,
|
||||||
pub color: Color,
|
pub color: Color,
|
||||||
|
|||||||
@ -5,4 +5,6 @@ authors = ["Justin Starry <justin.starry@icloud.com>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
log = "0.4"
|
||||||
|
web_logger = "0.2"
|
||||||
yew = { path = "../.." }
|
yew = { path = "../.." }
|
||||||
|
|||||||
77
examples/nested_list/src/app.rs
Normal file
77
examples/nested_list/src/app.rs
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
use super::header::ListHeader;
|
||||||
|
use super::item::ListItem;
|
||||||
|
use super::list::List;
|
||||||
|
use super::{Hovered, WeakComponentLink};
|
||||||
|
use yew::prelude::*;
|
||||||
|
|
||||||
|
pub struct App {
|
||||||
|
link: ComponentLink<Self>,
|
||||||
|
hovered: Hovered,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Msg {
|
||||||
|
Hover(Hovered),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Component for App {
|
||||||
|
type Message = Msg;
|
||||||
|
type Properties = ();
|
||||||
|
|
||||||
|
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||||
|
App {
|
||||||
|
link,
|
||||||
|
hovered: Hovered::None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||||
|
match msg {
|
||||||
|
Msg::Hover(hovered) => self.hovered = hovered,
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn view(&self) -> Html {
|
||||||
|
let on_hover = &self.link.callback(Msg::Hover);
|
||||||
|
let onmouseenter = &self.link.callback(|_| Msg::Hover(Hovered::None));
|
||||||
|
let list_link = &WeakComponentLink::<List>::default();
|
||||||
|
let sub_list_link = &WeakComponentLink::<List>::default();
|
||||||
|
html! {
|
||||||
|
<div class="main" onmouseenter=onmouseenter>
|
||||||
|
<h1>{ "Nested List Demo" }</h1>
|
||||||
|
<List on_hover=on_hover weak_link=list_link>
|
||||||
|
<ListHeader text="Calling all Rusties!" on_hover=on_hover list_link=list_link />
|
||||||
|
<ListItem name="Rustin" on_hover=on_hover />
|
||||||
|
<ListItem hide={true} name="Rustaroo" on_hover=on_hover />
|
||||||
|
<ListItem name="Rustifer" on_hover=on_hover>
|
||||||
|
<div class="sublist">{"Sublist!"}</div>
|
||||||
|
{
|
||||||
|
html! {
|
||||||
|
<List on_hover=on_hover weak_link=sub_list_link>
|
||||||
|
<ListHeader text="Sub Rusties!" on_hover=on_hover list_link=sub_list_link/>
|
||||||
|
<ListItem name="Sub Rustin" on_hover=on_hover />
|
||||||
|
<ListItem hide={true} name="Sub Rustaroo" on_hover=on_hover />
|
||||||
|
<ListItem name="Sub Rustifer" on_hover=on_hover />
|
||||||
|
</List>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</ListItem>
|
||||||
|
</List>
|
||||||
|
{self.view_last_hovered()}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl App {
|
||||||
|
fn view_last_hovered(&self) -> Html {
|
||||||
|
html! {
|
||||||
|
<div class="last-hovered">
|
||||||
|
{ "Last hovered:"}
|
||||||
|
<span class="last-hovered-text">
|
||||||
|
{ &self.hovered }
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,16 +1,19 @@
|
|||||||
use crate::Hovered;
|
use super::list::{List, Msg as ListMsg};
|
||||||
|
use super::{Hovered, WeakComponentLink};
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
|
|
||||||
pub struct ListHeader {
|
pub struct ListHeader {
|
||||||
props: Props,
|
props: Props,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Properties)]
|
#[derive(Clone, Properties)]
|
||||||
pub struct Props {
|
pub struct Props {
|
||||||
#[props(required)]
|
#[props(required)]
|
||||||
pub on_hover: Callback<Hovered>,
|
pub on_hover: Callback<Hovered>,
|
||||||
#[props(required)]
|
#[props(required)]
|
||||||
pub text: String,
|
pub text: String,
|
||||||
|
#[props(required)]
|
||||||
|
pub list_link: WeakComponentLink<List>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for ListHeader {
|
impl Component for ListHeader {
|
||||||
@ -26,9 +29,11 @@ impl Component for ListHeader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
fn view(&self) -> Html {
|
||||||
|
let list_link = self.props.list_link.borrow().clone().unwrap();
|
||||||
|
let onclick = list_link.callback(|_| ListMsg::HeaderClick);
|
||||||
let onmouseover = self.props.on_hover.reform(|_| Hovered::Header);
|
let onmouseover = self.props.on_hover.reform(|_| Hovered::Header);
|
||||||
html! {
|
html! {
|
||||||
<div class="list-header" onmouseover=onmouseover>
|
<div class="list-header" onmouseover=onmouseover onclick=onclick>
|
||||||
{ &self.props.text }
|
{ &self.props.text }
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@ pub struct ListItem {
|
|||||||
props: Props,
|
props: Props,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Properties)]
|
#[derive(Clone, Properties)]
|
||||||
pub struct Props {
|
pub struct Props {
|
||||||
pub hide: bool,
|
pub hide: bool,
|
||||||
#[props(required)]
|
#[props(required)]
|
||||||
@ -30,7 +30,10 @@ impl Component for ListItem {
|
|||||||
|
|
||||||
fn view(&self) -> Html {
|
fn view(&self) -> Html {
|
||||||
let name = self.props.name.clone();
|
let name = self.props.name.clone();
|
||||||
let onmouseover = self.props.on_hover.reform(move |_| Hovered::Item(name.clone()));
|
let onmouseover = self
|
||||||
|
.props
|
||||||
|
.on_hover
|
||||||
|
.reform(move |_| Hovered::Item(name.clone()));
|
||||||
html! {
|
html! {
|
||||||
<div class="list-item" onmouseover=onmouseover>
|
<div class="list-item" onmouseover=onmouseover>
|
||||||
{ &self.props.name }
|
{ &self.props.name }
|
||||||
|
|||||||
@ -1,19 +1,16 @@
|
|||||||
#![recursion_limit = "128"]
|
#![recursion_limit = "512"]
|
||||||
|
|
||||||
|
mod app;
|
||||||
mod header;
|
mod header;
|
||||||
mod item;
|
mod item;
|
||||||
mod list;
|
mod list;
|
||||||
|
|
||||||
use header::ListHeader;
|
pub use app::App;
|
||||||
use item::ListItem;
|
use std::cell::RefCell;
|
||||||
use list::List;
|
|
||||||
use yew::prelude::*;
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::rc::Rc;
|
||||||
pub struct Model {
|
use yew::html::ComponentLink;
|
||||||
link: ComponentLink<Self>,
|
pub type WeakComponentLink<COMP> = Rc<RefCell<Option<ComponentLink<COMP>>>>;
|
||||||
hovered: Hovered,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Hovered {
|
pub enum Hovered {
|
||||||
@ -23,60 +20,6 @@ pub enum Hovered {
|
|||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Msg {
|
|
||||||
Hover(Hovered),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Component for Model {
|
|
||||||
type Message = Msg;
|
|
||||||
type Properties = ();
|
|
||||||
|
|
||||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
|
||||||
Model { link,
|
|
||||||
hovered: Hovered::None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
|
||||||
match msg {
|
|
||||||
Msg::Hover(hovered) => self.hovered = hovered,
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
|
||||||
let on_hover = self.link.callback(Msg::Hover);
|
|
||||||
|
|
||||||
html! {
|
|
||||||
<div class="main">
|
|
||||||
<h1>{ "Nested List Demo" }</h1>
|
|
||||||
<List on_hover=on_hover.clone()>
|
|
||||||
<ListHeader text="Calling all Rusties!" on_hover=on_hover.clone() />
|
|
||||||
<ListItem name="Rustin" on_hover=on_hover.clone() />
|
|
||||||
<ListItem hide={true} name="Rustaroo" on_hover=on_hover.clone() />
|
|
||||||
<ListItem name="Rustifer" on_hover=on_hover.clone()>
|
|
||||||
<span>{"Hello!"}</span>
|
|
||||||
</ListItem>
|
|
||||||
</List>
|
|
||||||
{self.view_last_hovered()}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Model {
|
|
||||||
fn view_last_hovered(&self) -> Html {
|
|
||||||
html! {
|
|
||||||
<div class="last-hovered">
|
|
||||||
{ "Last hovered:"}
|
|
||||||
<span class="last-hovered-text">
|
|
||||||
{ &self.hovered }
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Hovered {
|
impl fmt::Display for Hovered {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
use crate::{header::Props as HeaderProps, ListHeader};
|
use super::{Hovered, WeakComponentLink};
|
||||||
use crate::{item::Props as ItemProps, ListItem};
|
use crate::{header::ListHeader, header::Props as HeaderProps};
|
||||||
use crate::Hovered;
|
use crate::{item::ListItem, item::Props as ItemProps};
|
||||||
use yew::html::{ChildrenRenderer, NodeRef};
|
use yew::html::{ChildrenRenderer, NodeRef};
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
use yew::virtual_dom::{VChild, VComp, VNode};
|
use yew::virtual_dom::{VChild, VComp, VNode};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub enum Variants {
|
pub enum Variants {
|
||||||
Item(<ListItem as Component>::Properties),
|
Item(<ListItem as Component>::Properties),
|
||||||
Header(<ListHeader as Component>::Properties),
|
Header(<ListHeader as Component>::Properties),
|
||||||
@ -22,40 +23,58 @@ impl From<HeaderProps> for Variants {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct ListVariant {
|
pub struct ListVariant {
|
||||||
props: Variants,
|
props: Variants,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Properties)]
|
#[derive(Clone, Properties)]
|
||||||
pub struct Props {
|
pub struct Props {
|
||||||
#[props(required)]
|
#[props(required)]
|
||||||
pub children: ChildrenRenderer<ListVariant>,
|
pub children: ChildrenRenderer<ListVariant>,
|
||||||
#[props(required)]
|
#[props(required)]
|
||||||
pub on_hover: Callback<Hovered>,
|
pub on_hover: Callback<Hovered>,
|
||||||
|
#[props(required)]
|
||||||
|
pub weak_link: WeakComponentLink<List>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct List {
|
pub struct List {
|
||||||
props: Props,
|
props: Props,
|
||||||
|
inactive: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Msg {
|
||||||
|
HeaderClick,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for List {
|
impl Component for List {
|
||||||
type Message = ();
|
type Message = Msg;
|
||||||
type Properties = Props;
|
type Properties = Props;
|
||||||
|
|
||||||
fn create(props: Self::Properties, _: ComponentLink<Self>) -> Self {
|
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||||
List { props }
|
*props.weak_link.borrow_mut() = Some(link);
|
||||||
|
List {
|
||||||
|
props,
|
||||||
|
inactive: false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||||
false
|
match msg {
|
||||||
|
Msg::HeaderClick => {
|
||||||
|
self.inactive = !self.inactive;
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
fn view(&self) -> Html {
|
||||||
|
let inactive = if self.inactive { "inactive" } else { "" };
|
||||||
let onmouseover = self.props.on_hover.reform(|_| Hovered::List);
|
let onmouseover = self.props.on_hover.reform(|_| Hovered::List);
|
||||||
let onmouseout = self.props.on_hover.reform(|_| Hovered::None);
|
let onmouseout = self.props.on_hover.reform(|_| Hovered::None);
|
||||||
html! {
|
html! {
|
||||||
<div class="list-container" onmouseout=onmouseout onmouseover=onmouseover>
|
<div class="list-container" onmouseout=onmouseout onmouseover=onmouseover>
|
||||||
<div class="list">
|
<div class=vec!["list", inactive]>
|
||||||
{self.view_header()}
|
{self.view_header()}
|
||||||
<div class="items">
|
<div class="items">
|
||||||
{self.view_items()}
|
{self.view_items()}
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
fn main() {
|
fn main() {
|
||||||
yew::start_app::<nested_list::Model>();
|
web_logger::init();
|
||||||
|
yew::start_app::<nested_list::App>();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,10 +35,15 @@ html, body {
|
|||||||
min-width: 30vw;
|
min-width: 30vw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.list.inactive {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
.list-header {
|
.list-header {
|
||||||
background: #FEECAA;
|
background: #FEECAA;
|
||||||
border-bottom: 1px solid #666;
|
border-bottom: 1px solid #666;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-header:hover {
|
.list-header:hover {
|
||||||
@ -65,6 +70,7 @@ html, body {
|
|||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.last-hovered {
|
.last-hovered {
|
||||||
@ -75,3 +81,17 @@ html, body {
|
|||||||
color: #666;
|
color: #666;
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.list-item-details .list-container {
|
||||||
|
margin-top: 0px;
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sublist {
|
||||||
|
display: inline-block;
|
||||||
|
background: #FFF;
|
||||||
|
border: 1px solid #666;
|
||||||
|
border-radius: 3px;
|
||||||
|
margin: 5px;
|
||||||
|
padding: 5px 20px;
|
||||||
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ pub struct InputComponent {
|
|||||||
link: ComponentLink<Self>,
|
link: ComponentLink<Self>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Properties)]
|
#[derive(Clone, Properties)]
|
||||||
pub struct Props {
|
pub struct Props {
|
||||||
#[props(required)]
|
#[props(required)]
|
||||||
pub on_hover: Callback<()>,
|
pub on_hover: Callback<()>,
|
||||||
|
|||||||
@ -64,7 +64,7 @@ pub type Html = VNode;
|
|||||||
/// In this example, the `Wrapper` component is used to wrap other elements.
|
/// In this example, the `Wrapper` component is used to wrap other elements.
|
||||||
/// ```
|
/// ```
|
||||||
///# use yew::{Children, Html, Properties, Component, ComponentLink, html};
|
///# use yew::{Children, Html, Properties, Component, ComponentLink, html};
|
||||||
///# #[derive(Properties)]
|
///# #[derive(Clone, Properties)]
|
||||||
///# struct WrapperProps {
|
///# struct WrapperProps {
|
||||||
///# children: Children,
|
///# children: Children,
|
||||||
///# }
|
///# }
|
||||||
@ -92,7 +92,7 @@ pub type Html = VNode;
|
|||||||
/// children property can be used to render the wrapped elements.
|
/// children property can be used to render the wrapped elements.
|
||||||
/// ```
|
/// ```
|
||||||
///# use yew::{Children, Html, Properties, Renderable, Component, ComponentLink, html};
|
///# use yew::{Children, Html, Properties, Renderable, Component, ComponentLink, html};
|
||||||
/// #[derive(Properties)]
|
/// #[derive(Clone, Properties)]
|
||||||
/// struct WrapperProps {
|
/// struct WrapperProps {
|
||||||
/// children: Children,
|
/// children: Children,
|
||||||
/// }
|
/// }
|
||||||
@ -124,7 +124,7 @@ pub type Children = ChildrenRenderer<Html>;
|
|||||||
/// ```
|
/// ```
|
||||||
///# use yew::{html, Component, Renderable, Html, ComponentLink, ChildrenWithProps, Properties};
|
///# use yew::{html, Component, Renderable, Html, ComponentLink, ChildrenWithProps, Properties};
|
||||||
///#
|
///#
|
||||||
///# #[derive(Properties)]
|
///# #[derive(Clone, Properties)]
|
||||||
///# struct ListProps {
|
///# struct ListProps {
|
||||||
///# children: ChildrenWithProps<ListItem>,
|
///# children: ChildrenWithProps<ListItem>,
|
||||||
///# }
|
///# }
|
||||||
@ -136,7 +136,7 @@ pub type Children = ChildrenRenderer<Html>;
|
|||||||
///# fn update(&mut self, msg: Self::Message) -> bool {unimplemented!()}
|
///# fn update(&mut self, msg: Self::Message) -> bool {unimplemented!()}
|
||||||
///# fn view(&self) -> Html {unimplemented!()}
|
///# fn view(&self) -> Html {unimplemented!()}
|
||||||
///# }
|
///# }
|
||||||
///# #[derive(Properties)]
|
///# #[derive(Clone, Properties)]
|
||||||
///# struct ListItemProps {
|
///# struct ListItemProps {
|
||||||
///# value: String
|
///# value: String
|
||||||
///# }
|
///# }
|
||||||
@ -166,7 +166,7 @@ pub type Children = ChildrenRenderer<Html>;
|
|||||||
/// ```
|
/// ```
|
||||||
///# use yew::{html, Component, Html, ChildrenWithProps, ComponentLink, Properties};
|
///# use yew::{html, Component, Html, ChildrenWithProps, ComponentLink, Properties};
|
||||||
///#
|
///#
|
||||||
/// #[derive(Properties)]
|
/// #[derive(Clone, Properties)]
|
||||||
/// struct ListProps {
|
/// struct ListProps {
|
||||||
/// children: ChildrenWithProps<ListItem>,
|
/// children: ChildrenWithProps<ListItem>,
|
||||||
/// }
|
/// }
|
||||||
@ -188,7 +188,7 @@ pub type Children = ChildrenRenderer<Html>;
|
|||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
///#
|
///#
|
||||||
///# #[derive(Properties)]
|
///# #[derive(Clone, Properties)]
|
||||||
///# struct ListItemProps {
|
///# struct ListItemProps {
|
||||||
///# value: String
|
///# value: String
|
||||||
///# }
|
///# }
|
||||||
@ -205,30 +205,33 @@ pub type Children = ChildrenRenderer<Html>;
|
|||||||
pub type ChildrenWithProps<CHILD> = ChildrenRenderer<VChild<CHILD>>;
|
pub type ChildrenWithProps<CHILD> = ChildrenRenderer<VChild<CHILD>>;
|
||||||
|
|
||||||
/// A type used for rendering children html.
|
/// A type used for rendering children html.
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct ChildrenRenderer<T> {
|
pub struct ChildrenRenderer<T> {
|
||||||
len: usize,
|
children: Vec<T>,
|
||||||
boxed_render: Box<dyn Fn() -> Vec<T>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> ChildrenRenderer<T> {
|
impl<T> ChildrenRenderer<T>
|
||||||
|
where
|
||||||
|
T: Clone + Into<VNode>,
|
||||||
|
{
|
||||||
/// Create children
|
/// Create children
|
||||||
pub fn new(len: usize, boxed_render: Box<dyn Fn() -> Vec<T>>) -> Self {
|
pub fn new(children: Vec<T>) -> Self {
|
||||||
Self { len, boxed_render }
|
Self { children }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Children list is empty
|
/// Children list is empty
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.len == 0
|
self.children.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Number of children elements
|
/// Number of children elements
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.len
|
self.children.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build children components and return `Vec`
|
/// Build children components and return `Vec`
|
||||||
pub fn to_vec(&self) -> Vec<T> {
|
pub fn to_vec(&self) -> Vec<T> {
|
||||||
(&self.boxed_render)()
|
self.children.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Render children components and return `Iterator`
|
/// Render children components and return `Iterator`
|
||||||
@ -239,13 +242,8 @@ impl<T> ChildrenRenderer<T> {
|
|||||||
|
|
||||||
impl<T> Default for ChildrenRenderer<T> {
|
impl<T> Default for ChildrenRenderer<T> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
// False positive: https://github.com/rust-lang/rust-clippy/issues/4002
|
|
||||||
#[allow(clippy::redundant_closure)]
|
|
||||||
let boxed_render = Box::new(|| Vec::new());
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
len: 0,
|
children: Vec::new(),
|
||||||
boxed_render,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -258,7 +256,7 @@ impl<T> fmt::Debug for ChildrenRenderer<T> {
|
|||||||
|
|
||||||
impl<T> Renderable for ChildrenRenderer<T>
|
impl<T> Renderable for ChildrenRenderer<T>
|
||||||
where
|
where
|
||||||
T: Into<VNode>,
|
T: Clone + Into<VNode>,
|
||||||
{
|
{
|
||||||
fn render(&self) -> Html {
|
fn render(&self) -> Html {
|
||||||
VList::new_with_children(self.iter().map(|c| c.into()).collect()).into()
|
VList::new_with_children(self.iter().map(|c| c.into()).collect()).into()
|
||||||
@ -338,7 +336,7 @@ impl<COMP: Component> Renderable for COMP {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Trait for building properties for a component
|
/// Trait for building properties for a component
|
||||||
pub trait Properties {
|
pub trait Properties: Clone {
|
||||||
/// Builder that will be used to construct properties
|
/// Builder that will be used to construct properties
|
||||||
type Builder;
|
type Builder;
|
||||||
|
|
||||||
|
|||||||
@ -9,6 +9,7 @@ pub mod vtext;
|
|||||||
use indexmap::set::IndexSet;
|
use indexmap::set::IndexSet;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::rc::Rc;
|
||||||
use stdweb::web::{Element, EventListenerHandle, Node};
|
use stdweb::web::{Element, EventListenerHandle, Node};
|
||||||
|
|
||||||
pub use self::vcomp::{VChild, VComp};
|
pub use self::vcomp::{VChild, VComp};
|
||||||
@ -33,7 +34,7 @@ impl fmt::Debug for dyn Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A list of event listeners.
|
/// A list of event listeners.
|
||||||
type Listeners = Vec<Box<dyn Listener>>;
|
type Listeners = Vec<Rc<dyn Listener>>;
|
||||||
|
|
||||||
/// A map of attributes.
|
/// A map of attributes.
|
||||||
type Attributes = HashMap<String, String>;
|
type Attributes = HashMap<String, String>;
|
||||||
|
|||||||
@ -9,7 +9,7 @@ use std::rc::Rc;
|
|||||||
use stdweb::web::{document, Element, INode, Node, TextNode};
|
use stdweb::web::{document, Element, INode, Node, TextNode};
|
||||||
|
|
||||||
/// The method generates an instance of a component.
|
/// The method generates an instance of a component.
|
||||||
type Generator = dyn FnOnce(GeneratorType) -> Mounted;
|
type Generator = dyn Fn(GeneratorType) -> Mounted;
|
||||||
|
|
||||||
/// Components can be generated by mounting or by overwriting an old component.
|
/// Components can be generated by mounting or by overwriting an old component.
|
||||||
enum GeneratorType {
|
enum GeneratorType {
|
||||||
@ -23,6 +23,15 @@ pub struct VComp {
|
|||||||
state: Rc<RefCell<MountState>>,
|
state: Rc<RefCell<MountState>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Clone for VComp {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
VComp {
|
||||||
|
type_id: self.type_id,
|
||||||
|
state: self.state.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A virtual child component.
|
/// A virtual child component.
|
||||||
pub struct VChild<COMP: Component> {
|
pub struct VChild<COMP: Component> {
|
||||||
/// The component properties
|
/// The component properties
|
||||||
@ -31,6 +40,15 @@ pub struct VChild<COMP: Component> {
|
|||||||
node_ref: NodeRef,
|
node_ref: NodeRef,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<COMP: Component> Clone for VChild<COMP> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
VChild {
|
||||||
|
props: self.props.clone(),
|
||||||
|
node_ref: self.node_ref.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<COMP> VChild<COMP>
|
impl<COMP> VChild<COMP>
|
||||||
where
|
where
|
||||||
COMP: Component,
|
COMP: Component,
|
||||||
@ -83,21 +101,21 @@ impl VComp {
|
|||||||
element,
|
element,
|
||||||
Some(VNode::VRef(dummy_node.into())),
|
Some(VNode::VRef(dummy_node.into())),
|
||||||
node_ref.clone(),
|
node_ref.clone(),
|
||||||
props,
|
props.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Mounted {
|
Mounted {
|
||||||
node_ref,
|
node_ref: node_ref.clone(),
|
||||||
scope: scope.clone().into(),
|
scope: scope.clone().into(),
|
||||||
destroyer: Box::new(move || scope.destroy()),
|
destroyer: Box::new(move || scope.destroy()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GeneratorType::Overwrite(hidden_scope) => {
|
GeneratorType::Overwrite(hidden_scope) => {
|
||||||
let mut scope: Scope<COMP> = hidden_scope.into();
|
let mut scope: Scope<COMP> = hidden_scope.into();
|
||||||
scope.update(ComponentUpdate::Properties(props));
|
scope.update(ComponentUpdate::Properties(props.clone()));
|
||||||
|
|
||||||
Mounted {
|
Mounted {
|
||||||
node_ref,
|
node_ref: node_ref.clone(),
|
||||||
scope: scope.clone().into(),
|
scope: scope.clone().into(),
|
||||||
destroyer: Box::new(move || scope.destroy()),
|
destroyer: Box::new(move || scope.destroy()),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,7 @@ use std::ops::{Deref, DerefMut};
|
|||||||
use stdweb::web::{Element, Node};
|
use stdweb::web::{Element, Node};
|
||||||
|
|
||||||
/// This struct represents a fragment of the Virtual DOM tree.
|
/// This struct represents a fragment of the Virtual DOM tree.
|
||||||
#[derive(Debug, PartialEq, Default)]
|
#[derive(Clone, Debug, PartialEq, Default)]
|
||||||
pub struct VList {
|
pub struct VList {
|
||||||
/// The list of children nodes.
|
/// The list of children nodes.
|
||||||
pub children: Vec<VNode>,
|
pub children: Vec<VNode>,
|
||||||
|
|||||||
@ -8,6 +8,7 @@ use std::iter::FromIterator;
|
|||||||
use stdweb::web::{Element, INode, Node};
|
use stdweb::web::{Element, INode, Node};
|
||||||
|
|
||||||
/// Bind virtual element to a DOM reference.
|
/// Bind virtual element to a DOM reference.
|
||||||
|
#[derive(Clone)]
|
||||||
pub enum VNode {
|
pub enum VNode {
|
||||||
/// A bind between `VTag` and `Element`.
|
/// A bind between `VTag` and `Element`.
|
||||||
VTag(Box<VTag>),
|
VTag(Box<VTag>),
|
||||||
|
|||||||
@ -8,6 +8,7 @@ use log::warn;
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::cmp::PartialEq;
|
use std::cmp::PartialEq;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::rc::Rc;
|
||||||
use stdweb::unstable::TryFrom;
|
use stdweb::unstable::TryFrom;
|
||||||
use stdweb::web::html_element::InputElement;
|
use stdweb::web::html_element::InputElement;
|
||||||
use stdweb::web::html_element::TextAreaElement;
|
use stdweb::web::html_element::TextAreaElement;
|
||||||
@ -56,6 +57,24 @@ pub struct VTag {
|
|||||||
captured: Vec<EventListenerHandle>,
|
captured: Vec<EventListenerHandle>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Clone for VTag {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
VTag {
|
||||||
|
tag: self.tag.clone(),
|
||||||
|
reference: None,
|
||||||
|
listeners: self.listeners.clone(),
|
||||||
|
attributes: self.attributes.clone(),
|
||||||
|
children: self.children.clone(),
|
||||||
|
classes: self.classes.clone(),
|
||||||
|
value: self.value.clone(),
|
||||||
|
kind: self.kind.clone(),
|
||||||
|
checked: self.checked,
|
||||||
|
node_ref: self.node_ref.clone(),
|
||||||
|
captured: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl VTag {
|
impl VTag {
|
||||||
/// Creates a new `VTag` instance with `tag` name (cannot be changed later in DOM).
|
/// Creates a new `VTag` instance with `tag` name (cannot be changed later in DOM).
|
||||||
pub fn new<S: Into<Cow<'static, str>>>(tag: S) -> Self {
|
pub fn new<S: Into<Cow<'static, str>>>(tag: S) -> Self {
|
||||||
@ -161,14 +180,14 @@ impl VTag {
|
|||||||
/// Adds new listener to the node.
|
/// Adds new listener to the node.
|
||||||
/// It's boxed because we want to keep it in a single list.
|
/// It's boxed because we want to keep it in a single list.
|
||||||
/// Later `Listener::attach` will attach an actual listener to a DOM node.
|
/// Later `Listener::attach` will attach an actual listener to a DOM node.
|
||||||
pub fn add_listener(&mut self, listener: Box<dyn Listener>) {
|
pub fn add_listener(&mut self, listener: Rc<dyn Listener>) {
|
||||||
self.listeners.push(listener);
|
self.listeners.push(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds new listeners to the node.
|
/// Adds new listeners to the node.
|
||||||
/// They are boxed because we want to keep them in a single list.
|
/// They are boxed because we want to keep them in a single list.
|
||||||
/// Later `Listener::attach` will attach an actual listener to a DOM node.
|
/// Later `Listener::attach` will attach an actual listener to a DOM node.
|
||||||
pub fn add_listeners(&mut self, listeners: Vec<Box<dyn Listener>>) {
|
pub fn add_listeners(&mut self, listeners: Vec<Rc<dyn Listener>>) {
|
||||||
for listener in listeners {
|
for listener in listeners {
|
||||||
self.listeners.push(listener);
|
self.listeners.push(listener);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,6 +9,7 @@ use stdweb::web::{document, Element, INode, Node, TextNode};
|
|||||||
/// A type for a virtual
|
/// A type for a virtual
|
||||||
/// [`TextNode`](https://developer.mozilla.org/en-US/docs/Web/API/Document/createTextNode)
|
/// [`TextNode`](https://developer.mozilla.org/en-US/docs/Web/API/Document/createTextNode)
|
||||||
/// representation.
|
/// representation.
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct VText {
|
pub struct VText {
|
||||||
/// Contains a text of the node.
|
/// Contains a text of the node.
|
||||||
pub text: String,
|
pub text: String,
|
||||||
|
|||||||
@ -4,8 +4,9 @@ use yew::prelude::*;
|
|||||||
|
|
||||||
mod t1 {
|
mod t1 {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
#[derive(Clone)]
|
||||||
struct Value;
|
struct Value;
|
||||||
#[derive(Properties)]
|
#[derive(Clone, Properties)]
|
||||||
pub struct Props {
|
pub struct Props {
|
||||||
// ERROR: optional params must implement default
|
// ERROR: optional params must implement default
|
||||||
value: Value,
|
value: Value,
|
||||||
@ -14,7 +15,7 @@ mod t1 {
|
|||||||
|
|
||||||
mod t2 {
|
mod t2 {
|
||||||
use super::*;
|
use super::*;
|
||||||
#[derive(Properties)]
|
#[derive(Clone, Properties)]
|
||||||
pub struct Props {
|
pub struct Props {
|
||||||
// ERROR: optional is not a tag
|
// ERROR: optional is not a tag
|
||||||
#[props(optional)]
|
#[props(optional)]
|
||||||
@ -24,7 +25,7 @@ mod t2 {
|
|||||||
|
|
||||||
mod t3 {
|
mod t3 {
|
||||||
use super::*;
|
use super::*;
|
||||||
#[derive(Properties)]
|
#[derive(Clone, Properties)]
|
||||||
pub struct Props {
|
pub struct Props {
|
||||||
#[props(required)]
|
#[props(required)]
|
||||||
value: String,
|
value: String,
|
||||||
@ -37,7 +38,7 @@ mod t3 {
|
|||||||
|
|
||||||
mod t4 {
|
mod t4 {
|
||||||
use super::*;
|
use super::*;
|
||||||
#[derive(Properties)]
|
#[derive(Clone, Properties)]
|
||||||
pub struct Props {
|
pub struct Props {
|
||||||
b: i32,
|
b: i32,
|
||||||
#[props(required)]
|
#[props(required)]
|
||||||
|
|||||||
@ -1,31 +1,31 @@
|
|||||||
error: expected `props(required)`
|
error: expected `props(required)`
|
||||||
--> $DIR/fail.rs:20:11
|
--> $DIR/fail.rs:21:11
|
||||||
|
|
|
|
||||||
20 | #[props(optional)]
|
21 | #[props(optional)]
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
||||||
error[E0277]: the trait bound `t1::Value: std::default::Default` is not satisfied
|
error[E0277]: the trait bound `t1::Value: std::default::Default` is not satisfied
|
||||||
--> $DIR/fail.rs:8:14
|
--> $DIR/fail.rs:9:21
|
||||||
|
|
|
|
||||||
8 | #[derive(Properties)]
|
9 | #[derive(Clone, Properties)]
|
||||||
| ^^^^^^^^^^ the trait `std::default::Default` is not implemented for `t1::Value`
|
| ^^^^^^^^^^ the trait `std::default::Default` is not implemented for `t1::Value`
|
||||||
|
|
|
|
||||||
= note: required by `std::default::Default::default`
|
= note: required by `std::default::Default::default`
|
||||||
|
|
||||||
error[E0599]: no method named `build` found for type `t3::PropsBuilder<t3::PropsBuilderStep_missing_required_prop_value>` in the current scope
|
error[E0599]: no method named `build` found for type `t3::PropsBuilder<t3::PropsBuilderStep_missing_required_prop_value>` in the current scope
|
||||||
--> $DIR/fail.rs:34:26
|
--> $DIR/fail.rs:35:26
|
||||||
|
|
|
|
||||||
27 | #[derive(Properties)]
|
28 | #[derive(Clone, Properties)]
|
||||||
| - method `build` not found for this
|
| - method `build` not found for this
|
||||||
...
|
...
|
||||||
34 | Props::builder().build();
|
35 | Props::builder().build();
|
||||||
| ^^^^^ method not found in `t3::PropsBuilder<t3::PropsBuilderStep_missing_required_prop_value>`
|
| ^^^^^ method not found in `t3::PropsBuilder<t3::PropsBuilderStep_missing_required_prop_value>`
|
||||||
|
|
||||||
error[E0599]: no method named `b` found for type `t4::PropsBuilder<t4::PropsBuilderStep_missing_required_prop_a>` in the current scope
|
error[E0599]: no method named `b` found for type `t4::PropsBuilder<t4::PropsBuilderStep_missing_required_prop_a>` in the current scope
|
||||||
--> $DIR/fail.rs:48:26
|
--> $DIR/fail.rs:49:26
|
||||||
|
|
|
|
||||||
40 | #[derive(Properties)]
|
41 | #[derive(Clone, Properties)]
|
||||||
| - method `b` not found for this
|
| - method `b` not found for this
|
||||||
...
|
...
|
||||||
48 | Props::builder().b(1).a(2).build();
|
49 | Props::builder().b(1).a(2).build();
|
||||||
| ^ help: there is a method with a similar name: `a`
|
| ^ help: there is a method with a similar name: `a`
|
||||||
|
|||||||
@ -5,8 +5,8 @@ use yew::prelude::*;
|
|||||||
mod t1 {
|
mod t1 {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[derive(Properties)]
|
#[derive(Clone, Properties)]
|
||||||
pub struct Props<T: Default> {
|
pub struct Props<T: Clone + Default> {
|
||||||
value: T,
|
value: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -19,9 +19,10 @@ mod t1 {
|
|||||||
mod t2 {
|
mod t2 {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
struct Value;
|
struct Value;
|
||||||
#[derive(Properties)]
|
#[derive(Clone, Properties)]
|
||||||
pub struct Props<T> {
|
pub struct Props<T: Clone> {
|
||||||
#[props(required)]
|
#[props(required)]
|
||||||
value: T,
|
value: T,
|
||||||
}
|
}
|
||||||
@ -34,7 +35,7 @@ mod t2 {
|
|||||||
mod t3 {
|
mod t3 {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[derive(Properties)]
|
#[derive(Clone, Properties)]
|
||||||
pub struct Props {
|
pub struct Props {
|
||||||
#[props(required)]
|
#[props(required)]
|
||||||
b: i32,
|
b: i32,
|
||||||
@ -50,10 +51,10 @@ mod t3 {
|
|||||||
mod t4 {
|
mod t4 {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[derive(Properties)]
|
#[derive(Clone, Properties)]
|
||||||
pub struct Props<T>
|
pub struct Props<T>
|
||||||
where
|
where
|
||||||
T: Default,
|
T: Clone + Default,
|
||||||
{
|
{
|
||||||
value: T,
|
value: T,
|
||||||
}
|
}
|
||||||
@ -67,8 +68,8 @@ mod t4 {
|
|||||||
mod t5 {
|
mod t5 {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[derive(Properties)]
|
#[derive(Clone, Properties)]
|
||||||
pub struct Props<'a, T: Default + 'a> {
|
pub struct Props<'a, T: Clone + Default + 'a> {
|
||||||
static_value: &'static str,
|
static_value: &'static str,
|
||||||
#[props(required)]
|
#[props(required)]
|
||||||
value: &'a T,
|
value: &'a T,
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
|
|
||||||
#[derive(Properties, PartialEq)]
|
#[derive(Clone, Properties, PartialEq)]
|
||||||
pub struct ChildProperties {
|
pub struct ChildProperties {
|
||||||
pub string: String,
|
pub string: String,
|
||||||
#[props(required)]
|
#[props(required)]
|
||||||
@ -27,7 +27,7 @@ impl Component for Child {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Properties)]
|
#[derive(Clone, Properties)]
|
||||||
pub struct ChildContainerProperties {
|
pub struct ChildContainerProperties {
|
||||||
pub children: ChildrenWithProps<Child>,
|
pub children: ChildrenWithProps<Child>,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -109,8 +109,8 @@ error[E0609]: no field `unknown` on type `ChildProperties`
|
|||||||
error[E0599]: no method named `unknown` found for type `ChildPropertiesBuilder<ChildPropertiesBuilderStep_missing_required_prop_int>` in the current scope
|
error[E0599]: no method named `unknown` found for type `ChildPropertiesBuilder<ChildPropertiesBuilderStep_missing_required_prop_int>` in the current scope
|
||||||
--> $DIR/html-component-fail.rs:65:20
|
--> $DIR/html-component-fail.rs:65:20
|
||||||
|
|
|
|
||||||
5 | #[derive(Properties, PartialEq)]
|
5 | #[derive(Clone, Properties, PartialEq)]
|
||||||
| - method `unknown` not found for this
|
| - method `unknown` not found for this
|
||||||
...
|
...
|
||||||
65 | html! { <Child unknown="unknown" /> };
|
65 | html! { <Child unknown="unknown" /> };
|
||||||
| ^^^^^^^ method not found in `ChildPropertiesBuilder<ChildPropertiesBuilderStep_missing_required_prop_int>`
|
| ^^^^^^^ method not found in `ChildPropertiesBuilder<ChildPropertiesBuilderStep_missing_required_prop_int>`
|
||||||
@ -170,8 +170,8 @@ help: you can convert an `u32` to `i32` and panic if the converted value wouldn'
|
|||||||
error[E0599]: no method named `string` found for type `ChildPropertiesBuilder<ChildPropertiesBuilderStep_missing_required_prop_int>` in the current scope
|
error[E0599]: no method named `string` found for type `ChildPropertiesBuilder<ChildPropertiesBuilderStep_missing_required_prop_int>` in the current scope
|
||||||
--> $DIR/html-component-fail.rs:73:20
|
--> $DIR/html-component-fail.rs:73:20
|
||||||
|
|
|
|
||||||
5 | #[derive(Properties, PartialEq)]
|
5 | #[derive(Clone, Properties, PartialEq)]
|
||||||
| - method `string` not found for this
|
| - method `string` not found for this
|
||||||
...
|
...
|
||||||
73 | html! { <Child string="abc" /> };
|
73 | html! { <Child string="abc" /> };
|
||||||
| ^^^^^^ method not found in `ChildPropertiesBuilder<ChildPropertiesBuilderStep_missing_required_prop_int>`
|
| ^^^^^^ method not found in `ChildPropertiesBuilder<ChildPropertiesBuilderStep_missing_required_prop_int>`
|
||||||
@ -179,8 +179,8 @@ error[E0599]: no method named `string` found for type `ChildPropertiesBuilder<Ch
|
|||||||
error[E0599]: no method named `children` found for type `ChildPropertiesBuilder<ChildPropertiesBuilderStep_missing_required_prop_int>` in the current scope
|
error[E0599]: no method named `children` found for type `ChildPropertiesBuilder<ChildPropertiesBuilderStep_missing_required_prop_int>` in the current scope
|
||||||
--> $DIR/html-component-fail.rs:77:5
|
--> $DIR/html-component-fail.rs:77:5
|
||||||
|
|
|
|
||||||
5 | #[derive(Properties, PartialEq)]
|
5 | #[derive(Clone, Properties, PartialEq)]
|
||||||
| - method `children` not found for this
|
| - method `children` not found for this
|
||||||
...
|
...
|
||||||
77 | html! { <Child>{ "Not allowed" }</Child> };
|
77 | html! { <Child>{ "Not allowed" }</Child> };
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ method not found in `ChildPropertiesBuilder<ChildPropertiesBuilderStep_missing_required_prop_int>`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ method not found in `ChildPropertiesBuilder<ChildPropertiesBuilderStep_missing_required_prop_int>`
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
use yew::html::ChildrenRenderer;
|
use yew::html::ChildrenRenderer;
|
||||||
|
|
||||||
#[derive(Properties, Default, PartialEq)]
|
#[derive(Clone, Properties, Default, PartialEq)]
|
||||||
pub struct ChildProperties {
|
pub struct ChildProperties {
|
||||||
pub string: String,
|
pub string: String,
|
||||||
#[props(required)]
|
#[props(required)]
|
||||||
@ -30,7 +30,7 @@ impl Component for Child {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Properties, Default)]
|
#[derive(Clone, Properties, Default)]
|
||||||
pub struct ContainerProperties {
|
pub struct ContainerProperties {
|
||||||
#[props(required)]
|
#[props(required)]
|
||||||
pub int: i32,
|
pub int: i32,
|
||||||
@ -55,7 +55,7 @@ impl Component for Container {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Properties, Default)]
|
#[derive(Clone, Properties, Default)]
|
||||||
pub struct ChildContainerProperties {
|
pub struct ChildContainerProperties {
|
||||||
#[props(required)]
|
#[props(required)]
|
||||||
pub int: i32,
|
pub int: i32,
|
||||||
@ -165,12 +165,7 @@ fn compile_pass() {
|
|||||||
</scoped::Container>
|
</scoped::Container>
|
||||||
|
|
||||||
<Container int=1 children=ChildrenRenderer::new(
|
<Container int=1 children=ChildrenRenderer::new(
|
||||||
1,
|
vec![html!{ "String" }]
|
||||||
::std::boxed::Box::new(move || {
|
|
||||||
|| -> ::std::vec::Vec<_> {
|
|
||||||
vec![html!{ "String" }]
|
|
||||||
}
|
|
||||||
}()),
|
|
||||||
) />
|
) />
|
||||||
</>
|
</>
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
|
|
||||||
#[derive(Properties, PartialEq)]
|
#[derive(Clone, Properties, PartialEq)]
|
||||||
pub struct TestProperties {
|
pub struct TestProperties {
|
||||||
pub string: String,
|
pub string: String,
|
||||||
pub int: i32,
|
pub int: i32,
|
||||||
|
|||||||
@ -8,7 +8,7 @@ wasm_bindgen_test_configure!(run_in_browser);
|
|||||||
|
|
||||||
struct Comp;
|
struct Comp;
|
||||||
|
|
||||||
#[derive(PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
struct Props {
|
struct Props {
|
||||||
field_1: u32,
|
field_1: u32,
|
||||||
field_2: u32,
|
field_2: u32,
|
||||||
@ -33,19 +33,19 @@ impl Component for Comp {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn set_properties_to_component() {
|
fn set_properties_to_component() {
|
||||||
let _ = html! {
|
html! {
|
||||||
<Comp />
|
<Comp />
|
||||||
};
|
};
|
||||||
|
|
||||||
let _ = html! {
|
html! {
|
||||||
<Comp field_1=1 />
|
<Comp field_1=1 />
|
||||||
};
|
};
|
||||||
|
|
||||||
let _ = html! {
|
html! {
|
||||||
<Comp field_2=2 />
|
<Comp field_2=2 />
|
||||||
};
|
};
|
||||||
|
|
||||||
let _ = html! {
|
html! {
|
||||||
<Comp field_1=1 field_2=2 />
|
<Comp field_1=1 field_2=2 />
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -54,7 +54,7 @@ fn set_properties_to_component() {
|
|||||||
field_2: 1,
|
field_2: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
let _ = html! {
|
html! {
|
||||||
<Comp with props />
|
<Comp with props />
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user