Skip to content

Commit

Permalink
implement imperative refs, capturing a scope
Browse files Browse the repository at this point in the history
instead of getting a ref "the first element", now get a
Scope link to the component
alternative design, should result in smaller codesize
  • Loading branch information
WorldSEnder committed Mar 27, 2022
1 parent ee6a67e commit 309b93d
Show file tree
Hide file tree
Showing 17 changed files with 304 additions and 139 deletions.
14 changes: 7 additions & 7 deletions examples/nested_list/src/app.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::header::ListHeader;
use super::item::ListItem;
use super::list::List;
use super::{Hovered, WeakComponentLink};
use super::Hovered;
use yew::prelude::*;

pub enum Msg {
Expand All @@ -10,8 +10,8 @@ pub enum Msg {

pub struct App {
hovered: Hovered,
list_link: WeakComponentLink<List>,
sub_list_link: WeakComponentLink<List>,
list_link: ComponentRef<List>,
sub_list_link: ComponentRef<List>,
}

impl Component for App {
Expand All @@ -21,8 +21,8 @@ impl Component for App {
fn create(_ctx: &Context<Self>) -> Self {
Self {
hovered: Hovered::None,
list_link: WeakComponentLink::default(),
sub_list_link: WeakComponentLink::default(),
list_link: ComponentRef::new(),
sub_list_link: ComponentRef::new(),
}
}

Expand Down Expand Up @@ -52,13 +52,13 @@ impl Component for App {
html! {
<div class="main" {onmouseover}>
<h1>{ "Nested List Demo" }</h1>
<List {on_hover} weak_link={list_link}>
<List {on_hover} ref={list_link}>
<ListHeader text="Calling all Rusties!" {on_hover} {list_link} />
<ListItem name="Rustin" {on_hover} />
<ListItem hide=true name="Rustaroo" {on_hover} />
<ListItem name="Rustifer" {on_hover}>
<div class="sublist" onmouseover={onmouseoversublist}>{ "Sublist!" }</div>
<List {on_hover} weak_link={sub_list_link}>
<List {on_hover} ref={sub_list_link}>
<ListHeader text="Sub Rusties!" {on_hover} list_link={sub_list_link}/>
<ListItem hide=true name="Hidden Sub" {on_hover} />
{ for letters }
Expand Down
6 changes: 3 additions & 3 deletions examples/nested_list/src/header.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use super::list::{List, Msg as ListMsg};
use super::{Hovered, WeakComponentLink};
use super::Hovered;
use yew::prelude::*;

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

pub struct ListHeader;
Expand All @@ -20,7 +20,7 @@ impl Component for ListHeader {
}

fn view(&self, ctx: &Context<Self>) -> Html {
let list_link = ctx.props().list_link.borrow().clone().unwrap();
let list_link = ctx.props().list_link.get().unwrap();
let onmouseover = ctx.props().on_hover.reform(|e: MouseEvent| {
e.stop_propagation();
Hovered::Header
Expand Down
17 changes: 5 additions & 12 deletions examples/nested_list/src/list.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::header::{ListHeader, Props as HeaderProps};
use crate::item::{ListItem, Props as ItemProps};
use crate::{Hovered, WeakComponentLink};
use crate::Hovered;
use std::rc::Rc;
use yew::html::{ChildrenRenderer, NodeRef};
use yew::html::ChildrenRenderer;
use yew::prelude::*;
use yew::virtual_dom::{VChild, VComp};

Expand Down Expand Up @@ -44,10 +44,8 @@ where
impl From<ListVariant> for Html {
fn from(variant: ListVariant) -> Html {
match variant.props {
Variants::Header(props) => {
VComp::new::<ListHeader>(props, NodeRef::default(), None).into()
}
Variants::Item(props) => VComp::new::<ListItem>(props, NodeRef::default(), None).into(),
Variants::Header(props) => VComp::new::<ListHeader>(props, None, None).into(),
Variants::Item(props) => VComp::new::<ListItem>(props, None, None).into(),
}
}
}
Expand All @@ -60,7 +58,6 @@ pub enum Msg {
pub struct Props {
pub children: ChildrenRenderer<ListVariant>,
pub on_hover: Callback<Hovered>,
pub weak_link: WeakComponentLink<List>,
}

pub struct List {
Expand All @@ -71,11 +68,7 @@ impl Component for List {
type Message = Msg;
type Properties = Props;

fn create(ctx: &Context<Self>) -> Self {
ctx.props()
.weak_link
.borrow_mut()
.replace(ctx.link().clone());
fn create(_ctx: &Context<Self>) -> Self {
Self { inactive: false }
}

Expand Down
33 changes: 0 additions & 33 deletions examples/nested_list/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,7 @@ mod header;
mod item;
mod list;

use std::cell::RefCell;
use std::fmt;
use std::ops::Deref;
use std::rc::Rc;
use yew::html::{Component, ImplicitClone, Scope};

pub struct WeakComponentLink<COMP: Component>(Rc<RefCell<Option<Scope<COMP>>>>);

impl<COMP: Component> Clone for WeakComponentLink<COMP> {
fn clone(&self) -> Self {
Self(Rc::clone(&self.0))
}
}
impl<COMP: Component> ImplicitClone for WeakComponentLink<COMP> {}

impl<COMP: Component> Default for WeakComponentLink<COMP> {
fn default() -> Self {
Self(Rc::default())
}
}

impl<COMP: Component> Deref for WeakComponentLink<COMP> {
type Target = Rc<RefCell<Option<Scope<COMP>>>>;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl<COMP: Component> PartialEq for WeakComponentLink<COMP> {
fn eq(&self, other: &Self) -> bool {
Rc::ptr_eq(&self.0, &other.0)
}
}

#[derive(Debug)]
pub enum Hovered {
Expand Down
2 changes: 2 additions & 0 deletions examples/node_refs/src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub enum Msg {
#[derive(Properties, PartialEq)]
pub struct Props {
pub on_hover: Callback<()>,
pub input_ref: NodeRef,
}

pub struct InputComponent;
Expand All @@ -33,6 +34,7 @@ impl Component for InputComponent {
<input
type="text"
class="input-component"
ref={&ctx.props().input_ref}
onmouseover={ctx.link().callback(|_| Msg::Hover)}
/>
}
Expand Down
4 changes: 2 additions & 2 deletions examples/node_refs/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,15 @@ impl Component for App {
<label>{ "Using tag ref: " }</label>
<input
type="text"
ref={self.refs[0].clone()}
ref={&self.refs[0]}
class="input-element"
onmouseover={ctx.link().callback(|_| Msg::HoverIndex(0))}
/>
</div>
<div>
<label>{ "Using component ref: " }</label>
<InputComponent
ref={self.refs[1].clone()}
input_ref={&self.refs[1]}
on_hover={ctx.link().callback(|_| Msg::HoverIndex(1))}
/>
</div>
Expand Down
12 changes: 8 additions & 4 deletions packages/yew-macro/src/html_tree/html_component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,9 @@ impl ToTokens for HtmlComponent {
children,
} = self;

let props_ty = quote_spanned!(ty.span()=> <#ty as ::yew::html::IntoComponent>::Properties);
let props_ty =
quote_spanned! {ty.span()=> <#ty as ::yew::html::IntoComponent>::Properties };
let comp_ty = quote_spanned! {ty.span()=> <#ty as ::yew::html::IntoComponent>::Component };
let children_renderer = if children.is_empty() {
None
} else {
Expand All @@ -101,18 +103,20 @@ impl ToTokens for HtmlComponent {
let build_props = props.build_properties_tokens(&props_ty, children_renderer);

let special_props = props.special();
let comp_ref_ty = quote_spanned! {ty.span()=> ::yew::html::ComponentRef::< #comp_ty > };
let node_ref = if let Some(node_ref) = &special_props.node_ref {
let value = &node_ref.value;
quote_spanned! {value.span()=> #value }
let value_quoted = quote_spanned! {value.span()=> #value };
quote! { ::std::option::Option::Some(::yew::html::IntoPropValue::< #comp_ref_ty >::into_prop_value( #value_quoted )) }
} else {
quote! { <::yew::html::NodeRef as ::std::default::Default>::default() }
quote_spanned! {ty.span()=> ::std::option::Option::None }
};

let key = if let Some(key) = &special_props.key {
let value = &key.value;
quote_spanned! {value.span()=>
#[allow(clippy::useless_conversion)]
Some(::std::convert::Into::<::yew::virtual_dom::Key>::into(#value))
::std::option::Option::Some(::std::convert::Into::<::yew::virtual_dom::Key>::into(#value))
}
} else {
quote! { ::std::option::Option::None }
Expand Down
10 changes: 8 additions & 2 deletions packages/yew-macro/tests/html_macro/component-fail.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -361,11 +361,17 @@ error[E0277]: the trait bound `{integer}: IntoPropValue<String>` is not satisfie
<&'static str as IntoPropValue<Option<String>>>
and 15 others

error[E0308]: mismatched types
error[E0277]: the trait bound `(): IntoPropValue<ComponentRef<Child>>` is not satisfied
--> tests/html_macro/component-fail.rs:80:31
|
80 | html! { <Child int=1 ref={()} /> };
| ^^ expected struct `NodeRef`, found `()`
| ^^ the trait `IntoPropValue<ComponentRef<Child>>` is not implemented for `()`
|
note: required by `into_prop_value`
--> $WORKSPACE/packages/yew/src/html/conversion.rs
|
| fn into_prop_value(self) -> T;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: the trait bound `u32: IntoPropValue<i32>` is not satisfied
--> tests/html_macro/component-fail.rs:82:24
Expand Down
10 changes: 5 additions & 5 deletions packages/yew-macro/tests/html_macro/component-pass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ fn compile_pass() {
};

let props = <<Child as ::yew::Component>::Properties as ::std::default::Default>::default();
let node_ref = <::yew::NodeRef as ::std::default::Default>::default();
let node_ref = <::yew::ComponentRef<Child> as ::std::default::Default>::default();
::yew::html! {
<>
<Child ..::std::clone::Clone::clone(&props) />
Expand Down Expand Up @@ -218,15 +218,15 @@ fn compile_pass() {
</>
};

let node_ref = <::yew::NodeRef as ::std::default::Default>::default();
let node_ref = <::yew::ComponentRef<Child> as ::std::default::Default>::default();
::yew::html! {
<>
<Child int=1 ref={node_ref} />
</>
};

let int = 1;
let node_ref = <::yew::NodeRef as ::std::default::Default>::default();
let node_ref = <::yew::ComponentRef<Child> as ::std::default::Default>::default();
::yew::html! {
<>
<Child {int} ref={node_ref} />
Expand Down Expand Up @@ -323,12 +323,12 @@ fn compile_pass() {
::std::vec![
ChildrenVariants::Child(::yew::virtual_dom::VChild::new(
<ChildProperties as ::std::default::Default>::default(),
<::yew::NodeRef as ::std::default::Default>::default(),
::std::option::Option::None,
::std::option::Option::None,
)),
ChildrenVariants::AltChild(::yew::virtual_dom::VChild::new(
(),
<::yew::NodeRef as ::std::default::Default>::default(),
::std::option::Option::None,
::std::option::Option::None
)),
]
Expand Down
3 changes: 2 additions & 1 deletion packages/yew/src/app_handle.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! [AppHandle] contains the state Yew keeps to bootstrap a component in an isolated scope.

use crate::dom_bundle::BSubtree;
use crate::html::Scoped;
use crate::html::{ComponentAnyRef, Scoped};
use crate::html::{IntoComponent, NodeRef, Scope};
use std::ops::Deref;
use std::rc::Rc;
Expand Down Expand Up @@ -34,6 +34,7 @@ where
host,
NodeRef::default(),
NodeRef::default(),
ComponentAnyRef::default(),
props,
);

Expand Down

0 comments on commit 309b93d

Please sign in to comment.