mirror of
https://github.com/yewstack/yew.git
synced 2025-12-08 21:26:25 +00:00
Remove generics from virtual dom (#783)
* Fix tests * Remove generics from virtual dom * Prep for degenerify * Fix examples * Remove props cloning * Fix tests
This commit is contained in:
parent
def59a0079
commit
f61667be97
@ -89,7 +89,7 @@ impl Component for Model {
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
let onclick = self.link.callback(|_| Msg::DoIt);
|
||||
html! {
|
||||
// Render your model here
|
||||
@ -323,8 +323,8 @@ Use external crates and put values from them into the template:
|
||||
extern crate chrono;
|
||||
use chrono::prelude::*;
|
||||
|
||||
impl Renderable<Model> for Model {
|
||||
fn render(&self) -> Html<Self> {
|
||||
impl Renderable for Model {
|
||||
fn render(&self) -> Html {
|
||||
html! {
|
||||
<p>{ Local::now() }</p>
|
||||
}
|
||||
|
||||
@ -83,7 +83,6 @@ impl ToTokens for HtmlComponent {
|
||||
props,
|
||||
children,
|
||||
} = self;
|
||||
let vcomp_scope = Ident::new("__yew_vcomp_scope", Span::call_site());
|
||||
|
||||
let validate_props = if let Props::List(ListProps { props, .. }) = props {
|
||||
let prop_ref = Ident::new("__yew_prop_ref", Span::call_site());
|
||||
@ -139,9 +138,11 @@ impl ToTokens for HtmlComponent {
|
||||
let init_props = match props {
|
||||
Props::List(ListProps { props, .. }) => {
|
||||
let set_props = props.iter().map(|HtmlProp { label, value }| {
|
||||
quote_spanned! { value.span()=>
|
||||
.#label(<::yew::virtual_dom::vcomp::VComp<_> as ::yew::virtual_dom::Transformer<_, _, _>>::transform(#vcomp_scope.clone(), #value))
|
||||
}
|
||||
quote_spanned! { value.span()=> .#label(
|
||||
<::yew::virtual_dom::vcomp::VComp as ::yew::virtual_dom::Transformer<_, _>>::transform(
|
||||
#value
|
||||
)
|
||||
)}
|
||||
});
|
||||
|
||||
quote! {
|
||||
@ -181,9 +182,7 @@ impl ToTokens for HtmlComponent {
|
||||
#validate_props
|
||||
}
|
||||
|
||||
let #vcomp_scope: ::yew::html::ScopeHolder<_> = ::std::default::Default::default();
|
||||
let __yew_node_ref: ::yew::html::NodeRef = #node_ref;
|
||||
::yew::virtual_dom::VChild::<#ty, _>::new(#init_props, #vcomp_scope, __yew_node_ref)
|
||||
::yew::virtual_dom::VChild::<#ty>::new(#init_props, #node_ref)
|
||||
}});
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,18 +49,12 @@ impl Parse for HtmlPropSuffix {
|
||||
if let TokenTree::Punct(punct) = &next {
|
||||
match punct.as_char() {
|
||||
'>' => {
|
||||
let possible_tag_end = input.peek(Token![<])
|
||||
|| input.peek(syn::token::Brace)
|
||||
|| input.is_empty();
|
||||
|
||||
if angle_count > 1 || possible_tag_end {
|
||||
angle_count -= 1;
|
||||
if angle_count == 0 {
|
||||
gt = Some(syn::token::Gt {
|
||||
spans: [punct.span()],
|
||||
});
|
||||
break;
|
||||
}
|
||||
angle_count -= 1;
|
||||
if angle_count == 0 {
|
||||
gt = Some(syn::token::Gt {
|
||||
spans: [punct.span()],
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
'<' => angle_count += 1,
|
||||
@ -73,14 +67,6 @@ impl Parse for HtmlPropSuffix {
|
||||
break;
|
||||
}
|
||||
}
|
||||
'-' => {
|
||||
if input.peek(Token![>]) {
|
||||
// Handle explicit return types in callbacks (#560)
|
||||
// We increase angle_count here in order to ignore
|
||||
// the following >.
|
||||
angle_count += 1;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
|
||||
@ -102,7 +102,6 @@ impl ToTokens for HtmlTag {
|
||||
} = &attributes;
|
||||
|
||||
let vtag = Ident::new("__yew_vtag", tag_name.span());
|
||||
let vtag_scope = Ident::new("__yew_vtag_scope", Span::call_site());
|
||||
let attr_pairs = attributes.iter().map(|TagAttribute { label, value }| {
|
||||
let label_str = label.to_string();
|
||||
quote_spanned! {value.span() => (#label_str.to_owned(), (#value).to_string()) }
|
||||
@ -155,16 +154,15 @@ impl ToTokens for HtmlTag {
|
||||
|
||||
quote_spanned! {name.span()=> {
|
||||
::yew::html::#name::Wrapper::new(
|
||||
<::yew::virtual_dom::vtag::VTag<_> as ::yew::virtual_dom::Transformer<_, _, _>>::transform(
|
||||
#vtag_scope.clone(), #callback
|
||||
<::yew::virtual_dom::vtag::VTag as ::yew::virtual_dom::Transformer<_, _>>::transform(
|
||||
#callback
|
||||
)
|
||||
)
|
||||
}}
|
||||
});
|
||||
|
||||
tokens.extend(quote! {{
|
||||
let #vtag_scope: ::yew::html::ScopeHolder<_> = ::std::default::Default::default();
|
||||
let mut #vtag = ::yew::virtual_dom::vtag::VTag::new_with_scope(#name, #vtag_scope.clone());
|
||||
let mut #vtag = ::yew::virtual_dom::vtag::VTag::new(#name);
|
||||
#(#set_kind)*
|
||||
#(#set_value)*
|
||||
#(#add_href)*
|
||||
|
||||
@ -32,7 +32,7 @@
|
||||
//! # unimplemented!()
|
||||
//! # }
|
||||
//! #
|
||||
//! # fn view(&self) -> Html<Self> {
|
||||
//! # fn view(&self) -> Html {
|
||||
//! #
|
||||
//! // ...
|
||||
//!
|
||||
|
||||
@ -48,7 +48,7 @@ impl Component for Model {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<nav class="menu">
|
||||
|
||||
@ -146,7 +146,7 @@ impl Component for Model {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
match self.scene {
|
||||
Scene::ClientsList => html! {
|
||||
<div class="crm">
|
||||
@ -179,8 +179,8 @@ impl Component for Model {
|
||||
}
|
||||
}
|
||||
|
||||
impl Renderable<Model> for Client {
|
||||
fn render(&self) -> Html<Model> {
|
||||
impl Renderable for Client {
|
||||
fn render(&self) -> Html {
|
||||
html! {
|
||||
<div class="client">
|
||||
<p>{ format!("First Name: {}", self.first_name) }</p>
|
||||
@ -193,7 +193,7 @@ impl Renderable<Model> for Client {
|
||||
}
|
||||
|
||||
impl Client {
|
||||
fn view_first_name_input(&self, link: &ComponentLink<Model>) -> Html<Model> {
|
||||
fn view_first_name_input(&self, link: &ComponentLink<Model>) -> Html {
|
||||
html! {
|
||||
<input class="new-client firstname"
|
||||
placeholder="First name"
|
||||
@ -202,7 +202,7 @@ impl Client {
|
||||
}
|
||||
}
|
||||
|
||||
fn view_last_name_input(&self, link: &ComponentLink<Model>) -> Html<Model> {
|
||||
fn view_last_name_input(&self, link: &ComponentLink<Model>) -> Html {
|
||||
html! {
|
||||
<input class="new-client lastname"
|
||||
placeholder="Last name"
|
||||
@ -210,7 +210,7 @@ impl Client {
|
||||
oninput=link.callback(|e: InputData| Msg::UpdateLastName(e.value)) />
|
||||
}
|
||||
}
|
||||
fn view_description_textarea(&self, link: &ComponentLink<Model>) -> Html<Model> {
|
||||
fn view_description_textarea(&self, link: &ComponentLink<Model>) -> Html {
|
||||
html! {
|
||||
<textarea class=("new-client", "description")
|
||||
placeholder="Description"
|
||||
|
||||
@ -2,14 +2,11 @@
|
||||
/// Source: https://github.com/acmumn/mentoring/blob/master/web-client/src/view/markdown.rs
|
||||
use pulldown_cmark::{Alignment, Event, Parser, Tag, OPTION_ENABLE_TABLES};
|
||||
use yew::virtual_dom::{VNode, VTag, VText};
|
||||
use yew::{html, Component, Html};
|
||||
use yew::{html, Html};
|
||||
|
||||
/// Renders a string of Markdown to HTML with the default options (footnotes
|
||||
/// disabled, tables enabled).
|
||||
pub fn render_markdown<COMP>(src: &str) -> Html<COMP>
|
||||
where
|
||||
COMP: Component,
|
||||
{
|
||||
pub fn render_markdown(src: &str) -> Html {
|
||||
let mut elems = vec![];
|
||||
let mut spine = vec![];
|
||||
|
||||
@ -81,10 +78,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn make_tag<COMP>(t: Tag) -> VTag<COMP>
|
||||
where
|
||||
COMP: Component,
|
||||
{
|
||||
fn make_tag(t: Tag) -> VTag {
|
||||
match t {
|
||||
Tag::Paragraph => VTag::new("p"),
|
||||
Tag::Rule => VTag::new("hr"),
|
||||
|
||||
@ -51,7 +51,7 @@ impl Component for Barrier {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
let onsignal = &self.link.callback(|_| Msg::ChildClicked);
|
||||
html! {
|
||||
<div class="barrier">
|
||||
|
||||
@ -44,7 +44,7 @@ impl Component for Button {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<button onclick=self.link.callback(|_| Msg::Clicked)>
|
||||
{ &self.title }
|
||||
|
||||
@ -61,7 +61,7 @@ impl Component for Counter {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
let colorize = {
|
||||
match self.color {
|
||||
Color::Red => "background: red;",
|
||||
|
||||
@ -46,7 +46,7 @@ impl Component for Model {
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
let counter = |x| {
|
||||
html! {
|
||||
<Counter initial=x color=&self.color
|
||||
@ -64,7 +64,7 @@ impl Component for Model {
|
||||
}
|
||||
|
||||
impl Model {
|
||||
fn view_barrier(&self) -> Html<Self> {
|
||||
fn view_barrier(&self) -> Html {
|
||||
if self.with_barrier {
|
||||
html! {
|
||||
<Barrier limit=10 onsignal=self.link.callback(|_| Msg::Repaint) />
|
||||
|
||||
@ -169,7 +169,7 @@ impl Component for Model {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<nav class="menu">
|
||||
@ -206,7 +206,7 @@ impl Component for Model {
|
||||
}
|
||||
|
||||
impl Model {
|
||||
fn view_data(&self) -> Html<Self> {
|
||||
fn view_data(&self) -> Html {
|
||||
if let Some(value) = self.data {
|
||||
html! {
|
||||
<p>{ value }</p>
|
||||
|
||||
@ -65,7 +65,7 @@ impl Component for Model {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
let flag = self.by_chunks;
|
||||
html! {
|
||||
<div>
|
||||
@ -91,7 +91,7 @@ impl Component for Model {
|
||||
}
|
||||
|
||||
impl Model {
|
||||
fn view_file(&self, data: &str) -> Html<Self> {
|
||||
fn view_file(&self, data: &str) -> Html {
|
||||
html! {
|
||||
<li>{ data }</li>
|
||||
}
|
||||
|
||||
@ -34,7 +34,7 @@ impl Component for Model {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<>
|
||||
<nav class="menu">{ self.view_menu() }</nav>
|
||||
@ -54,7 +54,7 @@ impl Component for Model {
|
||||
}
|
||||
|
||||
impl Model {
|
||||
fn view_cols(&self) -> Html<Self> {
|
||||
fn view_cols(&self) -> Html {
|
||||
let render = |idx| {
|
||||
html! {
|
||||
<td>{ idx }</td>
|
||||
@ -65,7 +65,7 @@ impl Model {
|
||||
}
|
||||
}
|
||||
|
||||
fn view_menu(&self) -> Html<Self> {
|
||||
fn view_menu(&self) -> Html {
|
||||
html! {
|
||||
<>
|
||||
<button onclick=self.link.callback(|_| Msg::More)>{ "More" }</button>
|
||||
|
||||
@ -100,7 +100,7 @@ impl Component for Model {
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
match &self.markdown {
|
||||
FetchState::NotFetching => html! {
|
||||
<button onclick=self.link.callback(|_| Msg::GetMarkdown)>
|
||||
|
||||
@ -208,7 +208,7 @@ impl Component for Model {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<section class="game-container">
|
||||
@ -241,7 +241,7 @@ impl Component for Model {
|
||||
}
|
||||
|
||||
impl Model {
|
||||
fn view_cellule(&self, (idx, cellule): (usize, &Cellule)) -> Html<Self> {
|
||||
fn view_cellule(&self, (idx, cellule): (usize, &Cellule)) -> Html {
|
||||
let cellule_status = {
|
||||
if cellule.life_state == LifeState::Alive {
|
||||
"cellule-live"
|
||||
|
||||
@ -33,7 +33,7 @@ impl Component for Model {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
let js_svg = js! {
|
||||
var div = document.createElement("div");
|
||||
div.innerHTML = @{SVG.to_string()};
|
||||
|
||||
@ -53,7 +53,7 @@ impl Component for Model {
|
||||
false
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<textarea oninput=|input| Msg::Payload(input.value)
|
||||
|
||||
@ -33,17 +33,17 @@ impl Component for Model {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<table>
|
||||
{ (0..99).map(|row| self.view_row(row)).collect::<Html<Self>>() }
|
||||
{ (0..99).map(|row| self.view_row(row)).collect::<Html>() }
|
||||
</table>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Model {
|
||||
fn view_square(&self, row: u32, column: u32) -> Html<Self> {
|
||||
fn view_square(&self, row: u32, column: u32) -> Html {
|
||||
html! {
|
||||
<td class=square_class((column, row), self.selected)
|
||||
onclick=self.link.callback(move |_| Msg::Select(column, row))>
|
||||
@ -51,7 +51,7 @@ impl Model {
|
||||
}
|
||||
}
|
||||
|
||||
fn view_row(&self, row: u32) -> Html<Self> {
|
||||
fn view_row(&self, row: u32) -> Html {
|
||||
html! {
|
||||
<tr>
|
||||
{for (0..99).map(|column| {
|
||||
|
||||
@ -23,7 +23,7 @@ impl Component for Model {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<button onclick=self.link.callback(|_| Msg::Click)>{ "Click" }</button>
|
||||
|
||||
@ -29,7 +29,7 @@ impl Component for Model {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<input
|
||||
|
||||
@ -68,7 +68,7 @@ impl Component for Model {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<nav class="menu">
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use crate::list::Hovered;
|
||||
use crate::Hovered;
|
||||
use yew::prelude::*;
|
||||
|
||||
pub struct ListHeader {
|
||||
@ -13,30 +13,22 @@ pub struct Props {
|
||||
pub text: String,
|
||||
}
|
||||
|
||||
pub enum Msg {
|
||||
Hover,
|
||||
}
|
||||
|
||||
impl Component for ListHeader {
|
||||
type Message = Msg;
|
||||
type Message = ();
|
||||
type Properties = Props;
|
||||
|
||||
fn create(props: Self::Properties, _: ComponentLink<Self>) -> Self {
|
||||
ListHeader { props }
|
||||
}
|
||||
|
||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||
match msg {
|
||||
Msg::Hover => {
|
||||
self.props.on_hover.emit(Hovered::Header);
|
||||
}
|
||||
}
|
||||
fn update(&mut self, _: Self::Message) -> ShouldRender {
|
||||
false
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
let onmouseover = self.props.on_hover.reform(|_| Hovered::Header);
|
||||
html! {
|
||||
<div class="list-header" onmouseover=|_| Msg::Hover>
|
||||
<div class="list-header" onmouseover=onmouseover>
|
||||
{ &self.props.text }
|
||||
</div>
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use crate::list::Hovered;
|
||||
use crate::Hovered;
|
||||
use yew::html::Children;
|
||||
use yew::prelude::*;
|
||||
|
||||
@ -13,35 +13,26 @@ pub struct Props {
|
||||
pub on_hover: Callback<Hovered>,
|
||||
#[props(required)]
|
||||
pub name: String,
|
||||
pub children: Children<ListItem>,
|
||||
}
|
||||
|
||||
pub enum Msg {
|
||||
Hover,
|
||||
pub children: Children,
|
||||
}
|
||||
|
||||
impl Component for ListItem {
|
||||
type Message = Msg;
|
||||
type Message = ();
|
||||
type Properties = Props;
|
||||
|
||||
fn create(props: Self::Properties, _: ComponentLink<Self>) -> Self {
|
||||
ListItem { props }
|
||||
}
|
||||
|
||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||
match msg {
|
||||
Msg::Hover => {
|
||||
self.props
|
||||
.on_hover
|
||||
.emit(Hovered::Item(self.props.name.clone()));
|
||||
}
|
||||
}
|
||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||
false
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
let name = self.props.name.clone();
|
||||
let onmouseover = self.props.on_hover.reform(move |_| Hovered::Item(name.clone()));
|
||||
html! {
|
||||
<div class="list-item" onmouseover=|_| Msg::Hover>
|
||||
<div class="list-item" onmouseover=onmouseover>
|
||||
{ &self.props.name }
|
||||
{ self.view_details() }
|
||||
</div>
|
||||
@ -50,7 +41,7 @@ impl Component for ListItem {
|
||||
}
|
||||
|
||||
impl ListItem {
|
||||
fn view_details(&self) -> Html<Self> {
|
||||
fn view_details(&self) -> Html {
|
||||
if self.props.children.is_empty() {
|
||||
return html! {};
|
||||
}
|
||||
|
||||
@ -6,36 +6,88 @@ mod list;
|
||||
|
||||
use header::ListHeader;
|
||||
use item::ListItem;
|
||||
use list::{List, Msg as ListMsg};
|
||||
use list::List;
|
||||
use yew::prelude::*;
|
||||
use std::fmt;
|
||||
|
||||
pub struct Model;
|
||||
pub struct Model {
|
||||
link: ComponentLink<Self>,
|
||||
hovered: Hovered,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Hovered {
|
||||
Header,
|
||||
Item(String),
|
||||
List,
|
||||
None,
|
||||
}
|
||||
|
||||
pub enum Msg {
|
||||
Hover(Hovered),
|
||||
}
|
||||
|
||||
impl Component for Model {
|
||||
type Message = ();
|
||||
type Message = Msg;
|
||||
type Properties = ();
|
||||
|
||||
fn create(_: Self::Properties, _: ComponentLink<Self>) -> Self {
|
||||
Model
|
||||
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
Model { link,
|
||||
hovered: Hovered::None,
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, _: Self::Message) -> ShouldRender {
|
||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||
match msg {
|
||||
Msg::Hover(hovered) => self.hovered = hovered,
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
let on_hover = self.link.callback(Msg::Hover);
|
||||
|
||||
html! {
|
||||
<div class="main">
|
||||
<h1>{ "Nested List Demo" }</h1>
|
||||
<List>
|
||||
<ListHeader text="Calling all Rusties!" on_hover=ListMsg::Hover />
|
||||
<ListItem name="Rustin" on_hover=ListMsg::Hover />
|
||||
<ListItem hide={true} name="Rustaroo" on_hover=ListMsg::Hover />
|
||||
<ListItem name="Rustifer" on_hover=ListMsg::Hover>
|
||||
<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!(
|
||||
f,
|
||||
"{}",
|
||||
match self {
|
||||
Hovered::Header => "Header",
|
||||
Hovered::Item(name) => name,
|
||||
Hovered::List => "List container",
|
||||
Hovered::None => "Nothing",
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,22 +1,10 @@
|
||||
use crate::{header::Props as HeaderProps, ListHeader};
|
||||
use crate::{item::Props as ItemProps, ListItem};
|
||||
use std::fmt;
|
||||
use yew::html::{ChildrenRenderer, NodeRef, ScopeHolder};
|
||||
use crate::Hovered;
|
||||
use yew::html::{ChildrenRenderer, NodeRef};
|
||||
use yew::prelude::*;
|
||||
use yew::virtual_dom::{VChild, VComp, VNode};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Hovered {
|
||||
Header,
|
||||
Item(String),
|
||||
List,
|
||||
None,
|
||||
}
|
||||
|
||||
pub enum Msg {
|
||||
Hover(Hovered),
|
||||
}
|
||||
|
||||
pub enum Variants {
|
||||
Item(<ListItem as Component>::Properties),
|
||||
Header(<ListHeader as Component>::Properties),
|
||||
@ -36,59 +24,50 @@ impl From<HeaderProps> for Variants {
|
||||
|
||||
pub struct ListVariant {
|
||||
props: Variants,
|
||||
scope: ScopeHolder<List>,
|
||||
}
|
||||
|
||||
#[derive(Properties)]
|
||||
pub struct Props {
|
||||
#[props(required)]
|
||||
pub children: ChildrenRenderer<ListVariant>,
|
||||
#[props(required)]
|
||||
pub on_hover: Callback<Hovered>,
|
||||
}
|
||||
|
||||
pub struct List {
|
||||
props: Props,
|
||||
hovered: Hovered,
|
||||
}
|
||||
|
||||
impl Component for List {
|
||||
type Message = Msg;
|
||||
type Message = ();
|
||||
type Properties = Props;
|
||||
|
||||
fn create(props: Self::Properties, _: ComponentLink<Self>) -> Self {
|
||||
List {
|
||||
props,
|
||||
hovered: Hovered::None,
|
||||
}
|
||||
List { props }
|
||||
}
|
||||
|
||||
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||
match msg {
|
||||
Msg::Hover(hovered) => self.hovered = hovered,
|
||||
}
|
||||
true
|
||||
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||
false
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
let onmouseover = self.props.on_hover.reform(|_| Hovered::List);
|
||||
let onmouseout = self.props.on_hover.reform(|_| Hovered::None);
|
||||
html! {
|
||||
<div
|
||||
class="list-container"
|
||||
onmouseout=|_| Msg::Hover(Hovered::None)
|
||||
onmouseover=|_| Msg::Hover(Hovered::List)
|
||||
>
|
||||
<div class="list-container" onmouseout=onmouseout onmouseover=onmouseover>
|
||||
<div class="list">
|
||||
{self.view_header()}
|
||||
<div class="items">
|
||||
{self.view_items()}
|
||||
</div>
|
||||
</div>
|
||||
{self.view_last_hovered()}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl List {
|
||||
fn view_header(&self) -> Html<Self> {
|
||||
fn view_header(&self) -> Html {
|
||||
html! {{
|
||||
for self.props.children.iter().filter(|c| match c.props {
|
||||
Variants::Header(_) => true,
|
||||
@ -97,7 +76,7 @@ impl List {
|
||||
}}
|
||||
}
|
||||
|
||||
fn view_items(&self) -> Html<Self> {
|
||||
fn view_items(&self) -> Html {
|
||||
html! {{
|
||||
for self.props.children.iter().filter(|c| match &c.props {
|
||||
Variants::Item(props) => !props.hide,
|
||||
@ -110,52 +89,25 @@ impl List {
|
||||
})
|
||||
}}
|
||||
}
|
||||
|
||||
fn view_last_hovered(&self) -> Html<Self> {
|
||||
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!(
|
||||
f,
|
||||
"{}",
|
||||
match self {
|
||||
Hovered::Header => "Header",
|
||||
Hovered::Item(name) => name,
|
||||
Hovered::List => "List container",
|
||||
Hovered::None => "Nothing",
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<CHILD> From<VChild<CHILD, List>> for ListVariant
|
||||
impl<CHILD> From<VChild<CHILD>> for ListVariant
|
||||
where
|
||||
CHILD: Component,
|
||||
CHILD::Properties: Into<Variants>,
|
||||
{
|
||||
fn from(vchild: VChild<CHILD, List>) -> Self {
|
||||
fn from(vchild: VChild<CHILD>) -> Self {
|
||||
ListVariant {
|
||||
props: vchild.props.into(),
|
||||
scope: vchild.scope,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<VNode<List>> for ListVariant {
|
||||
fn into(self) -> VNode<List> {
|
||||
impl Into<VNode> for ListVariant {
|
||||
fn into(self) -> VNode {
|
||||
match self.props {
|
||||
Variants::Header(props) => VComp::new::<ListHeader>(props, self.scope, NodeRef::default()).into(),
|
||||
Variants::Item(props) => VComp::new::<ListItem>(props, self.scope, NodeRef::default()).into(),
|
||||
Variants::Header(props) => VComp::new::<ListHeader>(props, NodeRef::default()).into(),
|
||||
Variants::Item(props) => VComp::new::<ListItem>(props, NodeRef::default()).into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,7 +32,7 @@ impl Component for InputComponent {
|
||||
false
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<input
|
||||
type="text"
|
||||
|
||||
@ -46,7 +46,7 @@ impl Component for Model {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<div class="main">
|
||||
<h1>{ "Node Refs Demo" }</h1>
|
||||
|
||||
@ -67,7 +67,7 @@ impl Component for Model {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
let view_exchange = |exchange| {
|
||||
html! {
|
||||
<li>{ exchange }</li>
|
||||
|
||||
@ -108,7 +108,7 @@ impl Component for BModel {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<div>
|
||||
@ -132,7 +132,7 @@ impl BModel {
|
||||
format!("Number: None")
|
||||
}
|
||||
}
|
||||
fn display_subpath_input(&self) -> Html<Self> {
|
||||
fn display_subpath_input(&self) -> Html {
|
||||
let sub_path = self.sub_path.clone();
|
||||
html! {
|
||||
<input placeholder="subpath"
|
||||
|
||||
@ -68,7 +68,7 @@ impl Component for Model {
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<nav class="menu">
|
||||
@ -83,8 +83,8 @@ impl Component for Model {
|
||||
}
|
||||
}
|
||||
|
||||
impl Renderable<Model> for Child {
|
||||
fn render(&self) -> Html<Model> {
|
||||
impl Renderable for Child {
|
||||
fn render(&self) -> Html {
|
||||
match self {
|
||||
Child::A => html! {
|
||||
<>
|
||||
|
||||
@ -71,7 +71,7 @@ impl Component for RouterButton {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<button
|
||||
class=self.props.classes.clone(),
|
||||
|
||||
@ -68,7 +68,7 @@ impl Component for Model {
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<div id="fullscreen">
|
||||
<div id="left_pane">
|
||||
@ -87,7 +87,7 @@ impl Component for Model {
|
||||
}
|
||||
|
||||
impl Model {
|
||||
fn view_scene(&self) -> Html<Self> {
|
||||
fn view_scene(&self) -> Html {
|
||||
if let Some(scene) = self.scene.as_ref() {
|
||||
match scene {
|
||||
Scene::Counter => html! { <Counter /> },
|
||||
|
||||
@ -35,7 +35,7 @@ impl Component for Model {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<div>
|
||||
|
||||
@ -99,7 +99,7 @@ impl Component for Model {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
let view_message = |message| {
|
||||
html! { <p>{ message }</p> }
|
||||
};
|
||||
|
||||
@ -121,7 +121,7 @@ impl Component for Model {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<div class="todomvc-wrapper">
|
||||
<section class="todoapp">
|
||||
@ -163,7 +163,7 @@ impl Component for Model {
|
||||
}
|
||||
|
||||
impl Model {
|
||||
fn view_filter(&self, filter: Filter) -> Html<Self> {
|
||||
fn view_filter(&self, filter: Filter) -> Html {
|
||||
let flt = filter.clone();
|
||||
html! {
|
||||
<li>
|
||||
@ -176,7 +176,7 @@ impl Model {
|
||||
}
|
||||
}
|
||||
|
||||
fn view_input(&self) -> Html<Self> {
|
||||
fn view_input(&self) -> Html {
|
||||
html! {
|
||||
// You can use standard Rust comments. One line:
|
||||
// <li></li>
|
||||
@ -195,7 +195,7 @@ impl Model {
|
||||
}
|
||||
}
|
||||
|
||||
fn view_entry(&self, (idx, entry): (usize, &Entry)) -> Html<Self> {
|
||||
fn view_entry(&self, (idx, entry): (usize, &Entry)) -> Html {
|
||||
let mut class = "todo".to_string();
|
||||
if entry.editing {
|
||||
class.push_str(" editing");
|
||||
@ -219,7 +219,7 @@ impl Model {
|
||||
}
|
||||
}
|
||||
|
||||
fn view_entry_edit_input(&self, (idx, entry): (usize, &Entry)) -> Html<Self> {
|
||||
fn view_entry_edit_input(&self, (idx, entry): (usize, &Entry)) -> Html {
|
||||
if entry.editing {
|
||||
html! {
|
||||
<input class="edit"
|
||||
|
||||
@ -69,7 +69,7 @@ impl Component for Model {
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<h3>{ format!("{} received <{}>", self.selector, self.title) }</h3>
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
//!# type Message = ();type Properties = ();
|
||||
//!# fn create(props: Self::Properties,link: ComponentLink<Self>) -> Self {unimplemented!()}
|
||||
//!# fn update(&mut self,msg: Self::Message) -> bool {unimplemented!()}
|
||||
//!# fn view(&self) -> Html<Self> {unimplemented!()}}
|
||||
//!# fn view(&self) -> Html {unimplemented!()}}
|
||||
//! impl ToString for Scene {
|
||||
//! fn to_string(&self) -> String {
|
||||
//! match self {
|
||||
@ -24,7 +24,7 @@
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! fn view(link: ComponentLink<Model>) -> Html<Model> {
|
||||
//! fn view(link: ComponentLink<Model>) -> Html {
|
||||
//! let scenes = vec![Scene::First, Scene::Second];
|
||||
//! html! {
|
||||
//! <Select<Scene> options=scenes onchange=link.callback(|_| ()) />
|
||||
@ -94,7 +94,7 @@ where
|
||||
true
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
let selected = self.props.selected.as_ref();
|
||||
let view_option = |value: &T| {
|
||||
let flag = selected == Some(value);
|
||||
|
||||
@ -51,13 +51,13 @@ pub trait Component: Sized + 'static {
|
||||
TypeId::of::<Self::Properties>() != TypeId::of::<()>()
|
||||
}
|
||||
/// Called by rendering loop.
|
||||
fn view(&self) -> Html<Self>;
|
||||
fn view(&self) -> Html;
|
||||
/// Called for finalization on the final point of the component's lifetime.
|
||||
fn destroy(&mut self) {} // TODO Replace with `Drop`
|
||||
}
|
||||
|
||||
/// A type which expected as a result of `view` function implementation.
|
||||
pub type Html<MSG> = VNode<MSG>;
|
||||
pub type Html = VNode;
|
||||
|
||||
/// A type used for accepting children elements in Component::Properties.
|
||||
///
|
||||
@ -69,7 +69,7 @@ pub type Html<MSG> = VNode<MSG>;
|
||||
///# use yew::{Children, Html, Properties, Component, ComponentLink, html};
|
||||
///# #[derive(Properties)]
|
||||
///# struct WrapperProps {
|
||||
///# children: Children<Wrapper>,
|
||||
///# children: Children,
|
||||
///# }
|
||||
///# struct Wrapper;
|
||||
///# impl Component for Wrapper{
|
||||
@ -78,7 +78,7 @@ pub type Html<MSG> = VNode<MSG>;
|
||||
///# fn create(props: Self::Properties,link: ComponentLink<Self>) -> Self {unimplemented!()}
|
||||
///# fn update(&mut self,msg: Self::Message) -> bool {unimplemented!()}
|
||||
///# // This is not a valid implementation. This is done for space convenience.
|
||||
///# fn view(&self) -> Html<Self> {
|
||||
///# fn view(&self) -> Html {
|
||||
/// html! {
|
||||
/// <Wrapper>
|
||||
/// <h4>{ "Hi" }</h4>
|
||||
@ -97,7 +97,7 @@ pub type Html<MSG> = VNode<MSG>;
|
||||
///# use yew::{Children, Html, Properties, Renderable, Component, ComponentLink, html};
|
||||
/// #[derive(Properties)]
|
||||
/// struct WrapperProps {
|
||||
/// children: Children<Wrapper>,
|
||||
/// children: Children,
|
||||
/// }
|
||||
///
|
||||
///# struct Wrapper {props: WrapperProps};
|
||||
@ -107,7 +107,7 @@ pub type Html<MSG> = VNode<MSG>;
|
||||
///# type Properties = WrapperProps;
|
||||
///# fn create(props: Self::Properties,link: ComponentLink<Self>) -> Self {unimplemented!()}
|
||||
///# fn update(&mut self,msg: Self::Message) -> bool {unimplemented!()}
|
||||
/// fn view(&self) -> Html<Wrapper> {
|
||||
/// fn view(&self) -> Html {
|
||||
/// html! {
|
||||
/// <div id="container">
|
||||
/// { self.props.children.render() }
|
||||
@ -116,7 +116,7 @@ pub type Html<MSG> = VNode<MSG>;
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub type Children<T> = ChildrenRenderer<Html<T>>;
|
||||
pub type Children = ChildrenRenderer<Html>;
|
||||
|
||||
/// A type used for accepting children elements in Component::Properties and accessing their props.
|
||||
///
|
||||
@ -129,7 +129,7 @@ pub type Children<T> = ChildrenRenderer<Html<T>>;
|
||||
///#
|
||||
///# #[derive(Properties)]
|
||||
///# struct ListProps {
|
||||
///# children: ChildrenWithProps<ListItem, List>,
|
||||
///# children: ChildrenWithProps<ListItem>,
|
||||
///# }
|
||||
///# struct List;
|
||||
///# impl Component for List {
|
||||
@ -137,7 +137,7 @@ pub type Children<T> = ChildrenRenderer<Html<T>>;
|
||||
///# type Properties = ListProps;
|
||||
///# fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {unimplemented!()}
|
||||
///# fn update(&mut self, msg: Self::Message) -> bool {unimplemented!()}
|
||||
///# fn view(&self) -> Html<List> {unimplemented!()}
|
||||
///# fn view(&self) -> Html {unimplemented!()}
|
||||
///# }
|
||||
///# #[derive(Properties)]
|
||||
///# struct ListItemProps {
|
||||
@ -149,9 +149,9 @@ pub type Children<T> = ChildrenRenderer<Html<T>>;
|
||||
///# type Properties = ListItemProps;
|
||||
///# fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {unimplemented!()}
|
||||
///# fn update(&mut self, msg: Self::Message) -> bool {unimplemented!()}
|
||||
///# fn view(&self) -> Html<Self> {unimplemented!()}
|
||||
///# fn view(&self) -> Html {unimplemented!()}
|
||||
///# }
|
||||
///# fn view() -> Html<List> {
|
||||
///# fn view() -> Html {
|
||||
/// html!{
|
||||
/// <List>
|
||||
/// <ListItem value="a" />
|
||||
@ -171,7 +171,7 @@ pub type Children<T> = ChildrenRenderer<Html<T>>;
|
||||
///#
|
||||
/// #[derive(Properties)]
|
||||
/// struct ListProps {
|
||||
/// children: ChildrenWithProps<ListItem, List>,
|
||||
/// children: ChildrenWithProps<ListItem>,
|
||||
/// }
|
||||
///
|
||||
///# struct List {props: ListProps};
|
||||
@ -181,7 +181,7 @@ pub type Children<T> = ChildrenRenderer<Html<T>>;
|
||||
///# fn create(props: Self::Properties,link: ComponentLink<Self>) -> Self {unimplemented!()}
|
||||
///# fn update(&mut self,msg: Self::Message) -> bool {unimplemented!()}
|
||||
/// // ...
|
||||
/// fn view(&self) -> Html<Self> {
|
||||
/// fn view(&self) -> Html {
|
||||
/// html!{{
|
||||
/// for self.props.children.iter().map(|mut item| {
|
||||
/// item.props.value = format!("item-{}", item.props.value);
|
||||
@ -202,10 +202,10 @@ pub type Children<T> = ChildrenRenderer<Html<T>>;
|
||||
///# type Properties = ListItemProps;
|
||||
///# fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {unimplemented!()}
|
||||
///# fn update(&mut self, msg: Self::Message) -> bool {unimplemented!()}
|
||||
///# fn view(&self) -> Html<ListItem> {unimplemented!()}
|
||||
///# fn view(&self) -> Html {unimplemented!()}
|
||||
///# }
|
||||
/// ```
|
||||
pub type ChildrenWithProps<C, P> = ChildrenRenderer<VChild<C, P>>;
|
||||
pub type ChildrenWithProps<CHILD> = ChildrenRenderer<VChild<CHILD>>;
|
||||
|
||||
/// A type used for rendering children html.
|
||||
pub struct ChildrenRenderer<T> {
|
||||
@ -236,7 +236,7 @@ impl<T> ChildrenRenderer<T> {
|
||||
|
||||
/// Render children components and return `Iterator`
|
||||
pub fn iter(&self) -> impl Iterator<Item = T> {
|
||||
(&self.boxed_render)().into_iter()
|
||||
self.to_vec().into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
@ -245,6 +245,7 @@ impl<T> Default for ChildrenRenderer<T> {
|
||||
// False positive: https://github.com/rust-lang/rust-clippy/issues/4002
|
||||
#[allow(clippy::redundant_closure)]
|
||||
let boxed_render = Box::new(|| Vec::new());
|
||||
|
||||
Self {
|
||||
len: 0,
|
||||
boxed_render,
|
||||
@ -258,11 +259,11 @@ impl<T> fmt::Debug for ChildrenRenderer<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, COMP: Component> Renderable<COMP> for ChildrenRenderer<T>
|
||||
impl<T> Renderable for ChildrenRenderer<T>
|
||||
where
|
||||
T: Into<VNode<COMP>>,
|
||||
T: Into<VNode>,
|
||||
{
|
||||
fn render(&self) -> Html<COMP> {
|
||||
fn render(&self) -> Html {
|
||||
VList {
|
||||
no_siblings: true,
|
||||
children: self.iter().map(|c| c.into()).collect(),
|
||||
@ -305,7 +306,7 @@ where
|
||||
/// false
|
||||
/// }
|
||||
///
|
||||
/// fn view(&self) -> Html<Self> {
|
||||
/// fn view(&self) -> Html {
|
||||
/// html! {
|
||||
/// <input ref=self.node_ref.clone() type="text" />
|
||||
/// }
|
||||
@ -332,13 +333,13 @@ impl NodeRef {
|
||||
}
|
||||
|
||||
/// Trait for rendering virtual DOM elements
|
||||
pub trait Renderable<COMP: Component> {
|
||||
pub trait Renderable {
|
||||
/// Called by rendering loop.
|
||||
fn render(&self) -> Html<COMP>;
|
||||
fn render(&self) -> Html;
|
||||
}
|
||||
|
||||
impl<COMP: Component> Renderable<COMP> for COMP {
|
||||
fn render(&self) -> Html<COMP> {
|
||||
impl<COMP: Component> Renderable for COMP {
|
||||
fn render(&self) -> Html {
|
||||
self.view()
|
||||
}
|
||||
}
|
||||
@ -394,7 +395,7 @@ where
|
||||
let scope = self.scope.clone();
|
||||
let closure = move |input| {
|
||||
let messages = function(input);
|
||||
scope.clone().send_message_batch(messages);
|
||||
scope.send_message_batch(messages);
|
||||
};
|
||||
closure.into()
|
||||
}
|
||||
@ -431,6 +432,7 @@ where
|
||||
scope.send_message(future.await);
|
||||
Ok(JsValue::NULL)
|
||||
};
|
||||
|
||||
future_to_promise(js_future);
|
||||
}
|
||||
|
||||
|
||||
@ -55,14 +55,13 @@ impl<COMP: Component> Scope<COMP> {
|
||||
pub(crate) fn mount_in_place(
|
||||
self,
|
||||
element: Element,
|
||||
ancestor: Option<VNode<COMP>>,
|
||||
ancestor: Option<VNode>,
|
||||
node_ref: NodeRef,
|
||||
props: COMP::Properties,
|
||||
) -> Scope<COMP> {
|
||||
let mut scope = self.clone();
|
||||
let link = ComponentLink::connect(&scope);
|
||||
let ready_state = ReadyState {
|
||||
scope: self.clone(),
|
||||
element,
|
||||
node_ref,
|
||||
link,
|
||||
@ -138,19 +137,17 @@ impl<COMP: Component> fmt::Display for ComponentState<COMP> {
|
||||
}
|
||||
|
||||
struct ReadyState<COMP: Component> {
|
||||
scope: Scope<COMP>,
|
||||
element: Element,
|
||||
node_ref: NodeRef,
|
||||
props: COMP::Properties,
|
||||
link: ComponentLink<COMP>,
|
||||
ancestor: Option<VNode<COMP>>,
|
||||
ancestor: Option<VNode>,
|
||||
}
|
||||
|
||||
impl<COMP: Component> ReadyState<COMP> {
|
||||
fn create(self) -> CreatedState<COMP> {
|
||||
CreatedState {
|
||||
component: COMP::create(self.props, self.link),
|
||||
scope: self.scope,
|
||||
element: self.element,
|
||||
last_frame: self.ancestor,
|
||||
node_ref: self.node_ref,
|
||||
@ -159,10 +156,9 @@ impl<COMP: Component> ReadyState<COMP> {
|
||||
}
|
||||
|
||||
struct CreatedState<COMP: Component> {
|
||||
scope: Scope<COMP>,
|
||||
element: Element,
|
||||
component: COMP,
|
||||
last_frame: Option<VNode<COMP>>,
|
||||
last_frame: Option<VNode>,
|
||||
node_ref: NodeRef,
|
||||
}
|
||||
|
||||
@ -177,10 +173,10 @@ impl<COMP: Component> CreatedState<COMP> {
|
||||
}
|
||||
|
||||
fn update(mut self) -> Self {
|
||||
let mut next_frame = self.component.render();
|
||||
let node = next_frame.apply(&self.element, None, self.last_frame, &self.scope);
|
||||
let mut vnode = self.component.render();
|
||||
let node = vnode.apply(&self.element, None, self.last_frame);
|
||||
self.node_ref.set(node);
|
||||
self.last_frame = Some(next_frame);
|
||||
self.last_frame = Some(vnode);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
//! true
|
||||
//! }
|
||||
//!
|
||||
//! fn view(&self) -> Html<Self> {
|
||||
//! fn view(&self) -> Html {
|
||||
//! html! {
|
||||
//! <div>
|
||||
//! <button onclick=self.link.callback(|_| Msg::DoIt)>{ "+1" }</button>
|
||||
|
||||
@ -148,7 +148,7 @@ impl FetchService {
|
||||
///# type Message = Msg;type Properties = ();
|
||||
///# fn create(props: Self::Properties,link: ComponentLink<Self>) -> Self {unimplemented!()}
|
||||
///# fn update(&mut self,msg: Self::Message) -> bool {unimplemented!()}
|
||||
///# fn view(&self) -> Html<Comp> {unimplemented!()}
|
||||
///# fn view(&self) -> Html {unimplemented!()}
|
||||
///# }
|
||||
///# enum Msg {
|
||||
///# Noop,
|
||||
@ -187,7 +187,7 @@ impl FetchService {
|
||||
///# type Message = Msg;type Properties = ();
|
||||
///# fn create(props: Self::Properties,link: ComponentLink<Self>) -> Self {unimplemented!()}
|
||||
///# fn update(&mut self,msg: Self::Message) -> bool {unimplemented!()}
|
||||
///# fn view(&self) -> Html<Comp> {unimplemented!()}
|
||||
///# fn view(&self) -> Html {unimplemented!()}
|
||||
///# }
|
||||
///# enum Msg {
|
||||
///# FetchResourceComplete(Data),
|
||||
@ -240,7 +240,7 @@ impl FetchService {
|
||||
///# type Properties = ();
|
||||
///# fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {unimplemented!()}
|
||||
///# fn update(&mut self, msg: Self::Message) -> bool {unimplemented!()}
|
||||
///# fn view(&self) -> Html<Comp> {unimplemented!()}
|
||||
///# fn view(&self) -> Html {unimplemented!()}
|
||||
///# }
|
||||
///# pub enum Msg {}
|
||||
///# fn dont_execute() {
|
||||
|
||||
@ -16,7 +16,6 @@ pub use self::vlist::VList;
|
||||
pub use self::vnode::VNode;
|
||||
pub use self::vtag::VTag;
|
||||
pub use self::vtext::VText;
|
||||
use crate::html::{Component, Scope, ScopeHolder};
|
||||
|
||||
/// `Listener` trait is an universal implementation of an event listener
|
||||
/// which helps to bind Rust-listener to JS-listener (DOM).
|
||||
@ -165,9 +164,6 @@ enum Reform {
|
||||
|
||||
/// This trait provides features to update a tree by calculating a difference against another tree.
|
||||
pub trait VDiff {
|
||||
/// The component which this instance put into.
|
||||
type Component: Component;
|
||||
|
||||
/// Remove itself from parent and return the next sibling.
|
||||
fn detach(&mut self, parent: &Element) -> Option<Node>;
|
||||
|
||||
@ -196,13 +192,12 @@ pub trait VDiff {
|
||||
&mut self,
|
||||
parent: &Element,
|
||||
previous_sibling: Option<&Node>,
|
||||
ancestor: Option<VNode<Self::Component>>,
|
||||
parent_scope: &Scope<Self::Component>,
|
||||
ancestor: Option<VNode>,
|
||||
) -> Option<Node>;
|
||||
}
|
||||
|
||||
/// Transforms properties and attaches a parent scope holder to callbacks for sending messages.
|
||||
pub trait Transformer<PARENT: Component, FROM, TO> {
|
||||
/// Transform properties to the expected type.
|
||||
pub trait Transformer<FROM, TO> {
|
||||
/// Transforms one type to another.
|
||||
fn transform(scope_holder: ScopeHolder<PARENT>, from: FROM) -> TO;
|
||||
fn transform(from: FROM) -> TO;
|
||||
}
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
//! This module contains the implementation of a virtual component `VComp`.
|
||||
|
||||
use super::{Transformer, VDiff, VNode};
|
||||
use crate::callback::Callback;
|
||||
use crate::html::{Component, ComponentUpdate, HiddenScope, NodeRef, Scope, ScopeHolder};
|
||||
use crate::html::{Component, ComponentUpdate, HiddenScope, NodeRef, Scope};
|
||||
use std::any::TypeId;
|
||||
use std::cell::RefCell;
|
||||
use std::fmt;
|
||||
@ -10,7 +9,7 @@ use std::rc::Rc;
|
||||
use stdweb::web::{document, Element, INode, Node, TextNode};
|
||||
|
||||
/// The method generates an instance of a component.
|
||||
type Generator<PARENT> = dyn FnOnce(GeneratorType, Scope<PARENT>) -> Mounted;
|
||||
type Generator = dyn FnOnce(GeneratorType) -> Mounted;
|
||||
|
||||
/// Components can be generated by mounting or by overwriting an old component.
|
||||
enum GeneratorType {
|
||||
@ -19,56 +18,48 @@ enum GeneratorType {
|
||||
}
|
||||
|
||||
/// A virtual component.
|
||||
pub struct VComp<PARENT: Component> {
|
||||
pub struct VComp {
|
||||
type_id: TypeId,
|
||||
state: Rc<RefCell<MountState<PARENT>>>,
|
||||
state: Rc<RefCell<MountState>>,
|
||||
}
|
||||
|
||||
/// A virtual child component.
|
||||
pub struct VChild<SELF: Component, PARENT: Component> {
|
||||
pub struct VChild<COMP: Component> {
|
||||
/// The component properties
|
||||
pub props: SELF::Properties,
|
||||
/// The parent component scope
|
||||
pub scope: ScopeHolder<PARENT>,
|
||||
pub props: COMP::Properties,
|
||||
/// Reference to the mounted node
|
||||
node_ref: NodeRef,
|
||||
}
|
||||
|
||||
impl<SELF, PARENT> VChild<SELF, PARENT>
|
||||
impl<COMP> VChild<COMP>
|
||||
where
|
||||
SELF: Component,
|
||||
PARENT: Component,
|
||||
COMP: Component,
|
||||
{
|
||||
/// Creates a child component that can be accessed and modified by its parent.
|
||||
pub fn new(props: SELF::Properties, scope: ScopeHolder<PARENT>, node_ref: NodeRef) -> Self {
|
||||
Self {
|
||||
props,
|
||||
scope,
|
||||
node_ref,
|
||||
}
|
||||
pub fn new(props: COMP::Properties, node_ref: NodeRef) -> Self {
|
||||
Self { props, node_ref }
|
||||
}
|
||||
}
|
||||
|
||||
impl<SELF, PARENT> From<VChild<SELF, PARENT>> for VComp<PARENT>
|
||||
impl<COMP> From<VChild<COMP>> for VComp
|
||||
where
|
||||
SELF: Component,
|
||||
PARENT: Component,
|
||||
COMP: Component,
|
||||
{
|
||||
fn from(vchild: VChild<SELF, PARENT>) -> Self {
|
||||
VComp::new::<SELF>(vchild.props, vchild.scope, vchild.node_ref)
|
||||
fn from(vchild: VChild<COMP>) -> Self {
|
||||
VComp::new::<COMP>(vchild.props, vchild.node_ref)
|
||||
}
|
||||
}
|
||||
|
||||
enum MountState<PARENT: Component> {
|
||||
Unmounted(Unmounted<PARENT>),
|
||||
enum MountState {
|
||||
Unmounted(Unmounted),
|
||||
Mounted(Mounted),
|
||||
Mounting,
|
||||
Detached,
|
||||
Overwritten,
|
||||
}
|
||||
|
||||
struct Unmounted<PARENT: Component> {
|
||||
generator: Box<Generator<PARENT>>,
|
||||
struct Unmounted {
|
||||
generator: Box<Generator>,
|
||||
}
|
||||
|
||||
struct Mounted {
|
||||
@ -77,21 +68,16 @@ struct Mounted {
|
||||
destroyer: Box<dyn FnOnce()>,
|
||||
}
|
||||
|
||||
impl<PARENT: Component> VComp<PARENT> {
|
||||
impl VComp {
|
||||
/// This method prepares a generator to make a new instance of the `Component`.
|
||||
pub fn new<SELF>(
|
||||
props: SELF::Properties,
|
||||
scope_holder: ScopeHolder<PARENT>,
|
||||
node_ref: NodeRef,
|
||||
) -> Self
|
||||
pub fn new<COMP>(props: COMP::Properties, node_ref: NodeRef) -> Self
|
||||
where
|
||||
SELF: Component,
|
||||
COMP: Component,
|
||||
{
|
||||
let generator = move |generator_type: GeneratorType, parent: Scope<PARENT>| -> Mounted {
|
||||
*scope_holder.borrow_mut() = Some(parent);
|
||||
let generator = move |generator_type: GeneratorType| -> Mounted {
|
||||
match generator_type {
|
||||
GeneratorType::Mount(element, dummy_node) => {
|
||||
let scope: Scope<SELF> = Scope::new();
|
||||
let scope: Scope<COMP> = Scope::new();
|
||||
|
||||
let mut scope = scope.mount_in_place(
|
||||
element,
|
||||
@ -107,7 +93,7 @@ impl<PARENT: Component> VComp<PARENT> {
|
||||
}
|
||||
}
|
||||
GeneratorType::Overwrite(hidden_scope) => {
|
||||
let mut scope: Scope<SELF> = hidden_scope.into();
|
||||
let mut scope: Scope<COMP> = hidden_scope.into();
|
||||
scope.update(ComponentUpdate::Properties(props));
|
||||
|
||||
Mounted {
|
||||
@ -120,7 +106,7 @@ impl<PARENT: Component> VComp<PARENT> {
|
||||
};
|
||||
|
||||
VComp {
|
||||
type_id: TypeId::of::<SELF>(),
|
||||
type_id: TypeId::of::<COMP>(),
|
||||
state: Rc::new(RefCell::new(MountState::Unmounted(Unmounted {
|
||||
generator: Box::new(generator),
|
||||
}))),
|
||||
@ -128,71 +114,15 @@ impl<PARENT: Component> VComp<PARENT> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<PARENT, T> Transformer<PARENT, T, T> for VComp<PARENT>
|
||||
where
|
||||
PARENT: Component,
|
||||
{
|
||||
fn transform(_: ScopeHolder<PARENT>, from: T) -> T {
|
||||
from
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, PARENT, T> Transformer<PARENT, &'a T, T> for VComp<PARENT>
|
||||
where
|
||||
PARENT: Component,
|
||||
T: Clone,
|
||||
{
|
||||
fn transform(_: ScopeHolder<PARENT>, from: &'a T) -> T {
|
||||
from.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, PARENT> Transformer<PARENT, &'a str, String> for VComp<PARENT>
|
||||
where
|
||||
PARENT: Component,
|
||||
{
|
||||
fn transform(_: ScopeHolder<PARENT>, from: &'a str) -> String {
|
||||
from.to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, PARENT, F, IN> Transformer<PARENT, F, Callback<IN>> for VComp<PARENT>
|
||||
where
|
||||
PARENT: Component,
|
||||
F: Fn(IN) -> PARENT::Message + 'static,
|
||||
{
|
||||
fn transform(scope: ScopeHolder<PARENT>, from: F) -> Callback<IN> {
|
||||
let callback = move |arg| {
|
||||
let msg = from(arg);
|
||||
if let Some(ref mut sender) = *scope.borrow_mut() {
|
||||
sender.send_message(msg);
|
||||
} else {
|
||||
panic!("Parent component hasn't activated this callback yet");
|
||||
}
|
||||
};
|
||||
callback.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, PARENT, F, IN> Transformer<PARENT, F, Option<Callback<IN>>> for VComp<PARENT>
|
||||
where
|
||||
PARENT: Component,
|
||||
F: Fn(IN) -> PARENT::Message + 'static,
|
||||
{
|
||||
fn transform(scope: ScopeHolder<PARENT>, from: F) -> Option<Callback<IN>> {
|
||||
Some(VComp::<PARENT>::transform(scope, from))
|
||||
}
|
||||
}
|
||||
|
||||
impl<PARENT: Component> Unmounted<PARENT> {
|
||||
impl Unmounted {
|
||||
/// Mount a virtual component using a generator.
|
||||
fn mount(self, parent: Element, dummy_node: TextNode, parent_scope: Scope<PARENT>) -> Mounted {
|
||||
(self.generator)(GeneratorType::Mount(parent, dummy_node), parent_scope)
|
||||
fn mount(self, parent: Element, dummy_node: TextNode) -> Mounted {
|
||||
(self.generator)(GeneratorType::Mount(parent, dummy_node))
|
||||
}
|
||||
|
||||
/// Overwrite an existing virtual component using a generator.
|
||||
fn replace(self, old: Mounted, parent_scope: Scope<PARENT>) -> Mounted {
|
||||
(self.generator)(GeneratorType::Overwrite(old.scope), parent_scope)
|
||||
fn replace(self, old: Mounted) -> Mounted {
|
||||
(self.generator)(GeneratorType::Overwrite(old.scope))
|
||||
}
|
||||
}
|
||||
|
||||
@ -201,12 +131,8 @@ enum Reform {
|
||||
Before(Option<Node>),
|
||||
}
|
||||
|
||||
impl<COMP> VDiff for VComp<COMP>
|
||||
where
|
||||
COMP: Component + 'static,
|
||||
{
|
||||
type Component = COMP;
|
||||
|
||||
impl VDiff for VComp {
|
||||
/// Remove VComp from parent.
|
||||
fn detach(&mut self, parent: &Element) -> Option<Node> {
|
||||
match self.state.replace(MountState::Detached) {
|
||||
MountState::Mounted(this) => {
|
||||
@ -227,8 +153,7 @@ where
|
||||
&mut self,
|
||||
parent: &Element,
|
||||
previous_sibling: Option<&Node>,
|
||||
ancestor: Option<VNode<Self::Component>>,
|
||||
parent_scope: &Scope<Self::Component>,
|
||||
ancestor: Option<VNode>,
|
||||
) -> Option<Node> {
|
||||
match self.state.replace(MountState::Mounting) {
|
||||
MountState::Unmounted(this) => {
|
||||
@ -256,7 +181,7 @@ where
|
||||
let mounted = match reform {
|
||||
Reform::Keep(mounted) => {
|
||||
// Send properties update when the component is already rendered.
|
||||
this.replace(mounted, parent_scope.clone())
|
||||
this.replace(mounted)
|
||||
}
|
||||
Reform::Before(before) => {
|
||||
// Temporary node which will be replaced by a component's root node.
|
||||
@ -276,7 +201,7 @@ where
|
||||
parent.append_child(&dummy_node);
|
||||
}
|
||||
}
|
||||
this.mount(parent.to_owned(), dummy_node, parent_scope.clone())
|
||||
this.mount(parent.to_owned(), dummy_node)
|
||||
}
|
||||
};
|
||||
|
||||
@ -292,20 +217,41 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: Component> PartialEq for VComp<C> {
|
||||
fn eq(&self, other: &VComp<C>) -> bool {
|
||||
impl<T> Transformer<T, T> for VComp {
|
||||
fn transform(from: T) -> T {
|
||||
from
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Transformer<&'a T, T> for VComp
|
||||
where
|
||||
T: Clone,
|
||||
{
|
||||
fn transform(from: &'a T) -> T {
|
||||
from.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Transformer<&'a str, String> for VComp {
|
||||
fn transform(from: &'a str) -> String {
|
||||
from.to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for VComp {
|
||||
fn eq(&self, other: &VComp) -> bool {
|
||||
self.type_id == other.type_id
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: Component> fmt::Debug for VComp<C> {
|
||||
impl fmt::Debug for VComp {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str("VComp<_>")
|
||||
f.write_str("VComp")
|
||||
}
|
||||
}
|
||||
|
||||
impl<SELF: Component, PARENT: Component> fmt::Debug for VChild<SELF, PARENT> {
|
||||
impl<COMP: Component> fmt::Debug for VChild<COMP> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str("VChild<_,_>")
|
||||
f.write_str("VChild<_>")
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,45 +1,32 @@
|
||||
//! This module contains fragments implementation.
|
||||
use super::{VDiff, VNode, VText};
|
||||
use crate::html::{Component, Scope};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use stdweb::web::{Element, Node};
|
||||
|
||||
/// This struct represents a fragment of the Virtual DOM tree.
|
||||
#[derive(Debug)]
|
||||
pub struct VList<COMP: Component> {
|
||||
#[derive(Debug, PartialEq, Default)]
|
||||
pub struct VList {
|
||||
/// Whether the fragment has siblings or not.
|
||||
pub no_siblings: bool,
|
||||
/// The list of children nodes. Which also could have their own children.
|
||||
pub children: Vec<VNode<COMP>>,
|
||||
pub children: Vec<VNode>,
|
||||
}
|
||||
|
||||
impl<COMP: Component> Deref for VList<COMP> {
|
||||
type Target = Vec<VNode<COMP>>;
|
||||
impl Deref for VList {
|
||||
type Target = Vec<VNode>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.children
|
||||
}
|
||||
}
|
||||
|
||||
impl<COMP: Component> DerefMut for VList<COMP> {
|
||||
impl DerefMut for VList {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.children
|
||||
}
|
||||
}
|
||||
|
||||
impl<COMP: Component> PartialEq for VList<COMP> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.children == other.children
|
||||
}
|
||||
}
|
||||
|
||||
impl<COMP: Component> Default for VList<COMP> {
|
||||
fn default() -> Self {
|
||||
VList::new(false)
|
||||
}
|
||||
}
|
||||
|
||||
impl<COMP: Component> VList<COMP> {
|
||||
impl VList {
|
||||
/// Creates a new empty `VList` instance.
|
||||
pub fn new(no_siblings: bool) -> Self {
|
||||
VList {
|
||||
@ -49,14 +36,12 @@ impl<COMP: Component> VList<COMP> {
|
||||
}
|
||||
|
||||
/// Add `VNode` child.
|
||||
pub fn add_child(&mut self, child: VNode<COMP>) {
|
||||
pub fn add_child(&mut self, child: VNode) {
|
||||
self.children.push(child);
|
||||
}
|
||||
}
|
||||
|
||||
impl<COMP: Component> VDiff for VList<COMP> {
|
||||
type Component = COMP;
|
||||
|
||||
impl VDiff for VList {
|
||||
fn detach(&mut self, parent: &Element) -> Option<Node> {
|
||||
let mut last_sibling = None;
|
||||
for mut child in self.children.drain(..) {
|
||||
@ -69,8 +54,7 @@ impl<COMP: Component> VDiff for VList<COMP> {
|
||||
&mut self,
|
||||
parent: &Element,
|
||||
previous_sibling: Option<&Node>,
|
||||
ancestor: Option<VNode<Self::Component>>,
|
||||
parent_scope: &Scope<Self::Component>,
|
||||
ancestor: Option<VNode>,
|
||||
) -> Option<Node> {
|
||||
// Reuse previous_sibling, because fragment reuse parent
|
||||
let mut previous_sibling = previous_sibling.cloned();
|
||||
@ -105,16 +89,10 @@ impl<COMP: Component> VDiff for VList<COMP> {
|
||||
loop {
|
||||
match (lefts.next(), rights.next()) {
|
||||
(Some(left), Some(right)) => {
|
||||
previous_sibling = left.apply(
|
||||
parent,
|
||||
previous_sibling.as_ref(),
|
||||
Some(right),
|
||||
&parent_scope,
|
||||
);
|
||||
previous_sibling = left.apply(parent, previous_sibling.as_ref(), Some(right));
|
||||
}
|
||||
(Some(left), None) => {
|
||||
previous_sibling =
|
||||
left.apply(parent, previous_sibling.as_ref(), None, &parent_scope);
|
||||
previous_sibling = left.apply(parent, previous_sibling.as_ref(), None);
|
||||
}
|
||||
(None, Some(ref mut right)) => {
|
||||
right.detach(parent);
|
||||
|
||||
@ -1,29 +1,27 @@
|
||||
//! This module contains the implementation of abstract virtual node.
|
||||
|
||||
use super::{VChild, VComp, VDiff, VList, VTag, VText};
|
||||
use crate::html::{Component, Renderable, Scope};
|
||||
use crate::html::{Component, Renderable};
|
||||
use std::cmp::PartialEq;
|
||||
use std::fmt;
|
||||
use std::iter::FromIterator;
|
||||
use stdweb::web::{Element, INode, Node};
|
||||
|
||||
/// Bind virtual element to a DOM reference.
|
||||
pub enum VNode<COMP: Component> {
|
||||
pub enum VNode {
|
||||
/// A bind between `VTag` and `Element`.
|
||||
VTag(Box<VTag<COMP>>),
|
||||
VTag(Box<VTag>),
|
||||
/// A bind between `VText` and `TextNode`.
|
||||
VText(VText<COMP>),
|
||||
VText(VText),
|
||||
/// A bind between `VComp` and `Element`.
|
||||
VComp(VComp<COMP>),
|
||||
VComp(VComp),
|
||||
/// A holder for a list of other nodes.
|
||||
VList(VList<COMP>),
|
||||
VList(VList),
|
||||
/// A holder for any `Node` (necessary for replacing node).
|
||||
VRef(Node),
|
||||
}
|
||||
|
||||
impl<COMP: Component> VDiff for VNode<COMP> {
|
||||
type Component = COMP;
|
||||
|
||||
impl VDiff for VNode {
|
||||
/// Remove VNode from parent.
|
||||
fn detach(&mut self, parent: &Element) -> Option<Node> {
|
||||
match *self {
|
||||
@ -45,22 +43,13 @@ impl<COMP: Component> VDiff for VNode<COMP> {
|
||||
&mut self,
|
||||
parent: &Element,
|
||||
previous_sibling: Option<&Node>,
|
||||
ancestor: Option<VNode<Self::Component>>,
|
||||
parent_scope: &Scope<Self::Component>,
|
||||
ancestor: Option<VNode>,
|
||||
) -> Option<Node> {
|
||||
match *self {
|
||||
VNode::VTag(ref mut vtag) => {
|
||||
vtag.apply(parent, previous_sibling, ancestor, parent_scope)
|
||||
}
|
||||
VNode::VText(ref mut vtext) => {
|
||||
vtext.apply(parent, previous_sibling, ancestor, parent_scope)
|
||||
}
|
||||
VNode::VComp(ref mut vcomp) => {
|
||||
vcomp.apply(parent, previous_sibling, ancestor, parent_scope)
|
||||
}
|
||||
VNode::VList(ref mut vlist) => {
|
||||
vlist.apply(parent, previous_sibling, ancestor, parent_scope)
|
||||
}
|
||||
VNode::VTag(ref mut vtag) => vtag.apply(parent, previous_sibling, ancestor),
|
||||
VNode::VText(ref mut vtext) => vtext.apply(parent, previous_sibling, ancestor),
|
||||
VNode::VComp(ref mut vcomp) => vcomp.apply(parent, previous_sibling, ancestor),
|
||||
VNode::VList(ref mut vlist) => vlist.apply(parent, previous_sibling, ancestor),
|
||||
VNode::VRef(ref mut node) => {
|
||||
let sibling = match ancestor {
|
||||
Some(mut n) => n.detach(parent),
|
||||
@ -80,59 +69,58 @@ impl<COMP: Component> VDiff for VNode<COMP> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<COMP: Component> Default for VNode<COMP> {
|
||||
impl Default for VNode {
|
||||
fn default() -> Self {
|
||||
VNode::VList(VList::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<COMP: Component> From<VText<COMP>> for VNode<COMP> {
|
||||
fn from(vtext: VText<COMP>) -> Self {
|
||||
impl From<VText> for VNode {
|
||||
fn from(vtext: VText) -> Self {
|
||||
VNode::VText(vtext)
|
||||
}
|
||||
}
|
||||
|
||||
impl<COMP: Component> From<VList<COMP>> for VNode<COMP> {
|
||||
fn from(vlist: VList<COMP>) -> Self {
|
||||
impl From<VList> for VNode {
|
||||
fn from(vlist: VList) -> Self {
|
||||
VNode::VList(vlist)
|
||||
}
|
||||
}
|
||||
|
||||
impl<COMP: Component> From<VTag<COMP>> for VNode<COMP> {
|
||||
fn from(vtag: VTag<COMP>) -> Self {
|
||||
impl From<VTag> for VNode {
|
||||
fn from(vtag: VTag) -> Self {
|
||||
VNode::VTag(Box::new(vtag))
|
||||
}
|
||||
}
|
||||
|
||||
impl<COMP: Component> From<VComp<COMP>> for VNode<COMP> {
|
||||
fn from(vcomp: VComp<COMP>) -> Self {
|
||||
impl From<VComp> for VNode {
|
||||
fn from(vcomp: VComp) -> Self {
|
||||
VNode::VComp(vcomp)
|
||||
}
|
||||
}
|
||||
|
||||
impl<COMP, CHILD> From<VChild<CHILD, COMP>> for VNode<COMP>
|
||||
impl<COMP> From<VChild<COMP>> for VNode
|
||||
where
|
||||
COMP: Component,
|
||||
CHILD: Component,
|
||||
{
|
||||
fn from(vchild: VChild<CHILD, COMP>) -> Self {
|
||||
fn from(vchild: VChild<COMP>) -> Self {
|
||||
VNode::VComp(VComp::from(vchild))
|
||||
}
|
||||
}
|
||||
|
||||
impl<COMP: Component, T: ToString> From<T> for VNode<COMP> {
|
||||
impl<T: ToString> From<T> for VNode {
|
||||
fn from(value: T) -> Self {
|
||||
VNode::VText(VText::new(value.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, COMP: Component> From<&'a dyn Renderable<COMP>> for VNode<COMP> {
|
||||
fn from(value: &'a dyn Renderable<COMP>) -> Self {
|
||||
impl<'a> From<&'a dyn Renderable> for VNode {
|
||||
fn from(value: &'a dyn Renderable) -> Self {
|
||||
value.render()
|
||||
}
|
||||
}
|
||||
|
||||
impl<COMP: Component, A: Into<VNode<COMP>>> FromIterator<A> for VNode<COMP> {
|
||||
impl<A: Into<VNode>> FromIterator<A> for VNode {
|
||||
fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self {
|
||||
let vlist = iter.into_iter().fold(VList::default(), |mut acc, x| {
|
||||
acc.add_child(x.into());
|
||||
@ -142,7 +130,7 @@ impl<COMP: Component, A: Into<VNode<COMP>>> FromIterator<A> for VNode<COMP> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<COMP: Component> fmt::Debug for VNode<COMP> {
|
||||
impl fmt::Debug for VNode {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
VNode::VTag(ref vtag) => vtag.fmt(f),
|
||||
@ -154,8 +142,8 @@ impl<COMP: Component> fmt::Debug for VNode<COMP> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<COMP: Component> PartialEq for VNode<COMP> {
|
||||
fn eq(&self, other: &VNode<COMP>) -> bool {
|
||||
impl PartialEq for VNode {
|
||||
fn eq(&self, other: &VNode) -> bool {
|
||||
match (self, other) {
|
||||
(VNode::VTag(vtag_a), VNode::VTag(vtag_b)) => vtag_a == vtag_b,
|
||||
(VNode::VText(vtext_a), VNode::VText(vtext_b)) => vtext_a == vtext_b,
|
||||
|
||||
@ -3,8 +3,7 @@
|
||||
use super::{
|
||||
Attributes, Classes, Listener, Listeners, Patch, Reform, Transformer, VDiff, VList, VNode,
|
||||
};
|
||||
use crate::callback::Callback;
|
||||
use crate::html::{Component, NodeRef, Scope, ScopeHolder};
|
||||
use crate::html::NodeRef;
|
||||
use log::warn;
|
||||
use std::borrow::Cow;
|
||||
use std::cmp::PartialEq;
|
||||
@ -25,7 +24,7 @@ pub const HTML_NAMESPACE: &str = "http://www.w3.org/1999/xhtml";
|
||||
/// A type for a virtual
|
||||
/// [Element](https://developer.mozilla.org/en-US/docs/Web/API/Element)
|
||||
/// representation.
|
||||
pub struct VTag<PARENT: Component> {
|
||||
pub struct VTag {
|
||||
/// A tag of the element.
|
||||
tag: Cow<'static, str>,
|
||||
/// A reference to the `Element`.
|
||||
@ -35,7 +34,7 @@ pub struct VTag<PARENT: Component> {
|
||||
/// List of attributes.
|
||||
pub attributes: Attributes,
|
||||
/// List of children nodes
|
||||
pub children: VList<PARENT>,
|
||||
pub children: VList,
|
||||
/// List of attached classes.
|
||||
pub classes: Classes,
|
||||
/// Contains a value of an
|
||||
@ -55,22 +54,11 @@ pub struct VTag<PARENT: Component> {
|
||||
pub node_ref: NodeRef,
|
||||
/// Keeps handler for attached listeners to have an opportunity to drop them later.
|
||||
captured: Vec<EventListenerHandle>,
|
||||
/// Holds a reference to the parent component scope for callback activation.
|
||||
scope_holder: ScopeHolder<PARENT>,
|
||||
}
|
||||
|
||||
impl<PARENT: Component> VTag<PARENT> {
|
||||
impl VTag {
|
||||
/// 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 {
|
||||
Self::new_with_scope(tag, ScopeHolder::default())
|
||||
}
|
||||
|
||||
/// Creates a new `VTag` instance with `tag` name (cannot be changed later in DOM) and parent
|
||||
/// scope holder for callback activation.
|
||||
pub fn new_with_scope<S: Into<Cow<'static, str>>>(
|
||||
tag: S,
|
||||
scope_holder: ScopeHolder<PARENT>,
|
||||
) -> Self {
|
||||
VTag {
|
||||
tag: tag.into(),
|
||||
reference: None,
|
||||
@ -85,7 +73,6 @@ impl<PARENT: Component> VTag<PARENT> {
|
||||
// In HTML node `checked` attribute sets `defaultChecked` parameter,
|
||||
// but we use own field to control real `checked` parameter
|
||||
checked: false,
|
||||
scope_holder,
|
||||
}
|
||||
}
|
||||
|
||||
@ -95,12 +82,12 @@ impl<PARENT: Component> VTag<PARENT> {
|
||||
}
|
||||
|
||||
/// Add `VNode` child.
|
||||
pub fn add_child(&mut self, child: VNode<PARENT>) {
|
||||
pub fn add_child(&mut self, child: VNode) {
|
||||
self.children.add_child(child);
|
||||
}
|
||||
|
||||
/// Add multiple `VNode` children.
|
||||
pub fn add_children(&mut self, children: Vec<VNode<PARENT>>) {
|
||||
pub fn add_children(&mut self, children: Vec<VNode>) {
|
||||
for child in children {
|
||||
self.add_child(child);
|
||||
}
|
||||
@ -360,9 +347,7 @@ impl<PARENT: Component> VTag<PARENT> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<PARENT: Component> VDiff for VTag<PARENT> {
|
||||
type Component = PARENT;
|
||||
|
||||
impl VDiff for VTag {
|
||||
/// Remove VTag from parent.
|
||||
fn detach(&mut self, parent: &Element) -> Option<Node> {
|
||||
let node = self
|
||||
@ -386,8 +371,7 @@ impl<PARENT: Component> VDiff for VTag<PARENT> {
|
||||
&mut self,
|
||||
parent: &Element,
|
||||
previous_sibling: Option<&Node>,
|
||||
ancestor: Option<VNode<Self::Component>>,
|
||||
parent_scope: &Scope<Self::Component>,
|
||||
ancestor: Option<VNode>,
|
||||
) -> Option<Node> {
|
||||
assert!(
|
||||
self.reference.is_none(),
|
||||
@ -473,16 +457,9 @@ impl<PARENT: Component> VDiff for VTag<PARENT> {
|
||||
self.captured.push(handle);
|
||||
}
|
||||
|
||||
// Activate scope
|
||||
*self.scope_holder.borrow_mut() = Some(parent_scope.clone());
|
||||
|
||||
// Process children
|
||||
self.children.apply(
|
||||
&element,
|
||||
None,
|
||||
ancestor.map(|a| a.children.into()),
|
||||
parent_scope,
|
||||
);
|
||||
self.children
|
||||
.apply(&element, None, ancestor.map(|a| a.children.into()));
|
||||
|
||||
let node = self.reference.as_ref().map(|e| e.as_node().to_owned());
|
||||
self.node_ref.set(node.clone());
|
||||
@ -490,7 +467,7 @@ impl<PARENT: Component> VDiff for VTag<PARENT> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<PARENT: Component> fmt::Debug for VTag<PARENT> {
|
||||
impl fmt::Debug for VTag {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "VTag {{ tag: {} }}", self.tag)
|
||||
}
|
||||
@ -512,8 +489,8 @@ fn set_checked(input: &InputElement, value: bool) {
|
||||
js!( @(no_return) @{input}.checked = @{value}; );
|
||||
}
|
||||
|
||||
impl<PARENT: Component> PartialEq for VTag<PARENT> {
|
||||
fn eq(&self, other: &VTag<PARENT>) -> bool {
|
||||
impl PartialEq for VTag {
|
||||
fn eq(&self, other: &VTag) -> bool {
|
||||
self.tag == other.tag
|
||||
&& self.value == other.value
|
||||
&& self.kind == other.kind
|
||||
@ -539,39 +516,17 @@ pub(crate) fn not<T>(option: &Option<T>) -> &Option<()> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<PARENT, T> Transformer<PARENT, T, T> for VTag<PARENT>
|
||||
where
|
||||
PARENT: Component,
|
||||
{
|
||||
fn transform(_: ScopeHolder<PARENT>, from: T) -> T {
|
||||
impl<T> Transformer<T, T> for VTag {
|
||||
fn transform(from: T) -> T {
|
||||
from
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, PARENT, T> Transformer<PARENT, &'a T, T> for VTag<PARENT>
|
||||
impl<'a, T> Transformer<&'a T, T> for VTag
|
||||
where
|
||||
PARENT: Component,
|
||||
T: Clone,
|
||||
{
|
||||
fn transform(_: ScopeHolder<PARENT>, from: &'a T) -> T {
|
||||
fn transform(from: &'a T) -> T {
|
||||
from.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, PARENT, F, IN> Transformer<PARENT, F, Callback<IN>> for VTag<PARENT>
|
||||
where
|
||||
PARENT: Component,
|
||||
F: Fn(IN) -> PARENT::Message + 'static,
|
||||
{
|
||||
fn transform(scope: ScopeHolder<PARENT>, from: F) -> Callback<IN> {
|
||||
let callback = move |arg| {
|
||||
let msg = from(arg);
|
||||
if let Some(ref mut sender) = *scope.borrow_mut() {
|
||||
sender.send_message(msg);
|
||||
} else {
|
||||
panic!("Parent component hasn't activated this callback yet");
|
||||
}
|
||||
};
|
||||
callback.into()
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,38 +1,32 @@
|
||||
//! This module contains the implementation of a virtual text node `VText`.
|
||||
|
||||
use super::{Reform, VDiff, VNode};
|
||||
use crate::html::{Component, Scope};
|
||||
use log::warn;
|
||||
use std::cmp::PartialEq;
|
||||
use std::fmt;
|
||||
use std::marker::PhantomData;
|
||||
use stdweb::web::{document, Element, INode, Node, TextNode};
|
||||
|
||||
/// A type for a virtual
|
||||
/// [`TextNode`](https://developer.mozilla.org/en-US/docs/Web/API/Document/createTextNode)
|
||||
/// representation.
|
||||
pub struct VText<COMP: Component> {
|
||||
pub struct VText {
|
||||
/// Contains a text of the node.
|
||||
pub text: String,
|
||||
/// A reference to the `TextNode`.
|
||||
pub reference: Option<TextNode>,
|
||||
_comp: PhantomData<COMP>,
|
||||
}
|
||||
|
||||
impl<COMP: Component> VText<COMP> {
|
||||
impl VText {
|
||||
/// Creates new virtual text node with a content.
|
||||
pub fn new(text: String) -> Self {
|
||||
VText {
|
||||
text,
|
||||
reference: None,
|
||||
_comp: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<COMP: Component> VDiff for VText<COMP> {
|
||||
type Component = COMP;
|
||||
|
||||
impl VDiff for VText {
|
||||
/// Remove VText from parent.
|
||||
fn detach(&mut self, parent: &Element) -> Option<Node> {
|
||||
let node = self
|
||||
@ -51,8 +45,7 @@ impl<COMP: Component> VDiff for VText<COMP> {
|
||||
&mut self,
|
||||
parent: &Element,
|
||||
previous_sibling: Option<&Node>,
|
||||
ancestor: Option<VNode<Self::Component>>,
|
||||
_: &Scope<Self::Component>,
|
||||
ancestor: Option<VNode>,
|
||||
) -> Option<Node> {
|
||||
assert!(
|
||||
self.reference.is_none(),
|
||||
@ -101,14 +94,14 @@ impl<COMP: Component> VDiff for VText<COMP> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<COMP: Component> fmt::Debug for VText<COMP> {
|
||||
impl fmt::Debug for VText {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "VText {{ text: {} }}", self.text)
|
||||
}
|
||||
}
|
||||
|
||||
impl<COMP: Component> PartialEq for VText<COMP> {
|
||||
fn eq(&self, other: &VText<COMP>) -> bool {
|
||||
impl PartialEq for VText {
|
||||
fn eq(&self, other: &VText) -> bool {
|
||||
self.text == other.text
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,7 +29,3 @@ error[E0599]: no method named `b` found for type `t4::PropsBuilder<t4::PropsBuil
|
||||
...
|
||||
48 | Props::builder().b(1).a(2).build();
|
||||
| ^ help: there is a method with a similar name: `a`
|
||||
|
||||
Some errors have detailed explanations: E0277, E0599.
|
||||
For more information about an error, try `rustc --explain E0277`.
|
||||
error: could not compile `yew-tests`.
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#[allow(dead_code)]
|
||||
#[rustversion::attr(beta, cfg_attr(not(feature = "web_test"), test))]
|
||||
#[rustversion::attr(stable(1.39.0), cfg_attr(not(feature = "web_test"), test))]
|
||||
fn tests() {
|
||||
let t = trybuild::TestCases::new();
|
||||
t.pass("tests/derive_props/pass.rs");
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
macro_rules! pass_helper {
|
||||
( @html ) => { html! {} };
|
||||
( @html html! { $($view:tt)* }; $($tail:tt)* ) => {
|
||||
let _: Html<TestComponent> = html! { $($view)* };
|
||||
html! { $($view)* };
|
||||
pass_helper! { @ html $($tail)* }
|
||||
};
|
||||
( @html $head:stmt; $($tail:tt)* ) => {
|
||||
@ -11,11 +11,12 @@ macro_rules! pass_helper {
|
||||
};
|
||||
( $($content:tt)* ) => {
|
||||
mod test_component;
|
||||
use test_component::TestComponent;
|
||||
use yew::prelude::*;
|
||||
#[allow(unused)]
|
||||
use test_component::TestComponent;
|
||||
struct SubComponent;
|
||||
impl Renderable<TestComponent> for SubComponent {
|
||||
fn render(&self) -> Html<TestComponent> {
|
||||
impl Renderable for SubComponent {
|
||||
fn render(&self) -> Html {
|
||||
pass_helper! { @ html $($content)* }
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ error[E0277]: `()` doesn't implement `std::fmt::Display`
|
||||
= help: the trait `std::fmt::Display` is not implemented for `()`
|
||||
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
|
||||
= note: required because of the requirements on the impl of `std::string::ToString` for `()`
|
||||
= note: required because of the requirements on the impl of `std::convert::From<()>` for `yew::virtual_dom::vnode::VNode<_>`
|
||||
= note: required because of the requirements on the impl of `std::convert::From<()>` for `yew::virtual_dom::vnode::VNode`
|
||||
= note: required by `std::convert::From::from`
|
||||
|
||||
error[E0277]: `()` doesn't implement `std::fmt::Display`
|
||||
@ -19,7 +19,7 @@ error[E0277]: `()` doesn't implement `std::fmt::Display`
|
||||
= help: the trait `std::fmt::Display` is not implemented for `()`
|
||||
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
|
||||
= note: required because of the requirements on the impl of `std::string::ToString` for `()`
|
||||
= note: required because of the requirements on the impl of `std::convert::From<()>` for `yew::virtual_dom::vnode::VNode<_>`
|
||||
= note: required because of the requirements on the impl of `std::convert::From<()>` for `yew::virtual_dom::vnode::VNode`
|
||||
= note: required by `std::convert::From::from`
|
||||
|
||||
error[E0277]: `()` doesn't implement `std::fmt::Display`
|
||||
@ -31,8 +31,5 @@ error[E0277]: `()` doesn't implement `std::fmt::Display`
|
||||
= help: the trait `std::fmt::Display` is not implemented for `()`
|
||||
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
|
||||
= note: required because of the requirements on the impl of `std::string::ToString` for `()`
|
||||
= note: required because of the requirements on the impl of `std::convert::From<()>` for `yew::virtual_dom::vnode::VNode<_>`
|
||||
= note: required because of the requirements on the impl of `std::convert::Into<yew::virtual_dom::vnode::VNode<_>>` for `()`
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
error: could not compile `yew-tests`.
|
||||
= note: required because of the requirements on the impl of `std::convert::From<()>` for `yew::virtual_dom::vnode::VNode`
|
||||
= note: required because of the requirements on the impl of `std::convert::Into<yew::virtual_dom::vnode::VNode>` for `()`
|
||||
|
||||
@ -3,6 +3,3 @@ error[E0277]: the trait bound `std::string::String: yew::html::Component` is not
|
||||
|
|
||||
6 | html! { <String /> };
|
||||
| ^^^^^^ the trait `yew::html::Component` is not implemented for `std::string::String`
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
error: could not compile `yew-tests`.
|
||||
|
||||
@ -22,14 +22,14 @@ impl Component for Child {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Properties)]
|
||||
pub struct ChildContainerProperties {
|
||||
pub children: ChildrenWithProps<Child, ChildContainer>,
|
||||
pub children: ChildrenWithProps<Child>,
|
||||
}
|
||||
|
||||
pub struct ChildContainer;
|
||||
@ -45,7 +45,7 @@ impl Component for ChildContainer {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
@ -187,47 +187,47 @@ error[E0599]: no method named `children` found for type `ChildPropertiesBuilder<
|
||||
|
|
||||
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
|
||||
|
||||
error[E0277]: the trait bound `yew::virtual_dom::vcomp::VChild<Child, ChildContainer>: std::convert::From<yew::virtual_dom::vnode::VNode<_>>` is not satisfied
|
||||
error[E0277]: the trait bound `yew::virtual_dom::vcomp::VChild<Child>: std::convert::From<yew::virtual_dom::vnode::VNode>` is not satisfied
|
||||
--> $DIR/html-component-fail.rs:78:5
|
||||
|
|
||||
78 | html! { <ChildContainer>{ "Not allowed" }</ChildContainer> };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From<yew::virtual_dom::vnode::VNode<_>>` is not implemented for `yew::virtual_dom::vcomp::VChild<Child, ChildContainer>`
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From<yew::virtual_dom::vnode::VNode>` is not implemented for `yew::virtual_dom::vcomp::VChild<Child>`
|
||||
|
|
||||
= note: required because of the requirements on the impl of `std::convert::Into<yew::virtual_dom::vcomp::VChild<Child, ChildContainer>>` for `yew::virtual_dom::vnode::VNode<_>`
|
||||
= note: required because of the requirements on the impl of `std::convert::Into<yew::virtual_dom::vcomp::VChild<Child>>` for `yew::virtual_dom::vnode::VNode`
|
||||
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
|
||||
|
||||
error[E0277]: the trait bound `yew::virtual_dom::vcomp::VChild<Child, ChildContainer>: std::convert::From<yew::virtual_dom::vnode::VNode<_>>` is not satisfied
|
||||
error[E0277]: the trait bound `yew::virtual_dom::vcomp::VChild<Child>: std::convert::From<yew::virtual_dom::vnode::VNode>` is not satisfied
|
||||
--> $DIR/html-component-fail.rs:79:5
|
||||
|
|
||||
79 | html! { <ChildContainer><></></ChildContainer> };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From<yew::virtual_dom::vnode::VNode<_>>` is not implemented for `yew::virtual_dom::vcomp::VChild<Child, ChildContainer>`
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From<yew::virtual_dom::vnode::VNode>` is not implemented for `yew::virtual_dom::vcomp::VChild<Child>`
|
||||
|
|
||||
= note: required because of the requirements on the impl of `std::convert::Into<yew::virtual_dom::vcomp::VChild<Child, ChildContainer>>` for `yew::virtual_dom::vnode::VNode<_>`
|
||||
= note: required because of the requirements on the impl of `std::convert::Into<yew::virtual_dom::vcomp::VChild<Child>>` for `yew::virtual_dom::vnode::VNode`
|
||||
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
|
||||
|
||||
error[E0277]: the trait bound `yew::virtual_dom::vcomp::VChild<Child, ChildContainer>: std::convert::From<yew::virtual_dom::vcomp::VChild<ChildContainer, _>>` is not satisfied
|
||||
error[E0277]: the trait bound `yew::virtual_dom::vcomp::VChild<Child>: std::convert::From<yew::virtual_dom::vcomp::VChild<ChildContainer>>` is not satisfied
|
||||
--> $DIR/html-component-fail.rs:80:5
|
||||
|
|
||||
80 | html! { <ChildContainer><ChildContainer /></ChildContainer> };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From<yew::virtual_dom::vcomp::VChild<ChildContainer, _>>` is not implemented for `yew::virtual_dom::vcomp::VChild<Child, ChildContainer>`
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From<yew::virtual_dom::vcomp::VChild<ChildContainer>>` is not implemented for `yew::virtual_dom::vcomp::VChild<Child>`
|
||||
|
|
||||
= note: required because of the requirements on the impl of `std::convert::Into<yew::virtual_dom::vcomp::VChild<Child, ChildContainer>>` for `yew::virtual_dom::vcomp::VChild<ChildContainer, _>`
|
||||
= note: required because of the requirements on the impl of `std::convert::Into<yew::virtual_dom::vcomp::VChild<Child>>` for `yew::virtual_dom::vcomp::VChild<ChildContainer>`
|
||||
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
|
||||
|
||||
error[E0277]: the trait bound `yew::virtual_dom::vcomp::VChild<Child, ChildContainer>: std::convert::From<yew::virtual_dom::vcomp::VChild<ChildContainer, _>>` is not satisfied
|
||||
error[E0277]: the trait bound `yew::virtual_dom::vcomp::VChild<Child>: std::convert::From<yew::virtual_dom::vcomp::VChild<ChildContainer>>` is not satisfied
|
||||
--> $DIR/html-component-fail.rs:81:5
|
||||
|
|
||||
81 | html! { <ChildContainer><ChildContainer /></ChildContainer> };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From<yew::virtual_dom::vcomp::VChild<ChildContainer, _>>` is not implemented for `yew::virtual_dom::vcomp::VChild<Child, ChildContainer>`
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From<yew::virtual_dom::vcomp::VChild<ChildContainer>>` is not implemented for `yew::virtual_dom::vcomp::VChild<Child>`
|
||||
|
|
||||
= note: required because of the requirements on the impl of `std::convert::Into<yew::virtual_dom::vcomp::VChild<Child, ChildContainer>>` for `yew::virtual_dom::vcomp::VChild<ChildContainer, _>`
|
||||
= note: required because of the requirements on the impl of `std::convert::Into<yew::virtual_dom::vcomp::VChild<Child>>` for `yew::virtual_dom::vcomp::VChild<ChildContainer>`
|
||||
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
|
||||
|
||||
error[E0277]: the trait bound `yew::virtual_dom::vcomp::VChild<Child, ChildContainer>: std::convert::From<yew::virtual_dom::vnode::VNode<_>>` is not satisfied
|
||||
error[E0277]: the trait bound `yew::virtual_dom::vcomp::VChild<Child>: std::convert::From<yew::virtual_dom::vnode::VNode>` is not satisfied
|
||||
--> $DIR/html-component-fail.rs:82:5
|
||||
|
|
||||
82 | html! { <ChildContainer><Child int=1 /><other /></ChildContainer> };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From<yew::virtual_dom::vnode::VNode<_>>` is not implemented for `yew::virtual_dom::vcomp::VChild<Child, ChildContainer>`
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From<yew::virtual_dom::vnode::VNode>` is not implemented for `yew::virtual_dom::vcomp::VChild<Child>`
|
||||
|
|
||||
= note: required because of the requirements on the impl of `std::convert::Into<yew::virtual_dom::vcomp::VChild<Child, ChildContainer>>` for `yew::virtual_dom::vnode::VNode<_>`
|
||||
= note: required because of the requirements on the impl of `std::convert::Into<yew::virtual_dom::vcomp::VChild<Child>>` for `yew::virtual_dom::vnode::VNode`
|
||||
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
|
||||
|
||||
@ -27,7 +27,7 @@ impl Component for Child {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
@ -36,7 +36,7 @@ impl Component for Child {
|
||||
pub struct ContainerProperties {
|
||||
#[props(required)]
|
||||
pub int: i32,
|
||||
pub children: Children<Container>,
|
||||
pub children: Children,
|
||||
}
|
||||
|
||||
pub struct Container;
|
||||
@ -52,7 +52,7 @@ impl Component for Container {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
@ -61,7 +61,7 @@ impl Component for Container {
|
||||
pub struct ChildContainerProperties {
|
||||
#[props(required)]
|
||||
pub int: i32,
|
||||
pub children: ChildrenWithProps<Child, ChildContainer>,
|
||||
pub children: ChildrenWithProps<Child>,
|
||||
}
|
||||
|
||||
pub struct ChildContainer;
|
||||
@ -77,7 +77,7 @@ impl Component for ChildContainer {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
@ -136,7 +136,8 @@ pass_helper! {
|
||||
html! {
|
||||
<>
|
||||
<Child int=1 />
|
||||
<Child int=1 optional_callback=|_| () />
|
||||
<Child int=1 optional_callback=Some(Callback::from(|_| ())) />
|
||||
<Child int=1 optional_callback=None />
|
||||
</>
|
||||
};
|
||||
|
||||
|
||||
@ -31,8 +31,8 @@ error[E0277]: `()` doesn't implement `std::fmt::Display`
|
||||
= help: the trait `std::fmt::Display` is not implemented for `()`
|
||||
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
|
||||
= note: required because of the requirements on the impl of `std::string::ToString` for `()`
|
||||
= note: required because of the requirements on the impl of `std::convert::From<()>` for `yew::virtual_dom::vnode::VNode<_>`
|
||||
= note: required because of the requirements on the impl of `std::convert::Into<yew::virtual_dom::vnode::VNode<_>>` for `()`
|
||||
= note: required because of the requirements on the impl of `std::convert::From<()>` for `yew::virtual_dom::vnode::VNode`
|
||||
= note: required because of the requirements on the impl of `std::convert::Into<yew::virtual_dom::vnode::VNode>` for `()`
|
||||
|
||||
error[E0277]: `()` doesn't implement `std::fmt::Display`
|
||||
--> $DIR/html-iterable-fail.rs:10:17
|
||||
@ -43,8 +43,8 @@ error[E0277]: `()` doesn't implement `std::fmt::Display`
|
||||
= help: the trait `std::fmt::Display` is not implemented for `()`
|
||||
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
|
||||
= note: required because of the requirements on the impl of `std::string::ToString` for `()`
|
||||
= note: required because of the requirements on the impl of `std::convert::From<()>` for `yew::virtual_dom::vnode::VNode<_>`
|
||||
= note: required because of the requirements on the impl of `std::convert::Into<yew::virtual_dom::vnode::VNode<_>>` for `()`
|
||||
= note: required because of the requirements on the impl of `std::convert::From<()>` for `yew::virtual_dom::vnode::VNode`
|
||||
= note: required because of the requirements on the impl of `std::convert::Into<yew::virtual_dom::vnode::VNode>` for `()`
|
||||
|
||||
error[E0277]: `()` doesn't implement `std::fmt::Display`
|
||||
--> $DIR/html-iterable-fail.rs:13:17
|
||||
@ -56,8 +56,5 @@ error[E0277]: `()` doesn't implement `std::fmt::Display`
|
||||
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
|
||||
= note: required because of the requirements on the impl of `std::fmt::Display` for `&()`
|
||||
= note: required because of the requirements on the impl of `std::string::ToString` for `&()`
|
||||
= note: required because of the requirements on the impl of `std::convert::From<&()>` for `yew::virtual_dom::vnode::VNode<_>`
|
||||
= note: required because of the requirements on the impl of `std::convert::Into<yew::virtual_dom::vnode::VNode<_>>` for `&()`
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
error: could not compile `yew-tests`.
|
||||
= note: required because of the requirements on the impl of `std::convert::From<&()>` for `yew::virtual_dom::vnode::VNode`
|
||||
= note: required because of the requirements on the impl of `std::convert::Into<yew::virtual_dom::vnode::VNode>` for `&()`
|
||||
|
||||
@ -4,12 +4,12 @@ mod helpers;
|
||||
use std::iter;
|
||||
|
||||
pass_helper! {
|
||||
html! { for iter::empty::<Html<TestComponent>>() };
|
||||
html! { for Vec::<Html<TestComponent>>::new().into_iter() };
|
||||
html! { for iter::empty::<Html>() };
|
||||
html! { for Vec::<Html>::new().into_iter() };
|
||||
html! { for (0..3).map(|num| { html! { <span>{num}</span> } }) };
|
||||
html! { for {iter::empty::<Html<TestComponent>>()} };
|
||||
html! { for {iter::empty::<Html>()} };
|
||||
|
||||
let empty: Vec<Html<TestComponent>> = Vec::new();
|
||||
let empty: Vec<Html> = Vec::new();
|
||||
html! { for empty.into_iter() };
|
||||
}
|
||||
|
||||
|
||||
@ -39,5 +39,3 @@ error: expected valid html element
|
||||
|
|
||||
10 | html! { <>invalid</> };
|
||||
| ^^^^^^^
|
||||
|
||||
error: could not compile `yew-tests`.
|
||||
|
||||
@ -61,7 +61,7 @@ error[E0277]: `()` doesn't implement `std::fmt::Display`
|
||||
= help: the trait `std::fmt::Display` is not implemented for `()`
|
||||
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
|
||||
= note: required because of the requirements on the impl of `std::string::ToString` for `()`
|
||||
= note: required because of the requirements on the impl of `std::convert::From<()>` for `yew::virtual_dom::vnode::VNode<_>`
|
||||
= note: required because of the requirements on the impl of `std::convert::From<()>` for `yew::virtual_dom::vnode::VNode`
|
||||
= note: required by `std::convert::From::from`
|
||||
|
||||
error[E0277]: `()` doesn't implement `std::fmt::Display`
|
||||
@ -73,9 +73,5 @@ error[E0277]: `()` doesn't implement `std::fmt::Display`
|
||||
= help: the trait `std::fmt::Display` is not implemented for `()`
|
||||
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
|
||||
= note: required because of the requirements on the impl of `std::string::ToString` for `()`
|
||||
= note: required because of the requirements on the impl of `std::convert::From<()>` for `yew::virtual_dom::vnode::VNode<_>`
|
||||
= note: required because of the requirements on the impl of `std::convert::From<()>` for `yew::virtual_dom::vnode::VNode`
|
||||
= note: required by `std::convert::From::from`
|
||||
|
||||
Some errors have detailed explanations: E0277, E0425.
|
||||
For more information about an error, try `rustc --explain E0277`.
|
||||
error: could not compile `yew-tests`.
|
||||
|
||||
@ -52,13 +52,11 @@ error: only one root html element allowed
|
||||
14 | html! { <img /></img> };
|
||||
| ^^^^^^
|
||||
|
||||
error: unexpected end of input, expected token tree
|
||||
--> $DIR/html-tag-fail.rs:15:5
|
||||
error: expected valid html element
|
||||
--> $DIR/html-tag-fail.rs:15:18
|
||||
|
|
||||
15 | html! { <div>Invalid</div> };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
|
||||
| ^^^^^^^
|
||||
|
||||
error: only one `attr` attribute allowed
|
||||
--> $DIR/html-tag-fail.rs:17:27
|
||||
|
||||
@ -23,7 +23,7 @@ impl Component for TestComponent {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
#[cfg(feature = "wasm_test")]
|
||||
use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};
|
||||
use yew::macros::Properties;
|
||||
use yew::virtual_dom::VNode;
|
||||
use yew::{html, Component, ComponentLink, Html, ShouldRender};
|
||||
|
||||
#[cfg(feature = "wasm_test")]
|
||||
@ -27,26 +26,26 @@ impl Component for Comp {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_properties_to_component() {
|
||||
let _: VNode<Comp> = html! {
|
||||
let _ = html! {
|
||||
<Comp />
|
||||
};
|
||||
|
||||
let _: VNode<Comp> = html! {
|
||||
let _ = html! {
|
||||
<Comp field_1=1 />
|
||||
};
|
||||
|
||||
let _: VNode<Comp> = html! {
|
||||
let _ = html! {
|
||||
<Comp field_2=2 />
|
||||
};
|
||||
|
||||
let _: VNode<Comp> = html! {
|
||||
let _ = html! {
|
||||
<Comp field_1=1 field_2=2 />
|
||||
};
|
||||
|
||||
@ -55,7 +54,7 @@ fn set_properties_to_component() {
|
||||
field_2: 1,
|
||||
};
|
||||
|
||||
let _: VNode<Comp> = html! {
|
||||
let _ = html! {
|
||||
<Comp with props />
|
||||
};
|
||||
}
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
#[cfg(feature = "wasm_test")]
|
||||
use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};
|
||||
use yew::virtual_dom::VNode;
|
||||
use yew::{html, Component, ComponentLink, Html, ShouldRender};
|
||||
|
||||
#[cfg(feature = "wasm_test")]
|
||||
@ -20,18 +19,18 @@ impl Component for Comp {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_fragments() {
|
||||
let fragment: VNode<Comp> = html! {
|
||||
let fragment = html! {
|
||||
<>
|
||||
</>
|
||||
};
|
||||
let _: VNode<Comp> = html! {
|
||||
html! {
|
||||
<div>
|
||||
{ fragment }
|
||||
</div>
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
use stdweb::web::{document, IElement};
|
||||
#[cfg(feature = "wasm_test")]
|
||||
use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};
|
||||
use yew::html::Scope;
|
||||
use yew::virtual_dom::vtag::{VTag, HTML_NAMESPACE, SVG_NAMESPACE};
|
||||
use yew::virtual_dom::{VDiff, VNode};
|
||||
use yew::{html, Component, ComponentLink, Html, ShouldRender};
|
||||
@ -24,7 +23,7 @@ impl Component for Comp {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
@ -43,7 +42,7 @@ impl Component for CompInt {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
@ -62,22 +61,22 @@ impl Component for CompBool {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_compares_tags() {
|
||||
let a: VNode<Comp> = html! {
|
||||
let a = html! {
|
||||
<div></div>
|
||||
};
|
||||
|
||||
let b: VNode<Comp> = html! {
|
||||
let b = html! {
|
||||
<div></div>
|
||||
};
|
||||
|
||||
let c: VNode<Comp> = html! {
|
||||
let c = html! {
|
||||
<p></p>
|
||||
};
|
||||
|
||||
@ -87,15 +86,15 @@ fn it_compares_tags() {
|
||||
|
||||
#[test]
|
||||
fn it_compares_text() {
|
||||
let a: VNode<Comp> = html! {
|
||||
let a = html! {
|
||||
<div>{ "correct" }</div>
|
||||
};
|
||||
|
||||
let b: VNode<Comp> = html! {
|
||||
let b = html! {
|
||||
<div>{ "correct" }</div>
|
||||
};
|
||||
|
||||
let c: VNode<Comp> = html! {
|
||||
let c = html! {
|
||||
<div>{ "incorrect" }</div>
|
||||
};
|
||||
|
||||
@ -105,15 +104,15 @@ fn it_compares_text() {
|
||||
|
||||
#[test]
|
||||
fn it_compares_attributes() {
|
||||
let a: VNode<Comp> = html! {
|
||||
let a = html! {
|
||||
<div a="test"></div>
|
||||
};
|
||||
|
||||
let b: VNode<Comp> = html! {
|
||||
let b = html! {
|
||||
<div a="test"></div>
|
||||
};
|
||||
|
||||
let c: VNode<Comp> = html! {
|
||||
let c = html! {
|
||||
<div a="fail"></div>
|
||||
};
|
||||
|
||||
@ -123,19 +122,19 @@ fn it_compares_attributes() {
|
||||
|
||||
#[test]
|
||||
fn it_compares_children() {
|
||||
let a: VNode<Comp> = html! {
|
||||
let a = html! {
|
||||
<div>
|
||||
<p></p>
|
||||
</div>
|
||||
};
|
||||
|
||||
let b: VNode<Comp> = html! {
|
||||
let b = html! {
|
||||
<div>
|
||||
<p></p>
|
||||
</div>
|
||||
};
|
||||
|
||||
let c: VNode<Comp> = html! {
|
||||
let c = html! {
|
||||
<div>
|
||||
<span></span>
|
||||
</div>
|
||||
@ -147,19 +146,19 @@ fn it_compares_children() {
|
||||
|
||||
#[test]
|
||||
fn it_compares_classes() {
|
||||
let a: VNode<Comp> = html! {
|
||||
let a = html! {
|
||||
<div class="test"></div>
|
||||
};
|
||||
|
||||
let b: VNode<Comp> = html! {
|
||||
let b = html! {
|
||||
<div class="test"></div>
|
||||
};
|
||||
|
||||
let c: VNode<Comp> = html! {
|
||||
let c = html! {
|
||||
<div class="fail"></div>
|
||||
};
|
||||
|
||||
let d: VNode<Comp> = html! {
|
||||
let d = html! {
|
||||
<div class=format!("fail")></div>
|
||||
};
|
||||
|
||||
@ -170,17 +169,17 @@ fn it_compares_classes() {
|
||||
|
||||
#[test]
|
||||
fn classes_from_local_variables() {
|
||||
let a: VNode<Comp> = html! {
|
||||
let a = html! {
|
||||
<div class=("class-1", "class-2")></div>
|
||||
};
|
||||
|
||||
let class_2 = "class-2";
|
||||
let b: VNode<Comp> = html! {
|
||||
let b = html! {
|
||||
<div class=("class-1", class_2)></div>
|
||||
};
|
||||
|
||||
let class_2_fmt = format!("class-{}", 2);
|
||||
let c: VNode<Comp> = html! {
|
||||
let c = html! {
|
||||
<div class=("class-1", class_2_fmt)></div>
|
||||
};
|
||||
|
||||
@ -190,11 +189,11 @@ fn classes_from_local_variables() {
|
||||
|
||||
#[test]
|
||||
fn supports_multiple_classes_string() {
|
||||
let a: VNode<Comp> = html! {
|
||||
let a = html! {
|
||||
<div class="class-1 class-2 class-3"></div>
|
||||
};
|
||||
|
||||
let b: VNode<Comp> = html! {
|
||||
let b = html! {
|
||||
<div class="class-2 class-3 class-1"></div>
|
||||
};
|
||||
|
||||
@ -214,7 +213,7 @@ fn supports_multiple_classes_string() {
|
||||
fn supports_multiple_classes_vec() {
|
||||
let mut classes = vec!["class-1"];
|
||||
classes.push("class-2");
|
||||
let a: VNode<Comp> = html! {
|
||||
let a = html! {
|
||||
<div class=classes></div>
|
||||
};
|
||||
|
||||
@ -232,9 +231,9 @@ fn supports_multiple_classes_vec() {
|
||||
fn filter_empty_string_classes_vec() {
|
||||
let mut classes = vec![""];
|
||||
classes.push("class-2");
|
||||
let a: VNode<Comp> = html! { <div class=vec![""]></div> };
|
||||
let b: VNode<Comp> = html! { <div class=("")></div> };
|
||||
let c: VNode<Comp> = html! { <div class=""></div> };
|
||||
let a = html! { <div class=vec![""]></div> };
|
||||
let b = html! { <div class=("")></div> };
|
||||
let c = html! { <div class=""></div> };
|
||||
|
||||
if let VNode::VTag(vtag) = a {
|
||||
assert!(vtag.classes.is_empty());
|
||||
@ -255,14 +254,14 @@ fn filter_empty_string_classes_vec() {
|
||||
}
|
||||
}
|
||||
|
||||
fn assert_vtag(node: &mut VNode<Comp>) -> &mut VTag<Comp> {
|
||||
fn assert_vtag(node: &mut VNode) -> &mut VTag {
|
||||
if let VNode::VTag(vtag) = node {
|
||||
return vtag;
|
||||
}
|
||||
panic!("should be vtag");
|
||||
}
|
||||
|
||||
fn assert_namespace(vtag: &VTag<Comp>, namespace: &'static str) {
|
||||
fn assert_namespace(vtag: &VTag, namespace: &'static str) {
|
||||
assert_eq!(
|
||||
vtag.reference.as_ref().unwrap().namespace_uri().unwrap(),
|
||||
namespace
|
||||
@ -271,32 +270,31 @@ fn assert_namespace(vtag: &VTag<Comp>, namespace: &'static str) {
|
||||
|
||||
#[test]
|
||||
fn supports_svg() {
|
||||
let scope = Scope::new();
|
||||
let div_el = document().create_element("div").unwrap();
|
||||
let svg_el = document().create_element_ns(SVG_NAMESPACE, "svg").unwrap();
|
||||
|
||||
let mut g_node: VNode<Comp> = html! { <g></g> };
|
||||
let path_node: VNode<Comp> = html! { <path></path> };
|
||||
let mut svg_node: VNode<Comp> = html! { <svg>{path_node}</svg> };
|
||||
let mut g_node = html! { <g></g> };
|
||||
let path_node = html! { <path></path> };
|
||||
let mut svg_node = html! { <svg>{path_node}</svg> };
|
||||
|
||||
let svg_tag = assert_vtag(&mut svg_node);
|
||||
svg_tag.apply(&div_el, None, None, &scope);
|
||||
svg_tag.apply(&div_el, None, None);
|
||||
assert_namespace(svg_tag, SVG_NAMESPACE);
|
||||
let path_tag = assert_vtag(svg_tag.children.get_mut(0).unwrap());
|
||||
assert_namespace(path_tag, SVG_NAMESPACE);
|
||||
|
||||
let g_tag = assert_vtag(&mut g_node);
|
||||
g_tag.apply(&div_el, None, None, &scope);
|
||||
g_tag.apply(&div_el, None, None);
|
||||
assert_namespace(g_tag, HTML_NAMESPACE);
|
||||
g_tag.reference = None;
|
||||
|
||||
g_tag.apply(&svg_el, None, None, &scope);
|
||||
g_tag.apply(&svg_el, None, None);
|
||||
assert_namespace(g_tag, SVG_NAMESPACE);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keeps_order_of_classes() {
|
||||
let a: VNode<Comp> = html! {
|
||||
let a = html! {
|
||||
<div class="class-1 class-2 class-3",></div>
|
||||
};
|
||||
|
||||
@ -308,15 +306,15 @@ fn keeps_order_of_classes() {
|
||||
|
||||
#[test]
|
||||
fn it_compares_values() {
|
||||
let a: VNode<Comp> = html! {
|
||||
let a = html! {
|
||||
<input value="test"/>
|
||||
};
|
||||
|
||||
let b: VNode<Comp> = html! {
|
||||
let b = html! {
|
||||
<input value="test"/>
|
||||
};
|
||||
|
||||
let c: VNode<Comp> = html! {
|
||||
let c = html! {
|
||||
<input value="fail"/>
|
||||
};
|
||||
|
||||
@ -326,15 +324,15 @@ fn it_compares_values() {
|
||||
|
||||
#[test]
|
||||
fn it_compares_kinds() {
|
||||
let a: VNode<Comp> = html! {
|
||||
let a = html! {
|
||||
<input type="text"/>
|
||||
};
|
||||
|
||||
let b: VNode<Comp> = html! {
|
||||
let b = html! {
|
||||
<input type="text"/>
|
||||
};
|
||||
|
||||
let c: VNode<Comp> = html! {
|
||||
let c = html! {
|
||||
<input type="hidden"/>
|
||||
};
|
||||
|
||||
@ -344,15 +342,15 @@ fn it_compares_kinds() {
|
||||
|
||||
#[test]
|
||||
fn it_compares_checked() {
|
||||
let a: VNode<Comp> = html! {
|
||||
let a = html! {
|
||||
<input type="checkbox" checked=false />
|
||||
};
|
||||
|
||||
let b: VNode<Comp> = html! {
|
||||
let b = html! {
|
||||
<input type="checkbox" checked=false />
|
||||
};
|
||||
|
||||
let c: VNode<Comp> = html! {
|
||||
let c = html! {
|
||||
<input type="checkbox" checked=true />
|
||||
};
|
||||
|
||||
@ -362,7 +360,7 @@ fn it_compares_checked() {
|
||||
|
||||
#[test]
|
||||
fn it_allows_aria_attributes() {
|
||||
let a: VNode<Comp> = html! {
|
||||
let a = html! {
|
||||
<p aria-controls="it-works">
|
||||
<a class="btn btn-primary"
|
||||
data-toggle="collapse"
|
||||
@ -396,38 +394,16 @@ fn it_allows_aria_attributes() {
|
||||
|
||||
#[test]
|
||||
fn it_checks_mixed_closing_tags() {
|
||||
let a: VNode<Comp> = html! { <div> <div/> </div> };
|
||||
let b: VNode<Comp> = html! { <div> <div></div> </div> };
|
||||
assert_eq!(a, b);
|
||||
|
||||
let a: VNode<Comp> = html! { <div> <div data-val={ 2 / 1 }/> </div> };
|
||||
let b: VNode<Comp> = html! { <div> <div data-val={ 2 }></div> </div> };
|
||||
assert_eq!(a, b);
|
||||
|
||||
let a: VNode<Comp> = html! { <div> <div data-val={ 2 > 1 }/> </div> };
|
||||
let b: VNode<Comp> = html! { <div> <div data-val={ true }></div> </div> };
|
||||
assert_eq!(a, b);
|
||||
|
||||
let a: VNode<CompInt> = html! { <div> <div onblur=|_| 2 / 1/> </div> };
|
||||
let b: VNode<CompInt> = html! { <div> <div onblur=|_| 2></div> </div> };
|
||||
let a = html! { <div> <div/> </div> };
|
||||
let b = html! { <div> <div></div> </div> };
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_checks_misleading_gt() {
|
||||
let a: VNode<CompBool> = html! { <div> <div onblur=|_| 2 > 1 /> </div> };
|
||||
let b: VNode<CompBool> = html! { <div> <div onblur=|_| { 2 > 1 } /> </div> };
|
||||
let c: VNode<CompBool> = html! { <div> <div onblur=|_| ( 2 > 1 ) /> </div> };
|
||||
let d: VNode<CompBool> = html! { <div> <div onblur=|_| true ></div> </div> };
|
||||
assert_eq!(a, b);
|
||||
assert_eq!(a, c);
|
||||
assert_eq!(a, d);
|
||||
html! { <div data-val=<u32 as Default>::default()></div> };
|
||||
html! { <div data-val=Box::<u32>::default()></div> };
|
||||
|
||||
let a: VNode<CompBool> = html! { <div><div onblur=|_| 2 > 1 /> </div> };
|
||||
let b: VNode<CompBool> = html! { <div><div onblur=|_| { true }></div></div> };
|
||||
assert_eq!(a, b);
|
||||
|
||||
let a: VNode<CompInt> = html! { <div> <a onblur=|_| -> u32 { 0 } /> </div> };
|
||||
let b: VNode<CompInt> = html! { <div> <a onblur=|_| 0></a> </div> };
|
||||
assert_eq!(a, b);
|
||||
html! { <div><a data-val=<u32 as Default>::default() /> </div> };
|
||||
html! { <div><a data-val=Box::<u32>::default() /></div> };
|
||||
}
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
#[cfg(feature = "wasm_test")]
|
||||
use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};
|
||||
use yew::virtual_dom::VNode;
|
||||
use yew::{html, Component, ComponentLink, Html, ShouldRender};
|
||||
|
||||
#[cfg(feature = "wasm_test")]
|
||||
@ -20,18 +19,18 @@ impl Component for Comp {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn view(&self) -> Html<Self> {
|
||||
fn view(&self) -> Html {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn text_as_root() {
|
||||
let _: VNode<Comp> = html! {
|
||||
html! {
|
||||
"Text Node As Root"
|
||||
};
|
||||
|
||||
let _: VNode<Comp> = html! {
|
||||
html! {
|
||||
{ "Text Node As Root" }
|
||||
};
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user