Skip to content

Commit

Permalink
Make virtual dom cloneable (yewstack#786)
Browse files Browse the repository at this point in the history
  • Loading branch information
jstarry authored and llebout committed Jan 20, 2020
1 parent b96a62f commit 2329dee
Show file tree
Hide file tree
Showing 31 changed files with 274 additions and 176 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ Properties are also pure Rust types with strict type-checking during the compila
```rust
// my_button.rs

#[derive(Properties, PartialEq)]
#[derive(Clone, Properties, PartialEq)]
pub struct Properties {
pub hidden: bool,
#[props(required)]
Expand Down
9 changes: 1 addition & 8 deletions crates/macro/src/html_tree/html_component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,16 +119,9 @@ impl ToTokens for HtmlComponent {
};

let set_children = if !children.is_empty() {
let children_len = children.len();
quote! {
.children(::yew::html::ChildrenRenderer::new(
#children_len,
::std::boxed::Box::new(move || {
#[allow(unused_must_use)]
|| -> ::std::vec::Vec<_> {
vec![#(#children.into(),)*]
}
}()),
vec![#(#children.into(),)*]
))
}
} else {
Expand Down
2 changes: 1 addition & 1 deletion crates/macro/src/html_tree/html_tag/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ impl ToTokens for HtmlTag {
#(#set_classes)*
#(#set_node_ref)*
#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),*]);
::yew::virtual_dom::VNode::from(#vtag)
}});
Expand Down
2 changes: 1 addition & 1 deletion crates/macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
//! link: ComponentLink<Self>,
//! }
//!
//! #[derive(Properties)]
//! #[derive(Clone, Properties)]
//! struct Props {
//! #[props(required)]
//! prop: String,
Expand Down
2 changes: 1 addition & 1 deletion examples/custom_components/src/barrier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub enum Msg {
ChildClicked,
}

#[derive(PartialEq, Properties)]
#[derive(Clone, PartialEq, Properties)]
pub struct Props {
pub limit: u32,
#[props(required)]
Expand Down
2 changes: 1 addition & 1 deletion examples/custom_components/src/button.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub enum Msg {
Clicked,
}

#[derive(PartialEq, Properties)]
#[derive(Clone, PartialEq, Properties)]
pub struct Props {
pub title: String,
#[props(required)]
Expand Down
2 changes: 1 addition & 1 deletion examples/custom_components/src/counter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ pub enum Msg {
Increase,
}

#[derive(PartialEq, Properties)]
#[derive(Clone, PartialEq, Properties)]
pub struct Props {
pub initial: u32,
pub color: Color,
Expand Down
2 changes: 2 additions & 0 deletions examples/nested_list/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ authors = ["Justin Starry <[email protected]>"]
edition = "2018"

[dependencies]
log = "0.4"
web_logger = "0.2"
yew = { path = "../.." }
77 changes: 77 additions & 0 deletions examples/nested_list/src/app.rs
Original file line number Diff line number Diff line change
@@ -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>
}
}
}
11 changes: 8 additions & 3 deletions examples/nested_list/src/header.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
use crate::Hovered;
use super::list::{List, Msg as ListMsg};
use super::{Hovered, WeakComponentLink};
use yew::prelude::*;

pub struct ListHeader {
props: Props,
}

#[derive(Properties)]
#[derive(Clone, Properties)]
pub struct Props {
#[props(required)]
pub on_hover: Callback<Hovered>,
#[props(required)]
pub text: String,
#[props(required)]
pub list_link: WeakComponentLink<List>,
}

impl Component for ListHeader {
Expand All @@ -26,9 +29,11 @@ impl Component for ListHeader {
}

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);
html! {
<div class="list-header" onmouseover=onmouseover>
<div class="list-header" onmouseover=onmouseover onclick=onclick>
{ &self.props.text }
</div>
}
Expand Down
7 changes: 5 additions & 2 deletions examples/nested_list/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pub struct ListItem {
props: Props,
}

#[derive(Properties)]
#[derive(Clone, Properties)]
pub struct Props {
pub hide: bool,
#[props(required)]
Expand All @@ -30,7 +30,10 @@ impl Component for ListItem {

fn view(&self) -> Html {
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! {
<div class="list-item" onmouseover=onmouseover>
{ &self.props.name }
Expand Down
71 changes: 7 additions & 64 deletions examples/nested_list/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
#![recursion_limit = "128"]
#![recursion_limit = "512"]

mod app;
mod header;
mod item;
mod list;

use header::ListHeader;
use item::ListItem;
use list::List;
use yew::prelude::*;
pub use app::App;
use std::cell::RefCell;
use std::fmt;

pub struct Model {
link: ComponentLink<Self>,
hovered: Hovered,
}
use std::rc::Rc;
use yew::html::ComponentLink;
pub type WeakComponentLink<COMP> = Rc<RefCell<Option<ComponentLink<COMP>>>>;

#[derive(Debug)]
pub enum Hovered {
Expand All @@ -23,60 +20,6 @@ pub enum Hovered {
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 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
Expand Down
39 changes: 29 additions & 10 deletions examples/nested_list/src/list.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use crate::{header::Props as HeaderProps, ListHeader};
use crate::{item::Props as ItemProps, ListItem};
use crate::Hovered;
use super::{Hovered, WeakComponentLink};
use crate::{header::ListHeader, header::Props as HeaderProps};
use crate::{item::ListItem, item::Props as ItemProps};
use yew::html::{ChildrenRenderer, NodeRef};
use yew::prelude::*;
use yew::virtual_dom::{VChild, VComp, VNode};

#[derive(Clone)]
pub enum Variants {
Item(<ListItem as Component>::Properties),
Header(<ListHeader as Component>::Properties),
Expand All @@ -22,40 +23,58 @@ impl From<HeaderProps> for Variants {
}
}

#[derive(Clone)]
pub struct ListVariant {
props: Variants,
}

#[derive(Properties)]
#[derive(Clone, Properties)]
pub struct Props {
#[props(required)]
pub children: ChildrenRenderer<ListVariant>,
#[props(required)]
pub on_hover: Callback<Hovered>,
#[props(required)]
pub weak_link: WeakComponentLink<List>,
}

pub struct List {
props: Props,
inactive: bool,
}

pub enum Msg {
HeaderClick,
}

impl Component for List {
type Message = ();
type Message = Msg;
type Properties = Props;

fn create(props: Self::Properties, _: ComponentLink<Self>) -> Self {
List { props }
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
*props.weak_link.borrow_mut() = Some(link);
List {
props,
inactive: false,
}
}

fn update(&mut self, _msg: Self::Message) -> ShouldRender {
false
fn update(&mut self, msg: Self::Message) -> ShouldRender {
match msg {
Msg::HeaderClick => {
self.inactive = !self.inactive;
true
}
}
}

fn view(&self) -> Html {
let inactive = if self.inactive { "inactive" } else { "" };
let onmouseover = self.props.on_hover.reform(|_| Hovered::List);
let onmouseout = self.props.on_hover.reform(|_| Hovered::None);
html! {
<div class="list-container" onmouseout=onmouseout onmouseover=onmouseover>
<div class="list">
<div class=vec!["list", inactive]>
{self.view_header()}
<div class="items">
{self.view_items()}
Expand Down
3 changes: 2 additions & 1 deletion examples/nested_list/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
fn main() {
yew::start_app::<nested_list::Model>();
web_logger::init();
yew::start_app::<nested_list::App>();
}
Loading

0 comments on commit 2329dee

Please sign in to comment.