Bläddra i källkod

handle listeners

Evan Almloff 3 år sedan
förälder
incheckning
6b03a60fee

+ 10 - 3
examples/hot_reload.rs

@@ -6,25 +6,32 @@ fn main() {
 }
 
 fn app(cx: Scope) -> Element {
-    let count = use_state(&cx, || 0);
+    let count = use_state(&cx, || 170);
 
     use_future(&cx, (), move |_| {
         let mut count = count.clone();
         async move {
             loop {
-                tokio::time::sleep(Duration::from_millis(10)).await;
+                tokio::time::sleep(Duration::from_millis(1000)).await;
                 count += 1;
             }
         }
     });
 
     cx.render(rsx! {
-        h1 {
+        div {
             width: format!("{}px", count),
+            background_color: "#999999",
+            onclick: move |_| {
+                count.modify(|count| *count + 1);
+            },
             "High-Five counter: {count}",
             Comp{
                 color: "#083289"
             }
+            Comp{
+                color: "green"
+            }
         }
     })
 }

+ 12 - 3
packages/rsx_interperter/src/captuered_context.rs

@@ -1,5 +1,5 @@
-use dioxus_core::VNode;
-use dioxus_rsx::{BodyNode, CallBody, Component, ElementAttr, IfmtInput};
+use dioxus_core::{Listener, VNode};
+use dioxus_rsx::{BodyNode, CallBody, Component, ElementAttr, ElementAttrNamed, IfmtInput};
 use quote::{quote, ToTokens, TokenStreamExt};
 use std::collections::HashMap;
 use syn::Expr;
@@ -11,6 +11,7 @@ pub struct CapturedContextBuilder {
     pub components: Vec<Component>,
     pub iterators: Vec<Expr>,
     pub captured_expressions: Vec<Expr>,
+    pub listeners: Vec<ElementAttrNamed>,
 }
 
 impl CapturedContextBuilder {
@@ -19,6 +20,7 @@ impl CapturedContextBuilder {
         self.text.extend(other.text);
         self.components.extend(other.components);
         self.iterators.extend(other.iterators);
+        self.listeners.extend(other.listeners);
         self.captured_expressions.extend(other.captured_expressions);
     }
 
@@ -52,6 +54,7 @@ impl CapturedContextBuilder {
                         ElementAttr::CustomAttrExpression { name: _, value } => {
                             captured.captured_expressions.push(value);
                         }
+                        ElementAttr::EventTokens { .. } => captured.listeners.push(attr),
                         _ => (),
                     }
                 }
@@ -82,11 +85,14 @@ impl ToTokens for CapturedContextBuilder {
             components,
             iterators,
             captured_expressions,
+            listeners,
         } = self;
+        let listeners_str = listeners
+            .iter()
+            .map(|comp| comp.to_token_stream().to_string());
         let compontents_str = components
             .iter()
             .map(|comp| comp.to_token_stream().to_string());
-        let components = components.iter().map(|comp| comp);
         let iterators_str = iterators
             .iter()
             .map(|expr| expr.to_token_stream().to_string());
@@ -109,6 +115,7 @@ impl ToTokens for CapturedContextBuilder {
                 components: vec![#((#compontents_str, #components)),*],
                 iterators: vec![#((#iterators_str, #iterators)),*],
                 expressions: vec![#((#captured_attr_expressions_text, #captured_expressions.to_string())),*],
+                listeners: vec![#((#listeners_str, #listeners)),*],
             }
         })
     }
@@ -125,6 +132,8 @@ pub struct CapturedContext<'a> {
     pub iterators: Vec<(&'static str, VNode<'a>)>,
     // map expression to the value resulting from the expression
     pub expressions: Vec<(&'static str, String)>,
+    // map listener code to the resulting listener
+    pub listeners: Vec<(&'static str, Listener<'a>)>,
 }
 
 pub struct IfmtArgs {

+ 30 - 9
packages/rsx_interperter/src/interperter.rs

@@ -1,5 +1,5 @@
 use dioxus_core::{Attribute, NodeFactory, VNode};
-use dioxus_rsx::{BodyNode, CallBody, Component, ElementAttr};
+use dioxus_rsx::{BodyNode, CallBody, ElementAttr};
 use quote::ToTokens;
 use std::str::FromStr;
 use syn::{parse2, parse_str, Expr};
@@ -111,10 +111,10 @@ fn build_node<'a>(
         }
         BodyNode::Element(el) => {
             let attributes: &mut Vec<Attribute> = bump.alloc(Vec::new());
-            for attr in el.attributes {
-                match attr.attr {
+            for attr in &el.attributes {
+                match &attr.attr {
                     ElementAttr::AttrText { .. } | ElementAttr::CustomAttrText { .. } => {
-                        let (name, value): (String, InterperedIfmt) = match attr.attr {
+                        let (name, value): (String, InterperedIfmt) = match &attr.attr {
                             ElementAttr::AttrText { name, value } => {
                                 (name.to_string(), value.value().parse().unwrap())
                             }
@@ -140,7 +140,7 @@ fn build_node<'a>(
 
                     ElementAttr::AttrExpression { .. }
                     | ElementAttr::CustomAttrExpression { .. } => {
-                        let (name, value) = match attr.attr {
+                        let (name, value) = match &attr.attr {
                             ElementAttr::AttrExpression { name, value } => {
                                 (name.to_string(), value)
                             }
@@ -153,7 +153,7 @@ fn build_node<'a>(
                         if let Some((_, resulting_value)) = ctx
                             .expressions
                             .iter()
-                            .find(|(n, _)| parse_str::<Expr>(*n).unwrap() == value)
+                            .find(|(n, _)| parse_str::<Expr>(*n).unwrap() == *value)
                         {
                             if let Some((name, namespace)) = attrbute_to_static_str(&name) {
                                 let value = bump.alloc(resulting_value.clone());
@@ -169,8 +169,6 @@ fn build_node<'a>(
                             panic!("could not resolve expression {:?}", value);
                         }
                     }
-                    // Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident { ident: \"count\", span: #0 bytes(497..502) }, arguments: None }] } })
-                    // Path(ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [PathSegment { ident: Ident(count), arguments: None }] } })
                     _ => (),
                 };
             }
@@ -181,12 +179,35 @@ fn build_node<'a>(
                     children.push(node);
                 }
             }
+            let listeners = bump.alloc(Vec::new());
+            for attr in el.attributes {
+                match attr.attr {
+                    ElementAttr::EventTokens { .. } => {
+                        let expr: Expr = parse2(attr.to_token_stream()).unwrap();
+                        if let Some(idx) = ctx
+                            .listeners
+                            .iter()
+                            .position(|(code, _)| parse_str::<Expr>(*code).unwrap() == expr)
+                        {
+                            let (_, listener) = ctx.listeners.remove(idx);
+                            listeners.push(listener)
+                        } else {
+                            panic!(
+                                "could not resolve listener {:?} \n in: {:#?}",
+                                expr.to_token_stream().to_string(),
+                                ctx.listeners.iter().map(|(s, _)| s).collect::<Vec<_>>()
+                            );
+                        }
+                    }
+                    _ => (),
+                }
+            }
             let tag = bump.alloc(el.name.to_string());
             if let Some((tag, ns)) = element_to_static_str(tag) {
                 Some(factory.raw_element(
                     tag,
                     ns,
-                    &[],
+                    listeners,
                     attributes.as_slice(),
                     children.as_slice(),
                     Some(format_args!("{}", key)),