Bläddra i källkod

add component support

Evan Almloff 3 år sedan
förälder
incheckning
a0c7e4d78a

+ 18 - 1
examples/hot_reload.rs

@@ -21,7 +21,24 @@ fn app(cx: Scope) -> Element {
     cx.render(rsx! {
         h1 {
             width: format!("{}px", count),
-            "High-Five counter: {count}"
+            "High-Five counter: {count}",
+            Comp{
+                color: "#083289"
+            }
+        }
+    })
+}
+
+#[derive(PartialEq, Props)]
+struct CompProps {
+    color: &'static str,
+}
+
+fn Comp(cx: Scope<CompProps>) -> Element {
+    cx.render(rsx! {
+        h1 {
+            color: cx.props.color,
+            "Hello, from a component!"
         }
     })
 }

+ 2 - 2
packages/core-macro/src/lib.rs

@@ -202,11 +202,11 @@ pub fn rsx(s: TokenStream) -> TokenStream {
                                 #rsx_text.to_string(),
                             );
                         });
-                        LazyNodes::new(move |factory|{
+                        LazyNodes::new(move |__cx|{
                             let read = rsx_text_index.read();
                             if let Some(text) = read.get(&line_num){
                                 interpert_rsx(
-                                    factory,
+                                    __cx,
                                     &text,
                                     #captured
                                 )

+ 3 - 0
packages/rsx/src/component.rs

@@ -22,6 +22,7 @@ use syn::{
     token, Expr, Ident, LitStr, Result, Token,
 };
 
+#[derive(PartialEq, Eq)]
 pub struct Component {
     pub name: syn::Path,
     pub body: Vec<ComponentField>,
@@ -149,11 +150,13 @@ impl ToTokens for Component {
 }
 
 // the struct's fields info
+#[derive(PartialEq, Eq)]
 pub struct ComponentField {
     pub name: Ident,
     pub content: ContentField,
 }
 
+#[derive(PartialEq, Eq)]
 pub enum ContentField {
     ManExpr(Expr),
     Formatted(LitStr),

+ 3 - 0
packages/rsx/src/element.rs

@@ -10,6 +10,7 @@ use syn::{
 // =======================================
 // Parse the VNode::Element type
 // =======================================
+#[derive(PartialEq, Eq)]
 pub struct Element {
     pub name: Ident,
     pub key: Option<LitStr>,
@@ -189,6 +190,7 @@ impl ToTokens for Element {
     }
 }
 
+#[derive(PartialEq, Eq)]
 pub enum ElementAttr {
     /// attribute: "valuee {}"
     AttrText {
@@ -225,6 +227,7 @@ pub enum ElementAttr {
     Meta(String),
 }
 
+#[derive(PartialEq, Eq)]
 pub struct ElementAttrNamed {
     pub el_name: Ident,
     pub attr: ElementAttr,

+ 1 - 0
packages/rsx/src/node.rs

@@ -15,6 +15,7 @@ Parse
 -> "text {with_args}"
 -> (0..10).map(|f| rsx!("asd")),  // <--- notice the comma - must be a complete expr
 */
+#[derive(PartialEq, Eq)]
 pub enum BodyNode {
     Element(Element),
     Component(Component),

+ 11 - 4
packages/rsx_interperter/src/captuered_context.rs

@@ -83,6 +83,13 @@ impl ToTokens for CapturedContextBuilder {
             iterators,
             captured_expressions,
         } = self;
+        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());
         let captured: Vec<_> = attributes
             .iter()
             .map(|(_, fmt)| fmt.named_args.iter())
@@ -99,8 +106,8 @@ impl ToTokens for CapturedContextBuilder {
                 captured: IfmtArgs{
                     named_args: vec![#((#captured_names, #captured_expr.to_string())),*]
                 },
-                components: vec![#(#components),*],
-                iterators: vec![#(#iterators),*],
+                components: vec![#((#compontents_str, #components)),*],
+                iterators: vec![#((#iterators_str, #iterators)),*],
                 expressions: vec![#((#captured_attr_expressions_text, #captured_expressions.to_string())),*],
             }
         })
@@ -113,9 +120,9 @@ pub struct CapturedContext<'a> {
     // // map of the attribute name and element path to the formated value
     // pub captured_attribute_values: IfmtArgs,
     // the only thing we can update in component is the children
-    pub components: Vec<VNode<'a>>,
+    pub components: Vec<(&'static str, VNode<'a>)>,
     // we can't reasonably interpert iterators, so they are staticly inserted
-    pub iterators: Vec<VNode<'a>>,
+    pub iterators: Vec<(&'static str, VNode<'a>)>,
     // map expression to the value resulting from the expression
     pub expressions: Vec<(&'static str, String)>,
 }

+ 23 - 6
packages/rsx_interperter/src/interperter.rs

@@ -1,7 +1,8 @@
 use dioxus_core::{Attribute, NodeFactory, VNode};
-use dioxus_rsx::{BodyNode, CallBody, ElementAttr};
+use dioxus_rsx::{BodyNode, CallBody, Component, ElementAttr};
+use quote::ToTokens;
 use std::str::FromStr;
-use syn::{parse_str, Expr};
+use syn::{parse2, parse_str, Expr};
 
 use crate::attributes::attrbute_to_static_str;
 use crate::captuered_context::{CapturedContext, IfmtArgs};
@@ -83,17 +84,21 @@ impl FromStr for InterperedIfmt {
     }
 }
 
-pub fn build<'a>(rsx: CallBody, ctx: CapturedContext, factory: &NodeFactory<'a>) -> VNode<'a> {
+pub fn build<'a>(
+    rsx: CallBody,
+    mut ctx: CapturedContext<'a>,
+    factory: &NodeFactory<'a>,
+) -> VNode<'a> {
     let children_built = factory.bump().alloc(Vec::new());
     for (i, child) in rsx.roots.into_iter().enumerate() {
-        children_built.push(build_node(child, &ctx, factory, i.to_string().as_str()));
+        children_built.push(build_node(child, &mut ctx, factory, i.to_string().as_str()));
     }
     factory.fragment_from_iter(children_built.iter())
 }
 
 fn build_node<'a>(
     node: BodyNode,
-    ctx: &CapturedContext,
+    ctx: &mut CapturedContext<'a>,
     factory: &NodeFactory<'a>,
     key: &str,
 ) -> Option<VNode<'a>> {
@@ -190,7 +195,19 @@ fn build_node<'a>(
                 None
             }
         }
-        BodyNode::Component(_) => todo!(),
+        BodyNode::Component(comp) => {
+            let expr: Expr = parse2(comp.to_token_stream()).unwrap();
+            if let Some(idx) = ctx
+                .components
+                .iter()
+                .position(|(code, _)| parse_str::<Expr>(*code).unwrap() == expr)
+            {
+                let (_, vnode) = ctx.components.remove(idx);
+                Some(vnode)
+            } else {
+                panic!("could not resolve component {:?}", comp.name);
+            }
+        }
         BodyNode::RawExpr(_) => todo!(),
         BodyNode::Meta(_) => todo!(),
     }

+ 1 - 1
packages/rsx_interperter/src/lib.rs

@@ -34,7 +34,7 @@ pub fn with_hot_reload(cx: Scope<Component>) -> Element {
 pub fn interpert_rsx<'a, 'b>(
     factory: dioxus_core::NodeFactory<'a>,
     text: &str,
-    context: captuered_context::CapturedContext,
+    context: captuered_context::CapturedContext<'a>,
 ) -> VNode<'a> {
     build(parse_str(text).unwrap(), context, &factory)
 }