瀏覽代碼

fix rendering

Evan Almloff 3 年之前
父節點
當前提交
3b06059834

+ 56 - 18
benches/tui_update.rs

@@ -10,50 +10,64 @@ fn tui_update(c: &mut Criterion) {
     let mut group = c.benchmark_group("Update boxes");
     let mut group = c.benchmark_group("Update boxes");
 
 
     // We can also use loops to define multiple benchmarks, even over multiple dimensions.
     // We can also use loops to define multiple benchmarks, even over multiple dimensions.
-    for size in 1..=6 {
-        let parameter_string = format!("{}", 5 * size);
+    for size in 1..=8u32 {
+        let parameter_string = format!("{}", (3 * size).pow(2));
         group.bench_with_input(
         group.bench_with_input(
             BenchmarkId::new("size", parameter_string),
             BenchmarkId::new("size", parameter_string),
             &size,
             &size,
             |b, size| {
             |b, size| {
                 b.iter(|| match size {
                 b.iter(|| match size {
                     1 => dioxus::tui::launch_cfg(
                     1 => dioxus::tui::launch_cfg(
-                        app5,
+                        app3,
                         Config {
                         Config {
                             headless: true,
                             headless: true,
                             ..Default::default()
                             ..Default::default()
                         },
                         },
                     ),
                     ),
                     2 => dioxus::tui::launch_cfg(
                     2 => dioxus::tui::launch_cfg(
-                        app10,
+                        app6,
                         Config {
                         Config {
                             headless: true,
                             headless: true,
                             ..Default::default()
                             ..Default::default()
                         },
                         },
                     ),
                     ),
                     3 => dioxus::tui::launch_cfg(
                     3 => dioxus::tui::launch_cfg(
-                        app15,
+                        app9,
                         Config {
                         Config {
                             headless: true,
                             headless: true,
                             ..Default::default()
                             ..Default::default()
                         },
                         },
                     ),
                     ),
                     4 => dioxus::tui::launch_cfg(
                     4 => dioxus::tui::launch_cfg(
-                        app20,
+                        app12,
                         Config {
                         Config {
                             headless: true,
                             headless: true,
                             ..Default::default()
                             ..Default::default()
                         },
                         },
                     ),
                     ),
                     5 => dioxus::tui::launch_cfg(
                     5 => dioxus::tui::launch_cfg(
-                        app25,
+                        app15,
                         Config {
                         Config {
                             headless: true,
                             headless: true,
                             ..Default::default()
                             ..Default::default()
                         },
                         },
                     ),
                     ),
                     6 => dioxus::tui::launch_cfg(
                     6 => dioxus::tui::launch_cfg(
-                        app30,
+                        app18,
+                        Config {
+                            headless: true,
+                            ..Default::default()
+                        },
+                    ),
+                    7 => dioxus::tui::launch_cfg(
+                        app21,
+                        Config {
+                            headless: true,
+                            ..Default::default()
+                        },
+                    ),
+                    8 => dioxus::tui::launch_cfg(
+                        app24,
                         Config {
                         Config {
                             headless: true,
                             headless: true,
                             ..Default::default()
                             ..Default::default()
@@ -157,25 +171,49 @@ fn Grid(cx: Scope<GridProps>) -> Element {
     })
     })
 }
 }
 
 
-fn app5(cx: Scope) -> Element {
+fn app3(cx: Scope) -> Element {
+    cx.render(rsx! {
+        div{
+            width: "100%",
+            height: "100%",
+            Grid{
+                size: 3,
+            }
+        }
+    })
+}
+
+fn app6(cx: Scope) -> Element {
+    cx.render(rsx! {
+        div{
+            width: "100%",
+            height: "100%",
+            Grid{
+                size: 6,
+            }
+        }
+    })
+}
+
+fn app9(cx: Scope) -> Element {
     cx.render(rsx! {
     cx.render(rsx! {
         div{
         div{
             width: "100%",
             width: "100%",
             height: "100%",
             height: "100%",
             Grid{
             Grid{
-                size: 5,
+                size: 9,
             }
             }
         }
         }
     })
     })
 }
 }
 
 
-fn app10(cx: Scope) -> Element {
+fn app12(cx: Scope) -> Element {
     cx.render(rsx! {
     cx.render(rsx! {
         div{
         div{
             width: "100%",
             width: "100%",
             height: "100%",
             height: "100%",
             Grid{
             Grid{
-                size: 10,
+                size: 12,
             }
             }
         }
         }
     })
     })
@@ -193,37 +231,37 @@ fn app15(cx: Scope) -> Element {
     })
     })
 }
 }
 
 
-fn app20(cx: Scope) -> Element {
+fn app18(cx: Scope) -> Element {
     cx.render(rsx! {
     cx.render(rsx! {
         div{
         div{
             width: "100%",
             width: "100%",
             height: "100%",
             height: "100%",
             Grid{
             Grid{
-                size: 20,
+                size: 18,
             }
             }
         }
         }
     })
     })
 }
 }
 
 
-fn app25(cx: Scope) -> Element {
+fn app21(cx: Scope) -> Element {
     cx.render(rsx! {
     cx.render(rsx! {
         div{
         div{
             width: "100%",
             width: "100%",
             height: "100%",
             height: "100%",
             Grid{
             Grid{
-                size: 25,
+                size: 21,
             }
             }
         }
         }
     })
     })
 }
 }
 
 
-fn app30(cx: Scope) -> Element {
+fn app24(cx: Scope) -> Element {
     cx.render(rsx! {
     cx.render(rsx! {
         div{
         div{
             width: "100%",
             width: "100%",
             height: "100%",
             height: "100%",
             Grid{
             Grid{
-                size: 30,
+                size: 24,
             }
             }
         }
         }
     })
     })

+ 31 - 8
packages/native-core-macro/src/lib.rs

@@ -4,12 +4,35 @@ use proc_macro::TokenStream;
 use quote::{quote, ToTokens};
 use quote::{quote, ToTokens};
 use syn::{
 use syn::{
     self,
     self,
-    parse::{Parse, ParseStream},
+    parse::{Parse, ParseStream, Result},
     punctuated::Punctuated,
     punctuated::Punctuated,
     token::Paren,
     token::Paren,
-    Field, Ident, Token, Type, TypeTuple,
+    Field, Ident, LitStr, Token, Type, TypeTuple,
 };
 };
 
 
+// struct StrSlice {
+//     init: LitStr,
+// }
+
+// impl Parse for StrSlice {
+//     fn parse(input: ParseStream) -> Result<Self> {
+//         input.parse::<Token![[]>()?;
+//         let str: LitStr = input.parse()?;
+//         let name: Ident = input.parse()?;
+//         input.parse::<Token![,]>()?;
+//         input.parse::<Token![]]>()?;
+//         Ok(LazyStatic {
+//             visibility,
+//             name,
+//             ty,
+//             init,
+//         })
+//     }
+// }
+
+// #[proc_macro]
+// pub fn sorted_str_slice(input: TokenStream) -> TokenStream {}
+
 #[derive(PartialEq)]
 #[derive(PartialEq)]
 enum DepKind {
 enum DepKind {
     NodeDepState,
     NodeDepState,
@@ -105,7 +128,7 @@ fn impl_derive_macro(ast: &syn::DeriveInput) -> TokenStream {
 
 
     let gen = quote! {
     let gen = quote! {
         impl State for #type_name{
         impl State for #type_name{
-            fn update_node_dep_state<'a>(&'a mut self, ty: std::any::TypeId, node: &'a dioxus_core::VNode<'a>, ctx: &anymap::AnyMap) -> bool{
+        fn update_node_dep_state<'a>(&'a mut self, ty: std::any::TypeId, node: &'a dioxus_core::VNode<'a>, vdom: &'a dioxus_core::VirtualDom, ctx: &anymap::AnyMap) -> bool{
                 use dioxus_native_core::state::NodeDepState as _;
                 use dioxus_native_core::state::NodeDepState as _;
                 // println!("called update_node_dep_state with ty: {:?}", ty);
                 // println!("called update_node_dep_state with ty: {:?}", ty);
                 if false {
                 if false {
@@ -117,7 +140,7 @@ fn impl_derive_macro(ast: &syn::DeriveInput) -> TokenStream {
                 }
                 }
             }
             }
 
 
-            fn update_parent_dep_state<'a>(&'a mut self, ty: std::any::TypeId, node: &'a dioxus_core::VNode<'a>, parent: Option<&Self>, ctx: &anymap::AnyMap) -> bool{
+            fn update_parent_dep_state<'a>(&'a mut self, ty: std::any::TypeId, node: &'a dioxus_core::VNode<'a>, vdom: &'a dioxus_core::VirtualDom, parent: Option<&Self>, ctx: &anymap::AnyMap) -> bool{
                 use dioxus_native_core::state::ParentDepState as _;
                 use dioxus_native_core::state::ParentDepState as _;
                 // println!("called update_parent_dep_state with ty: {:?}", ty);
                 // println!("called update_parent_dep_state with ty: {:?}", ty);
                 if false {
                 if false {
@@ -129,7 +152,7 @@ fn impl_derive_macro(ast: &syn::DeriveInput) -> TokenStream {
                 }
                 }
             }
             }
 
 
-            fn update_child_dep_state<'a>(&'a mut self, ty: std::any::TypeId, node: &'a dioxus_core::VNode<'a>, children: &[&Self], ctx: &anymap::AnyMap) -> bool{
+            fn update_child_dep_state<'a>(&'a mut self, ty: std::any::TypeId, node: &'a dioxus_core::VNode<'a>, vdom: &'a dioxus_core::VirtualDom, children: &[&Self], ctx: &anymap::AnyMap) -> bool{
                 use dioxus_native_core::state::ChildDepState as _;
                 use dioxus_native_core::state::ChildDepState as _;
                 // println!("called update_child_dep_state with ty: {:?}", ty);
                 // println!("called update_child_dep_state with ty: {:?}", ty);
                 if false {
                 if false {
@@ -205,7 +228,7 @@ struct DepTypes {
 }
 }
 
 
 impl Parse for DepTypes {
 impl Parse for DepTypes {
-    fn parse(input: ParseStream) -> Result<Self, syn::Error> {
+    fn parse(input: ParseStream) -> Result<Self> {
         let dep_ty = input.parse().ok();
         let dep_ty = input.parse().ok();
         let comma: Option<Token![,]> = input.parse().ok();
         let comma: Option<Token![,]> = input.parse().ok();
         let ctx_ty = input.parse().ok();
         let ctx_ty = input.parse().ok();
@@ -221,7 +244,7 @@ struct NodeDepTypes {
 }
 }
 
 
 impl Parse for NodeDepTypes {
 impl Parse for NodeDepTypes {
-    fn parse(input: ParseStream) -> Result<Self, syn::Error> {
+    fn parse(input: ParseStream) -> Result<Self> {
         let ctx_ty = input.parse().ok();
         let ctx_ty = input.parse().ok();
         Ok(Self { ctx_ty })
         Ok(Self { ctx_ty })
     }
     }
@@ -307,7 +330,7 @@ impl<'a> StateMember<'a> {
             quote! {&()}
             quote! {&()}
         };
         };
         let ty = &self.mem.ty;
         let ty = &self.mem.ty;
-        let node_view = quote!(NodeView::new(node, #ty::NODE_MASK));
+        let node_view = quote!(NodeView::new(node, #ty::NODE_MASK, vdom));
         if let Some(dep_ident) = &self.dep_mem.map(|m| &m.ident) {
         if let Some(dep_ident) = &self.dep_mem.map(|m| &m.ident) {
             match self.dep_kind {
             match self.dep_kind {
                 DepKind::NodeDepState => {
                 DepKind::NodeDepState => {

+ 368 - 0
packages/native-core-macro/src/lib.rs~Stashed changes

@@ -0,0 +1,368 @@
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+use quote::{quote, ToTokens};
+use syn::{
+    self,
+    parse::{Parse, ParseStream, Result},
+    punctuated::Punctuated,
+    token::Paren,
+    Field, Ident, LitStr, Token, Type, TypeTuple,
+};
+
+// struct StrSlice {
+//     init: LitStr,
+// }
+
+// impl Parse for StrSlice {
+//     fn parse(input: ParseStream) -> Result<Self> {
+//         input.parse::<Token![[]>()?;
+//         let str: LitStr = input.parse()?;
+//         let name: Ident = input.parse()?;
+//         input.parse::<Token![,]>()?;
+//         input.parse::<Token![]]>()?;
+//         Ok(LazyStatic {
+//             visibility,
+//             name,
+//             ty,
+//             init,
+//         })
+//     }
+// }
+
+// #[proc_macro]
+// pub fn sorted_str_slice(input: TokenStream) -> TokenStream {}
+
+#[derive(PartialEq)]
+enum DepKind {
+    NodeDepState,
+    ChildDepState,
+    ParentDepState,
+}
+
+// macro that streams data from the State for any attributes that end with _
+#[proc_macro_derive(State, attributes(node_dep_state, child_dep_state, parent_dep_state))]
+pub fn state_macro_derive(input: TokenStream) -> TokenStream {
+    let ast = syn::parse(input).unwrap();
+    impl_derive_macro(&ast)
+}
+
+fn impl_derive_macro(ast: &syn::DeriveInput) -> TokenStream {
+    let type_name = &ast.ident;
+    let fields: Vec<_> = match &ast.data {
+        syn::Data::Struct(data) => match &data.fields {
+            syn::Fields::Named(e) => &e.named,
+            syn::Fields::Unnamed(_) => todo!("unnamed fields"),
+            syn::Fields::Unit => todo!("unit fields"),
+        }
+        .iter()
+        .collect(),
+        _ => unimplemented!(),
+    };
+    let strct = Struct::parse(&fields);
+    let state_strct = StateStruct::parse(&fields, &strct);
+
+    let node_dep_state_fields = quote::__private::TokenStream::from_iter(
+        state_strct
+            .state_members
+            .iter()
+            .filter(|f| f.dep_kind == DepKind::NodeDepState)
+            .map(|f| {
+                let ty_id = &f.type_id();
+                let reduce = &f.reduce_self();
+                quote! {
+                    else if ty == #ty_id {
+                        #reduce
+                    }
+                }
+            }),
+    );
+    let child_dep_state_fields = quote::__private::TokenStream::from_iter(
+        state_strct
+            .state_members
+            .iter()
+            .filter(|f| f.dep_kind == DepKind::ChildDepState)
+            .map(|f| {
+                let ty_id = &f.type_id();
+                let reduce = &f.reduce_self();
+                quote! {
+                    else if ty == #ty_id {
+                        #reduce
+                    }
+                }
+            }),
+    );
+    let parent_dep_state_fields = quote::__private::TokenStream::from_iter(
+        state_strct
+            .state_members
+            .iter()
+            .filter(|f| f.dep_kind == DepKind::ParentDepState)
+            .map(|f| {
+                let ty_id = &f.type_id();
+                let reduce = &f.reduce_self();
+                quote! {
+                    else if ty == #ty_id {
+                        #reduce
+                    }
+                }
+            }),
+    );
+
+    let node_types = state_strct
+        .state_members
+        .iter()
+        .filter(|f| f.dep_kind == DepKind::NodeDepState)
+        .map(|f| &f.mem.ty);
+    let child_types = state_strct
+        .state_members
+        .iter()
+        .filter(|f| f.dep_kind == DepKind::ChildDepState)
+        .map(|f| &f.mem.ty);
+    let parent_types = state_strct
+        .state_members
+        .iter()
+        .filter(|f| f.dep_kind == DepKind::ParentDepState)
+        .map(|f| &f.mem.ty);
+
+    let type_name_str = type_name.to_string();
+
+    let gen = quote! {
+        impl State for #type_name{
+        fn update_node_dep_state<'a>(&'a mut self, ty: std::any::TypeId, node: &'a dioxus_core::VNode<'a>, vdom: &'a dioxus_core::VirtualDom, ctx: &anymap::AnyMap) -> bool{
+                use dioxus_native_core::state::NodeDepState as _;
+                // println!("called update_node_dep_state with ty: {:?}", ty);
+                if false {
+                    unreachable!();
+                }
+                #node_dep_state_fields
+                else{
+                    panic!("{:?} not in {}", ty, #type_name_str)
+                }
+            }
+
+            fn update_parent_dep_state<'a>(&'a mut self, ty: std::any::TypeId, node: &'a dioxus_core::VNode<'a>, vdom: &'a dioxus_core::VirtualDom, parent: Option<&Self>, ctx: &anymap::AnyMap) -> bool{
+                use dioxus_native_core::state::ParentDepState as _;
+                // println!("called update_parent_dep_state with ty: {:?}", ty);
+                if false {
+                    unreachable!();
+                }
+                #parent_dep_state_fields
+                else{
+                    panic!("{:?} not in {}", ty, #type_name_str)
+                }
+            }
+
+            fn update_child_dep_state<'a>(&'a mut self, ty: std::any::TypeId, node: &'a dioxus_core::VNode<'a>, vdom: &'a dioxus_core::VirtualDom, children: &[&Self], ctx: &anymap::AnyMap) -> bool{
+                use dioxus_native_core::state::ChildDepState as _;
+                // println!("called update_child_dep_state with ty: {:?}", ty);
+                if false {
+                    unreachable!()
+                }
+                #child_dep_state_fields
+                else{
+                    panic!("{:?} not in {}", ty, #type_name_str)
+                }
+            }
+
+            fn child_dep_types(&self, mask: &dioxus_native_core::state::NodeMask) -> Vec<std::any::TypeId>{
+                let mut dep_types = Vec::new();
+                #(if #child_types::NODE_MASK.overlaps(mask) {
+                    dep_types.push(std::any::TypeId::of::<#child_types>());
+                })*
+                dep_types
+            }
+
+            fn parent_dep_types(&self, mask: &dioxus_native_core::state::NodeMask) -> Vec<std::any::TypeId>{
+                let mut dep_types = Vec::new();
+                #(if #parent_types::NODE_MASK.overlaps(mask) {
+                    dep_types.push(std::any::TypeId::of::<#parent_types>());
+                })*
+                dep_types
+            }
+
+            fn node_dep_types(&self, mask: &dioxus_native_core::state::NodeMask) -> Vec<std::any::TypeId>{
+                let mut dep_types = Vec::new();
+                #(if #node_types::NODE_MASK.overlaps(mask) {
+                    dep_types.push(std::any::TypeId::of::<#node_types>());
+                })*
+                dep_types
+            }
+        }
+    };
+    gen.into()
+}
+
+struct Struct {
+    members: Vec<Member>,
+}
+
+impl Struct {
+    fn parse(fields: &[&Field]) -> Self {
+        let members = fields.iter().filter_map(|f| Member::parse(f)).collect();
+        Self { members }
+    }
+}
+
+struct StateStruct<'a> {
+    state_members: Vec<StateMember<'a>>,
+}
+
+impl<'a> StateStruct<'a> {
+    fn parse(fields: &[&'a Field], strct: &'a Struct) -> Self {
+        let state_members = strct
+            .members
+            .iter()
+            .zip(fields.iter())
+            .filter_map(|(m, f)| StateMember::parse(f, m, &strct))
+            .collect();
+
+        // todo: sort members
+
+        Self { state_members }
+    }
+}
+
+struct DepTypes {
+    ctx_ty: Option<Type>,
+    dep_ty: Option<Type>,
+}
+
+impl Parse for DepTypes {
+    fn parse(input: ParseStream) -> Result<Self> {
+        let dep_ty = input.parse().ok();
+        let comma: Option<Token![,]> = input.parse().ok();
+        let ctx_ty = input.parse().ok();
+        Ok(Self {
+            ctx_ty: comma.and(ctx_ty),
+            dep_ty,
+        })
+    }
+}
+
+struct NodeDepTypes {
+    ctx_ty: Option<Type>,
+}
+
+impl Parse for NodeDepTypes {
+    fn parse(input: ParseStream) -> Result<Self> {
+        let ctx_ty = input.parse().ok();
+        Ok(Self { ctx_ty })
+    }
+}
+
+impl From<NodeDepTypes> for DepTypes {
+    fn from(node_dep_types: NodeDepTypes) -> Self {
+        Self {
+            ctx_ty: node_dep_types.ctx_ty,
+            dep_ty: None,
+        }
+    }
+}
+
+struct Member {
+    ty: Type,
+    ident: Ident,
+}
+
+impl Member {
+    fn parse(field: &Field) -> Option<Self> {
+        Some(Self {
+            ty: field.ty.clone(),
+            ident: field.ident.as_ref()?.clone(),
+        })
+    }
+}
+
+struct StateMember<'a> {
+    mem: &'a Member,
+    dep_kind: DepKind,
+    dep_mem: Option<&'a Member>,
+    ctx_ty: Option<Type>,
+}
+
+impl<'a> StateMember<'a> {
+    fn parse(field: &Field, mem: &'a Member, parent: &'a Struct) -> Option<StateMember<'a>> {
+        field.attrs.iter().find_map(|a| {
+            let dep_kind = a
+                .path
+                .get_ident()
+                .map(|i| match i.to_string().as_str() {
+                    "node_dep_state" => Some(DepKind::NodeDepState),
+                    "child_dep_state" => Some(DepKind::ChildDepState),
+                    "parent_dep_state" => Some(DepKind::ParentDepState),
+                    _ => None,
+                })
+                .flatten()?;
+            let deps: DepTypes = match dep_kind {
+                DepKind::NodeDepState => a.parse_args::<NodeDepTypes>().ok()?.into(),
+                _ => a.parse_args().ok()?,
+            };
+
+            Some(Self {
+                mem,
+                dep_kind,
+                dep_mem: deps
+                    .dep_ty
+                    .map(|ty| parent.members.iter().find(|m| m.ty == ty))
+                    .flatten(),
+                ctx_ty: deps.ctx_ty,
+            })
+        })
+    }
+
+    fn reduce_self(&self) -> quote::__private::TokenStream {
+        let ident = &self.mem.ident;
+        let get_ctx = if let Some(ctx_ty) = &self.ctx_ty {
+            if ctx_ty
+                == &Type::Tuple(TypeTuple {
+                    paren_token: Paren {
+                        span: quote::__private::Span::call_site(),
+                    },
+                    elems: Punctuated::new(),
+                })
+            {
+                quote! {&()}
+            } else {
+                let msg = ctx_ty.to_token_stream().to_string() + " not found in context";
+                quote! {ctx.get().expect(#msg)}
+            }
+        } else {
+            quote! {&()}
+        };
+        let ty = &self.mem.ty;
+        let node_view = quote!(NodeView::new(node, #ty::NODE_MASK, vdom));
+        if let Some(dep_ident) = &self.dep_mem.map(|m| &m.ident) {
+            match self.dep_kind {
+                DepKind::NodeDepState => {
+                    quote!(self.#ident.reduce(#node_view, #get_ctx))
+                }
+                DepKind::ChildDepState => {
+                    quote!(self.#ident.reduce(#node_view, children.iter().map(|s| &s.#dep_ident), #get_ctx))
+                }
+                DepKind::ParentDepState => {
+                    quote!(self.#ident.reduce(#node_view, parent.as_ref().map(|p| &p.#dep_ident), #get_ctx))
+                }
+            }
+        } else {
+            match self.dep_kind {
+                DepKind::NodeDepState => {
+                    quote!(self.#ident.reduce(#node_view, #get_ctx))
+                }
+                DepKind::ChildDepState => {
+                    quote!(self.#ident.reduce(#node_view, &(), #get_ctx))
+                }
+                DepKind::ParentDepState => {
+                    quote!(self.#ident.reduce(#node_view, Some(&()), #get_ctx))
+                }
+            }
+        }
+    }
+
+    fn type_id(&self) -> quote::__private::TokenStream {
+        let ty = &self.mem.ty;
+        quote!({
+            let type_id = std::any::TypeId::of::<#ty>();
+            type_id
+        })
+    }
+}

+ 2 - 0
packages/native-core/src/layout_attributes.rs

@@ -29,6 +29,8 @@
 - [ ] pub aspect_ratio: Number,
 - [ ] pub aspect_ratio: Number,
 */
 */
 
 
+// align-content,align-items,align-self,animation,animation-delay,animation-direction,animation-duration,animation-fill-mode,animation-iteration-count,animation-name,animation-play-state,animation-timing-function,backface-visibility,border,border-bottom,border-bottom-color,border-bottom-left-radius,border-bottom-right-radius,border-bottom-style,border-bottom-width,border-collapse,border-color,border-image,border-image-outset,border-image-repeat,border-image-slice,border-image-source,border-image-width,border-left,border-left-color,border-left-style,border-left-width,border-radius,border-right,border-right-color,border-right-style,border-right-width,border-spacing,border-style,border-top,border-top-color,border-top-left-radius,border-top-right-radius,border-top-style,border-top-width,border-width,bottom,box-shadow,box-sizing,caption-side,clear,clip,column-count,column-fill,column-gap,column-rule,column-rule-color,column-rule-style,column-rule-width,column-span,column-width,columns,content,counter-increment,counter-reset,cursor,direction,ltr,rtl,display,empty-cells,flex,flex-basis,flex-direction,flex-flow,flex-grow,flex-shrink,flex-wrap,float,height,justify-content,flex-start,flex-end,center,space-between,space-around,space-evenly,left,letter-spacing,line-height,list-style,list-style-image,list-style-position,list-style-type,margin,margin-bottom,margin-left,margin-right,margin-top,max-height,max-width,min-height,min-width,opacity,order,outline,outline-color,outline-offset,outline-style,outline-width,overflow,overflow-x,overflow-y,padding,padding-bottom,padding-left,padding-right,padding-top,page-break-after,page-break-before,page-break-inside,perspective,perspective-origin,position,static,relative,fixed,absolute,sticky,pointer-events,quotes,resize,right,tab-size,table-layout,top,transform,transform-origin,transform-style,transition,transition-delay,transition-duration,transition-property,transition-timing-function,vertical-align,visibility,white-space,width,word-break,word-spacing,word-wrap,z-index
+
 use stretch2::{prelude::*, style::PositionType};
 use stretch2::{prelude::*, style::PositionType};
 
 
 /// applies the entire html namespace defined in dioxus-html
 /// applies the entire html namespace defined in dioxus-html

+ 3 - 2
packages/native-core/src/real_dom.rs

@@ -301,7 +301,7 @@ impl<S: State> RealDom<S> {
             for ty in ids {
             for ty in ids {
                 let node = &mut self[node_ref.id];
                 let node = &mut self[node_ref.id];
                 let vnode = node.element(vdom);
                 let vnode = node.element(vdom);
-                changed |= node.state.update_node_dep_state(ty, vnode, &ctx);
+                changed |= node.state.update_node_dep_state(ty, vnode, vdom, &ctx);
             }
             }
             if changed {
             if changed {
                 to_rerender.insert(node_ref.id);
                 to_rerender.insert(node_ref.id);
@@ -328,7 +328,7 @@ impl<S: State> RealDom<S> {
                 let vnode = node.element(vdom);
                 let vnode = node.element(vdom);
                 if node
                 if node
                     .state
                     .state
-                    .update_child_dep_state(ty, vnode, &children_state, &ctx)
+                    .update_child_dep_state(ty, vnode, vdom, &children_state, &ctx)
                 {
                 {
                     changed.push(ty);
                     changed.push(ty);
                 }
                 }
@@ -387,6 +387,7 @@ impl<S: State> RealDom<S> {
                 if state.update_parent_dep_state(
                 if state.update_parent_dep_state(
                     ty,
                     ty,
                     vnode,
                     vnode,
+                    vdom,
                     parent.filter(|n| n.id.0 != 0).map(|n| &n.state),
                     parent.filter(|n| n.id.0 != 0).map(|n| &n.state),
                     &ctx,
                     &ctx,
                 ) {
                 ) {

+ 9 - 2
packages/native-core/src/state.rs

@@ -1,7 +1,7 @@
 use std::{any::TypeId, fmt::Debug};
 use std::{any::TypeId, fmt::Debug};
 
 
 use anymap::AnyMap;
 use anymap::AnyMap;
-use dioxus_core::{Attribute, ElementId, VElement, VNode, VText};
+use dioxus_core::{Attribute, ElementId, VElement, VNode, VText, VirtualDom};
 
 
 pub(crate) fn union_ordered_iter<T: Ord + Debug>(
 pub(crate) fn union_ordered_iter<T: Ord + Debug>(
     s_iter: impl Iterator<Item = T>,
     s_iter: impl Iterator<Item = T>,
@@ -40,7 +40,11 @@ pub struct NodeView<'a> {
     mask: NodeMask,
     mask: NodeMask,
 }
 }
 impl<'a> NodeView<'a> {
 impl<'a> NodeView<'a> {
-    pub fn new(vnode: &'a VNode<'a>, view: NodeMask) -> Self {
+    pub fn new(mut vnode: &'a VNode<'a>, view: NodeMask, vdom: &'a VirtualDom) -> Self {
+        if let VNode::Component(sc) = vnode {
+            let scope = vdom.get_scope(sc.scope.get().unwrap()).unwrap();
+            vnode = scope.root_node();
+        }
         Self {
         Self {
             inner: vnode,
             inner: vnode,
             mask: view,
             mask: view,
@@ -284,6 +288,7 @@ pub trait State: Default + Clone {
         &'a mut self,
         &'a mut self,
         ty: TypeId,
         ty: TypeId,
         node: &'a VNode<'a>,
         node: &'a VNode<'a>,
+        vdom: &'a dioxus_core::VirtualDom,
         ctx: &AnyMap,
         ctx: &AnyMap,
     ) -> bool;
     ) -> bool;
     /// This must be a valid resolution order. (no nodes updated before a state they rely on)
     /// This must be a valid resolution order. (no nodes updated before a state they rely on)
@@ -293,6 +298,7 @@ pub trait State: Default + Clone {
         &'a mut self,
         &'a mut self,
         ty: TypeId,
         ty: TypeId,
         node: &'a VNode<'a>,
         node: &'a VNode<'a>,
+        vdom: &'a dioxus_core::VirtualDom,
         parent: Option<&Self>,
         parent: Option<&Self>,
         ctx: &AnyMap,
         ctx: &AnyMap,
     ) -> bool;
     ) -> bool;
@@ -303,6 +309,7 @@ pub trait State: Default + Clone {
         &'a mut self,
         &'a mut self,
         ty: TypeId,
         ty: TypeId,
         node: &'a VNode<'a>,
         node: &'a VNode<'a>,
+        vdom: &'a dioxus_core::VirtualDom,
         children: &[&Self],
         children: &[&Self],
         ctx: &AnyMap,
         ctx: &AnyMap,
     ) -> bool;
     ) -> bool;

+ 0 - 6
packages/native-core/tests/parse.rs

@@ -14,12 +14,6 @@ struct Z {
     z: C,
     z: C,
 }
 }
 
 
-// struct Z {
-//     x: A,
-//     y: B,
-//     z: C,
-// }
-
 use dioxus_native_core::state::NodeDepState;
 use dioxus_native_core::state::NodeDepState;
 
 
 #[derive(Default, Clone)]
 #[derive(Default, Clone)]

+ 17 - 11
packages/tui/src/layout.rs

@@ -28,11 +28,13 @@ impl ChildDepState for StretchLayout {
     where
     where
         Self::DepState: 'a,
         Self::DepState: 'a,
     {
     {
+        let mut changed = false;
         let mut stretch = ctx.borrow_mut();
         let mut stretch = ctx.borrow_mut();
+        let mut style = Style::default();
         if let Some(text) = node.text() {
         if let Some(text) = node.text() {
             let char_len = text.chars().count();
             let char_len = text.chars().count();
 
 
-            let style = Style {
+            style = Style {
                 size: Size {
                 size: Size {
                     // characters are 1 point tall
                     // characters are 1 point tall
                     height: Dimension::Points(1.0),
                     height: Dimension::Points(1.0),
@@ -42,7 +44,6 @@ impl ChildDepState for StretchLayout {
                 },
                 },
                 ..Default::default()
                 ..Default::default()
             };
             };
-
             if let Some(n) = self.node {
             if let Some(n) = self.node {
                 if self.style != style {
                 if self.style != style {
                     stretch.set_style(n, style).unwrap();
                     stretch.set_style(n, style).unwrap();
@@ -50,12 +51,8 @@ impl ChildDepState for StretchLayout {
             } else {
             } else {
                 self.node = Some(stretch.new_node(style, &[]).unwrap());
                 self.node = Some(stretch.new_node(style, &[]).unwrap());
             }
             }
-
-            self.style = style;
         } else {
         } else {
             // gather up all the styles from the attribute list
             // gather up all the styles from the attribute list
-            let mut style = Style::default();
-
             for &Attribute { name, value, .. } in node.attributes() {
             for &Attribute { name, value, .. } in node.attributes() {
                 apply_layout_attributes(name, value, &mut style);
                 apply_layout_attributes(name, value, &mut style);
             }
             }
@@ -73,18 +70,27 @@ impl ChildDepState for StretchLayout {
             }
             }
 
 
             if let Some(n) = self.node {
             if let Some(n) = self.node {
-                if stretch.children(n).unwrap() != child_layout {
-                    stretch.set_children(n, &child_layout).unwrap();
+                if self.style != style {
+                    stretch.set_style(n, style).unwrap();
                 }
                 }
+            } else {
+                self.node = Some(stretch.new_node(style, &[]).unwrap());
+            }
+            if let Some(n) = self.node {
                 if self.style != style {
                 if self.style != style {
                     stretch.set_style(n, style).unwrap();
                     stretch.set_style(n, style).unwrap();
                 }
                 }
+                if stretch.children(n).unwrap() != child_layout {
+                    stretch.set_children(n, &child_layout).unwrap();
+                }
             } else {
             } else {
-                self.node = Some(stretch.new_node(style, &child_layout).unwrap());
+                self.node = Some(stretch.new_node(style, &[]).unwrap());
             }
             }
-
+        }
+        if self.style != style {
+            changed = true;
             self.style = style;
             self.style = style;
         }
         }
-        true
+        changed
     }
     }
 }
 }

+ 2 - 3
packages/tui/src/lib.rs

@@ -148,8 +148,7 @@ fn render_vdom(
                     fn resize(dims: Rect, stretch: &mut Stretch, rdom: &Dom) {
                     fn resize(dims: Rect, stretch: &mut Stretch, rdom: &Dom) {
                         let width = dims.width;
                         let width = dims.width;
                         let height = dims.height;
                         let height = dims.height;
-                        let root_id = rdom.root_id();
-                        let root_node = rdom[root_id].state.layout.node.unwrap();
+                        let root_node = rdom[0].state.layout.node.unwrap();
 
 
                         stretch
                         stretch
                             .compute_layout(
                             .compute_layout(
@@ -165,7 +164,7 @@ fn render_vdom(
                         terminal.draw(|frame| {
                         terminal.draw(|frame| {
                             // size is guaranteed to not change when rendering
                             // size is guaranteed to not change when rendering
                             resize(frame.size(), &mut stretch.borrow_mut(), &rdom);
                             resize(frame.size(), &mut stretch.borrow_mut(), &rdom);
-                            let root = &rdom[rdom.root_id()];
+                            let root = &rdom[0];
                             render::render_vnode(frame, &stretch.borrow(), &rdom, &root, cfg);
                             render::render_vnode(frame, &stretch.borrow(), &rdom, &root, cfg);
                         })?;
                         })?;
                     } else {
                     } else {

+ 1 - 0
packages/tui/src/render.rs

@@ -30,6 +30,7 @@ pub(crate) fn render_vnode(
     }
     }
 
 
     let Layout { location, size, .. } = layout.layout(node.state.layout.node.unwrap()).unwrap();
     let Layout { location, size, .. } = layout.layout(node.state.layout.node.unwrap()).unwrap();
+    // println!("rendering {node:?} {location:?} {size:?}");
 
 
     let Point { x, y } = location;
     let Point { x, y } = location;
     let Size { width, height } = size;
     let Size { width, height } = size;

+ 19 - 14
packages/tui/src/style_attributes.rs

@@ -50,22 +50,22 @@ impl ParentDepState for StyleModifier {
     const NODE_MASK: NodeMask = NodeMask::new(AttributeMask::All, true, true, false);
     const NODE_MASK: NodeMask = NodeMask::new(AttributeMask::All, true, true, false);
 
 
     fn reduce(&mut self, node: NodeView, parent: Option<&Self::DepState>, _: &Self::Ctx) -> bool {
     fn reduce(&mut self, node: NodeView, parent: Option<&Self::DepState>, _: &Self::Ctx) -> bool {
-        *self = StyleModifier::default();
+        let mut new = StyleModifier::default();
         if parent.is_some() {
         if parent.is_some() {
-            self.style.fg = None;
+            new.style.fg = None;
         }
         }
 
 
         // handle text modifier elements
         // handle text modifier elements
         if node.namespace().is_none() {
         if node.namespace().is_none() {
             if let Some(tag) = node.tag() {
             if let Some(tag) = node.tag() {
                 match tag {
                 match tag {
-                    "b" => apply_style_attributes("font-weight", "bold", self),
-                    "strong" => apply_style_attributes("font-weight", "bold", self),
-                    "u" => apply_style_attributes("text-decoration", "underline", self),
-                    "ins" => apply_style_attributes("text-decoration", "underline", self),
-                    "del" => apply_style_attributes("text-decoration", "line-through", self),
-                    "i" => apply_style_attributes("font-style", "italic", self),
-                    "em" => apply_style_attributes("font-style", "italic", self),
+                    "b" => apply_style_attributes("font-weight", "bold", &mut new),
+                    "strong" => apply_style_attributes("font-weight", "bold", &mut new),
+                    "u" => apply_style_attributes("text-decoration", "underline", &mut new),
+                    "ins" => apply_style_attributes("text-decoration", "underline", &mut new),
+                    "del" => apply_style_attributes("text-decoration", "line-through", &mut new),
+                    "i" => apply_style_attributes("font-style", "italic", &mut new),
+                    "em" => apply_style_attributes("font-style", "italic", &mut new),
                     "mark" => {
                     "mark" => {
                         apply_style_attributes("background-color", "rgba(241, 231, 64, 50%)", self)
                         apply_style_attributes("background-color", "rgba(241, 231, 64, 50%)", self)
                     }
                     }
@@ -76,16 +76,21 @@ impl ParentDepState for StyleModifier {
 
 
         // gather up all the styles from the attribute list
         // gather up all the styles from the attribute list
         for &Attribute { name, value, .. } in node.attributes() {
         for &Attribute { name, value, .. } in node.attributes() {
-            apply_style_attributes(name, value, self);
+            apply_style_attributes(name, value, &mut new);
         }
         }
 
 
         // keep the text styling from the parent element
         // keep the text styling from the parent element
         if let Some(parent) = parent {
         if let Some(parent) = parent {
-            let mut new_style = self.style.merge(parent.style);
-            new_style.bg = self.style.bg;
-            self.style = new_style;
+            let mut new_style = new.style.merge(parent.style);
+            new_style.bg = new.style.bg;
+            new.style = new_style;
+        }
+        if &mut new != self {
+            *self = new;
+            true
+        } else {
+            false
         }
         }
-        true
     }
     }
 }
 }