Ver Fonte

update TUI renderer to new approach

Evan Almloff há 2 anos atrás
pai
commit
9efff74c0c

+ 1 - 0
packages/native-core/src/lib.rs

@@ -4,6 +4,7 @@ use std::hash::BuildHasherDefault;
 pub use node_ref::NodeMask;
 pub use passes::AnyMapLike;
 pub use passes::{Dependancy, Pass, TypeErasedPass};
+pub use real_dom::{NodeMut, NodeRef, RealDom};
 use rustc_hash::FxHasher;
 pub use tree::NodeId;
 

+ 9 - 7
packages/native-core/src/node_ref.rs

@@ -262,15 +262,16 @@ impl NodeMaskBuilder {
     /// A node mask with no parts visible.
     pub const NONE: Self = Self::new();
     /// A node mask with every part visible.
-    pub const ALL: Self = Self::new_with_attrs(AttributeMaskBuilder::All)
+    pub const ALL: Self = Self::new()
+        .with_attrs(AttributeMaskBuilder::All)
         .with_text()
         .with_element()
         .with_listeners();
 
-    /// Create a new node mask with the given attributes
-    pub const fn new_with_attrs(attritutes: AttributeMaskBuilder) -> Self {
+    /// Create a empty node mask
+    pub const fn new() -> Self {
         Self {
-            attritutes,
+            attritutes: AttributeMaskBuilder::Some(&[]),
             tag: false,
             namespace: false,
             text: false,
@@ -278,9 +279,10 @@ impl NodeMaskBuilder {
         }
     }
 
-    /// Create a empty node mask
-    pub const fn new() -> Self {
-        Self::new_with_attrs(AttributeMaskBuilder::Some(&[]))
+    /// Allow the mask to view the given attributes
+    pub const fn with_attrs(mut self, attritutes: AttributeMaskBuilder) -> Self {
+        self.attritutes = attritutes;
+        self
     }
 
     /// Allow the mask to view the tag

+ 132 - 63
packages/native-core/src/real_dom.rs

@@ -18,7 +18,7 @@ use crate::{FxDashSet, SendAnyMap};
 ///
 /// # Custom values
 /// To allow custom values to be passed into attributes implement FromAnyValue on a type that can represent your custom value and specify the V generic to be that type. If you have many different custom values, it can be useful to use a enum type to represent the varients.
-pub struct RealDom<V: FromAnyValue + Send = ()> {
+pub struct RealDom<V: FromAnyValue + Send + Sync = ()> {
     pub(crate) tree: Tree,
     /// a map from element id to real node id
     node_id_mapping: Vec<Option<NodeId>>,
@@ -38,7 +38,7 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
     pub fn new(mut passes: Box<[TypeErasedPass<V>]>) -> RealDom<V> {
         let mut tree = Tree::new();
         let root_id = tree.root();
-        let root: &mut NodeData<V> = tree.write(root_id).unwrap();
+        let root: &mut NodeData<V> = tree.get_mut(root_id).unwrap();
         let mut root_node: NodeData<V> = NodeData::new(NodeType::Element(ElementNode {
             tag: "Root".to_string(),
             namespace: Some("Root".to_string()),
@@ -95,7 +95,7 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
     }
 
     fn set_element_id(&mut self, node_id: NodeId, element_id: ElementId) {
-        let mut node = self.tree.write::<NodeData>(node_id).unwrap();
+        let mut node = self.tree.get_mut::<NodeData>(node_id).unwrap();
         let node_id = node.node_id;
         node.element_id = Some(element_id);
         if self.node_id_mapping.len() <= element_id.0 {
@@ -342,14 +342,17 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
 
     /// Find all nodes that are listening for an event, sorted by there height in the dom progressing starting at the bottom and progressing up.
     /// This can be useful to avoid creating duplicate events.
-    pub fn get_listening_sorted(&self, event: &'static str) -> Vec<NodeId> {
+    pub fn get_listening_sorted(&self, event: &'static str) -> Vec<NodeRef<V>> {
         if let Some(nodes) = self.nodes_listening.get(event) {
             let mut listening: Vec<_> = nodes
                 .iter()
                 .map(|id| (*id, self.tree.height(*id).unwrap()))
                 .collect();
             listening.sort_by(|(_, h1), (_, h2)| h1.cmp(h2).reverse());
-            listening.into_iter().map(|(id, _)| id).collect()
+            listening
+                .into_iter()
+                .map(|(id, _)| NodeRef { id, dom: self })
+                .collect()
         } else {
             Vec::new()
         }
@@ -371,7 +374,8 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
         let new_node = node.node_data().clone();
         let new_id = self.create_node(new_node, None, true).id();
 
-        for child in self.tree.children_ids(node_id).unwrap() {
+        let children = self.tree.children_ids(node_id).unwrap().to_vec();
+        for child in children {
             let child_id = self.clone_node(child);
             self.add_child(new_id, child_id);
         }
@@ -382,11 +386,13 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
         self.tree.root()
     }
 
-    pub fn get(&self, id: NodeId) -> Option<NodeRef<'_, V>> {
+    pub fn get(&self, id: impl IntoNodeId<V>) -> Option<NodeRef<'_, V>> {
+        let id = id.into_node_id(self);
         self.tree.contains(id).then_some(NodeRef { id, dom: self })
     }
 
-    pub fn get_mut(&mut self, id: NodeId) -> Option<NodeMut<'_, V>> {
+    pub fn get_mut(&mut self, id: impl IntoNodeId<V>) -> Option<NodeMut<'_, V>> {
+        let id = id.into_node_id(self);
         self.tree.contains(id).then(|| NodeMut {
             id,
             dirty: NodeMask::default(),
@@ -395,8 +401,11 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
     }
 
     /// WARNING: This escapes the reactive system that the real dom uses. Any changes made with this method will not trigger updates in states when [RealDom::update_state] is called.
-    pub fn get_mut_raw(&mut self, id: NodeId) -> Option<&mut NodeData<V>> {
-        self.tree.write(id)
+    pub fn get_mut_raw(&mut self, id: impl IntoNodeId<V>) -> Option<NodeMutRaw<V>> {
+        let id = id.into_node_id(self);
+        self.tree
+            .contains(id)
+            .then_some(NodeMutRaw { id, dom: self })
     }
 
     /// Update the state of the dom, after appling some mutations. This will keep the nodes in the dom up to date with their VNode counterparts.
@@ -499,7 +508,7 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
                 f(node);
                 if let Some(children) = self.tree.children_ids(id) {
                     for id in children {
-                        queue.push_back(id);
+                        queue.push_back(*id);
                     }
                 }
             }
@@ -510,10 +519,11 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
         let mut stack = vec![self.root()];
         while let Some(id) = stack.pop() {
             if let Some(children) = self.tree.children_ids(id) {
+                let children = children.iter().copied().rev().collect::<Vec<_>>();
                 if let Some(node) = self.get_mut(id) {
                     let node = node;
                     f(node);
-                    stack.extend(children.iter().copied().rev());
+                    stack.extend(children.iter());
                 }
             }
         }
@@ -524,6 +534,7 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
         queue.push_back(self.root());
         while let Some(id) = queue.pop_front() {
             if let Some(children) = self.tree.children_ids(id) {
+                let children = children.to_vec();
                 if let Some(node) = self.get_mut(id) {
                     f(node);
                     for id in children {
@@ -535,75 +546,116 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
     }
 }
 
-// impl<V: FromAnyValue> Index<ElementId> for RealDom<V> {
-//     type Output = Node<V>;
+pub trait IntoNodeId<V: FromAnyValue + Send + Sync> {
+    fn into_node_id(self, rdom: &RealDom<V>) -> NodeId;
+}
+
+impl<V: FromAnyValue + Send + Sync> IntoNodeId<V> for NodeId {
+    fn into_node_id(self, _rdom: &RealDom<V>) -> NodeId {
+        self
+    }
+}
+
+impl<V: FromAnyValue + Send + Sync> IntoNodeId<V> for ElementId {
+    fn into_node_id(self, rdom: &RealDom<V>) -> NodeId {
+        rdom.element_to_node_id(self)
+    }
+}
+
+pub trait NodeImmutable<V: FromAnyValue + Send + Sync>: Sized {
+    fn real_dom(&self) -> &RealDom<V>;
+
+    fn id(&self) -> NodeId;
+
+    fn mounted_id(&self) -> Option<ElementId> {
+        self.node_data().mounted_id()
+    }
+
+    fn node_data(&self) -> &NodeData<V> {
+        self.get().unwrap()
+    }
 
-//     fn index(&self, id: ElementId) -> &Self::Output {
-//         self.tree.get(self.element_to_node_id(id)).unwrap()
-//     }
-// }
+    fn node_type(&self) -> &NodeType<V> {
+        &self.node_data().node_type
+    }
 
-// impl<V: FromAnyValue> Index<NodeId> for RealDom<V> {
-//     type Output = Node<V>;
+    fn get<T: Any>(&self) -> Option<&T> {
+        self.real_dom().tree.get(self.id())
+    }
+
+    fn child_ids(&self) -> Option<&[NodeId]> {
+        self.real_dom().tree.children_ids(self.id())
+    }
 
-//     fn index(&self, idx: NodeId) -> &Self::Output {
-//         self.tree.get(idx).unwrap()
-//     }
-// }
+    fn children(&self) -> Option<Vec<NodeRef<V>>> {
+        self.child_ids().map(|ids| {
+            ids.iter()
+                .map(|id| NodeRef {
+                    id: *id,
+                    dom: self.real_dom(),
+                })
+                .collect()
+        })
+    }
 
-// impl<V: FromAnyValue> IndexMut<ElementId> for RealDom<V> {
-//     fn index_mut(&mut self, id: ElementId) -> &mut Self::Output {
-//         self.tree.get_mut(self.element_to_node_id(id)).unwrap()
-//     }
-// }
+    fn parent_id(&self) -> Option<NodeId> {
+        self.real_dom().tree.parent_id(self.id())
+    }
 
-// impl<V: FromAnyValue> IndexMut<NodeId> for RealDom<V> {
-//     fn index_mut(&mut self, idx: NodeId) -> &mut Self::Output {
-//         self.tree.get_mut(idx).unwrap()
-//     }
-// }
+    fn parent(&self) -> Option<NodeRef<V>> {
+        self.parent_id().map(|id| NodeRef {
+            id,
+            dom: self.real_dom(),
+        })
+    }
+}
 
-pub struct NodeRef<'a, V: FromAnyValue + Send = ()> {
+pub trait NodeMutable<V: FromAnyValue + Send + Sync>: Sized + NodeImmutable<V> {
+    fn get_mut<T: Any>(&mut self) -> Option<&mut T>;
+}
+
+#[derive(Clone, Copy)]
+pub struct NodeRef<'a, V: FromAnyValue + Send + Sync = ()> {
     id: NodeId,
     dom: &'a RealDom<V>,
 }
 
-impl<'a, V: FromAnyValue + Send> NodeRef<'a, V> {
-    pub fn node_data(&self) -> &NodeData<V> {
-        self.read().unwrap()
+impl<'a, V: FromAnyValue + Send + Sync> NodeImmutable<V> for NodeRef<'a, V> {
+    fn real_dom(&self) -> &RealDom<V> {
+        self.dom
     }
 
-    pub fn node_type(&self) -> &NodeType<V> {
-        &self.node_data().node_type
-    }
-
-    pub fn read<T: Any>(&self) -> Option<&T> {
-        self.dom.tree.read(self.id)
+    fn id(&self) -> NodeId {
+        self.id
     }
 }
 
-pub struct NodeMut<'a, V: FromAnyValue + Send = ()> {
+pub struct NodeMut<'a, V: FromAnyValue + Send + Sync = ()> {
     id: NodeId,
     dom: &'a mut RealDom<V>,
     dirty: NodeMask,
 }
 
-impl<'a, V: FromAnyValue + Send> NodeMut<'a, V> {
-    fn node_data(&self) -> &NodeData<V> {
-        self.read().unwrap()
+impl<'a, V: FromAnyValue + Send + Sync> NodeImmutable<V> for NodeMut<'a, V> {
+    fn real_dom(&self) -> &RealDom<V> {
+        self.dom
     }
 
-    fn node_data_mut(&mut self) -> &mut NodeData<V> {
-        self.dom.tree.write(self.id).unwrap()
+    fn id(&self) -> NodeId {
+        self.id
     }
+}
 
-    pub fn node_type(&self) -> &NodeType<V> {
-        &self.node_data().node_type
+impl<'a, V: FromAnyValue + Send + Sync> NodeMutable<V> for NodeMut<'a, V> {
+    fn get_mut<T: Any>(&mut self) -> Option<&mut T> {
+        todo!("get_mut with mark as dirty")
     }
+}
 
+impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> {
     pub fn node_type_mut(&mut self) -> NodeTypeMut<'_, V> {
         let Self { id, dom, dirty } = self;
-        let node_type = &mut dom.tree.write::<NodeData<V>>(*id).unwrap().node_type;
+        let node_type = &mut dom.tree.get_mut::<NodeData<V>>(*id).unwrap().node_type;
         match node_type {
             NodeType::Element(element) => NodeTypeMut::Element(ElementNodeMut { element, dirty }),
             NodeType::Text(text) => {
@@ -615,20 +667,16 @@ impl<'a, V: FromAnyValue + Send> NodeMut<'a, V> {
     }
 
     pub fn set_type(&mut self, new: NodeType<V>) {
-        self.node_data_mut().node_type = new;
+        self.dom
+            .tree
+            .get_mut::<NodeData<V>>(self.id)
+            .unwrap()
+            .node_type = new;
         self.dirty = NodeMaskBuilder::ALL.build();
     }
-
-    pub fn read<T: Any>(&self) -> Option<&T> {
-        self.dom.tree.read(self.id)
-    }
-
-    pub fn write<T: Any>(&mut self) -> Option<&T> {
-        todo!("get_mut with mark as dirty")
-    }
 }
 
-impl<V: FromAnyValue + Send> Drop for NodeMut<'_, V> {
+impl<V: FromAnyValue + Send + Sync> Drop for NodeMut<'_, V> {
     fn drop(&mut self) {
         let node_id = self.node_data().node_id;
         let mask = std::mem::take(&mut self.dirty);
@@ -716,3 +764,24 @@ impl<V: FromAnyValue> ElementNodeMut<'_, V> {
         &mut self.element.listeners
     }
 }
+
+pub struct NodeMutRaw<'a, V: FromAnyValue + Send + Sync = ()> {
+    id: NodeId,
+    dom: &'a mut RealDom<V>,
+}
+
+impl<'a, V: FromAnyValue + Send + Sync> NodeImmutable<V> for NodeMutRaw<'a, V> {
+    fn real_dom(&self) -> &RealDom<V> {
+        self.dom
+    }
+
+    fn id(&self) -> NodeId {
+        self.id
+    }
+}
+
+impl<'a, V: FromAnyValue + Send + Sync> NodeMutable<V> for NodeMutRaw<'a, V> {
+    fn get_mut<T: Any>(&mut self) -> Option<&mut T> {
+        self.dom.tree.get_mut::<T>(self.id)
+    }
+}

+ 4 - 4
packages/native-core/src/tree.rs

@@ -164,11 +164,11 @@ impl Tree {
         }
     }
 
-    pub fn read<T: Any>(&self, id: NodeId) -> Option<&T> {
+    pub fn get<T: Any>(&self, id: NodeId) -> Option<&T> {
         self.nodes.read_slab().get(id)
     }
 
-    pub fn write<T: Any>(&mut self, id: NodeId) -> Option<&mut T> {
+    pub fn get_mut<T: Any>(&mut self, id: NodeId) -> Option<&mut T> {
         self.nodes.write_slab().get_mut(id)
     }
 
@@ -184,8 +184,8 @@ impl Tree {
         self.get_node_data(id).parent
     }
 
-    pub fn children_ids(&self, id: NodeId) -> Option<Vec<NodeId>> {
-        Some(self.get_node_data(id).children.clone())
+    pub fn children_ids(&self, id: NodeId) -> Option<&[NodeId]> {
+        Some(&self.get_node_data(id).children)
     }
 
     pub fn height(&self, id: NodeId) -> Option<u16> {

+ 2 - 2
packages/native-core/src/utils/mod.rs

@@ -1,3 +1,3 @@
-// mod persistant_iterator;
-// pub use persistant_iterator::*;
+mod persistant_iterator;
+pub use persistant_iterator::*;
 pub mod cursor;

+ 21 - 41
packages/native-core/src/utils/persistant_iterator.rs

@@ -1,7 +1,6 @@
 use crate::{
     node::{ElementNode, FromAnyValue, NodeType},
-    passes::{AnyMapLike, TypeErasedPass},
-    real_dom::RealDom,
+    real_dom::{NodeImmutable, RealDom},
     NodeId,
 };
 use dioxus_core::{Mutation, Mutations};
@@ -72,10 +71,10 @@ impl PersistantElementIter {
 
     /// remove stale element refreneces
     /// returns true if the focused element is removed
-    pub fn prune<S: State<V>, V: FromAnyValue>(
+    pub fn prune<V: FromAnyValue + Send + Sync>(
         &mut self,
         mutations: &Mutations,
-        rdom: &RealDom<S, V>,
+        rdom: &RealDom<V>,
     ) -> bool {
         let mut changed = false;
         let ids_removed: Vec<_> = mutations
@@ -102,7 +101,7 @@ impl PersistantElementIter {
         // if a child is removed or inserted before or at the current element, update the child index
         for (el_id, child_idx) in self.stack.iter_mut() {
             if let NodePosition::InChild(child_idx) = child_idx {
-                if let Some(children) = &rdom.children_ids(*el_id) {
+                if let Some(children) = &rdom.get(*el_id).unwrap().child_ids() {
                     for m in &mutations.edits {
                         match m {
                             Mutation::Remove { id } => {
@@ -133,7 +132,7 @@ impl PersistantElementIter {
     }
 
     /// get the next element
-    pub fn next<S: State<V>, V: FromAnyValue>(&mut self, rdom: &RealDom<S, V>) -> ElementProduced {
+    pub fn next<V: FromAnyValue + Send + Sync>(&mut self, rdom: &RealDom<V>) -> ElementProduced {
         if self.stack.is_empty() {
             let id = NodeId(0);
             let new = (id, NodePosition::AtNode);
@@ -142,9 +141,9 @@ impl PersistantElementIter {
         } else {
             let (last, old_child_idx) = self.stack.last_mut().unwrap();
             let node = rdom.get(*last).unwrap();
-            match &node.node_data.node_type {
+            match &node.node_data().node_type {
                 NodeType::Element(ElementNode { .. }) => {
-                    let children = rdom.children_ids(*last).unwrap();
+                    let children = node.child_ids().unwrap();
                     *old_child_idx = old_child_idx.map(|i| i + 1);
                     // if we have children, go to the next child
                     let child_idx = old_child_idx.get_or_insert(0);
@@ -154,7 +153,7 @@ impl PersistantElementIter {
                     } else {
                         let id = children[child_idx];
                         if let NodeType::Element(ElementNode { .. }) =
-                            rdom.get(id).unwrap().node_data.node_type
+                            rdom.get(id).unwrap().node_data().node_type
                         {
                             self.stack.push((id, NodePosition::AtNode));
                         }
@@ -171,19 +170,17 @@ impl PersistantElementIter {
     }
 
     /// get the previous element
-    pub fn prev<S: State<V> + Send, V: FromAnyValue>(
-        &mut self,
-        rdom: &RealDom<S, V>,
-    ) -> ElementProduced {
+    pub fn prev<V: FromAnyValue + Send + Sync>(&mut self, rdom: &RealDom<V>) -> ElementProduced {
         // recursively add the last child element to the stack
-        fn push_back<S: State<V> + Send, V: FromAnyValue>(
+        fn push_back<V: FromAnyValue + Send + Sync>(
             stack: &mut smallvec::SmallVec<[(NodeId, NodePosition); 5]>,
             new_node: NodeId,
-            rdom: &RealDom<S, V>,
+            rdom: &RealDom<V>,
         ) -> NodeId {
-            match &rdom[new_node].node_data.node_type {
+            let node = rdom.get(new_node).unwrap();
+            match &node.node_data().node_type {
                 NodeType::Element(ElementNode { .. }) => {
-                    let children = rdom.children_ids(new_node).unwrap();
+                    let children = node.child_ids().unwrap();
                     if children.is_empty() {
                         new_node
                     } else {
@@ -199,10 +196,10 @@ impl PersistantElementIter {
             ElementProduced::Looped(push_back(&mut self.stack, new_node, rdom))
         } else {
             let (last, old_child_idx) = self.stack.last_mut().unwrap();
-            let node = &rdom[*last];
-            match &node.node_data.node_type {
+            let node = rdom.get(*last).unwrap();
+            match &node.node_data().node_type {
                 NodeType::Element(ElementNode { .. }) => {
-                    let children = rdom.children_ids(*last).unwrap();
+                    let children = node.child_ids().unwrap();
                     // if we have children, go to the next child
                     if let NodePosition::InChild(0) = old_child_idx {
                         ElementProduced::Progressed(self.pop())
@@ -240,23 +237,6 @@ impl PersistantElementIter {
     }
 }
 
-#[derive(Default, Clone, Debug)]
-struct Empty {}
-impl AnyMapLike for Empty {
-    fn get<T: std::any::Any>(&self) -> Option<&T> {
-        None
-    }
-
-    fn get_mut<T: std::any::Any>(&mut self) -> Option<&mut T> {
-        None
-    }
-}
-impl State for Empty {
-    fn create_passes() -> Box<[TypeErasedPass<Self>]> {
-        Box::new([])
-    }
-}
-
 #[test]
 #[allow(unused_variables)]
 fn traverse() {
@@ -279,7 +259,7 @@ fn traverse() {
     let mut vdom = VirtualDom::new(Base);
     let mutations = vdom.rebuild();
 
-    let mut rdom: RealDom<Empty> = RealDom::new();
+    let mut rdom: RealDom = RealDom::new(Box::new([]));
 
     let _to_update = rdom.apply_mutations(mutations);
 
@@ -378,7 +358,7 @@ fn persist_removes() {
     }
     let mut vdom = VirtualDom::new(Base);
 
-    let mut rdom: RealDom<Empty> = RealDom::new();
+    let mut rdom: RealDom = RealDom::new(Box::new([]));
 
     let build = vdom.rebuild();
     println!("{:#?}", build);
@@ -460,7 +440,7 @@ fn persist_instertions_before() {
     }
     let mut vdom = VirtualDom::new(Base);
 
-    let mut rdom: RealDom<Empty> = RealDom::new();
+    let mut rdom: RealDom = RealDom::new(Box::new([]));
 
     let build = vdom.rebuild();
     let _to_update = rdom.apply_mutations(build);
@@ -516,7 +496,7 @@ fn persist_instertions_after() {
     }
     let mut vdom = VirtualDom::new(Base);
 
-    let mut rdom: RealDom<Empty> = RealDom::new();
+    let mut rdom: RealDom = RealDom::new(Box::new([]));
 
     let build = vdom.rebuild();
     let _to_update = rdom.apply_mutations(build);

+ 41 - 38
packages/tui/src/focus.rs

@@ -1,15 +1,17 @@
-use crate::{node::PreventDefault, TuiDom};
+use crate::node::PreventDefault;
 
 use dioxus_native_core::{
-    tree::TreeView,
+    node_ref::{AttributeMaskBuilder, NodeMaskBuilder},
+    real_dom::{NodeImmutable, NodeMutable},
     utils::{ElementProduced, PersistantElementIter},
-    NodeId, Pass, SendAnyMap,
+    Dependancy, NodeId, Pass, RealDom, SendAnyMap,
 };
-use dioxus_native_core_macro::sorted_str_slice;
 
 use std::{cmp::Ordering, num::NonZeroU16};
 
-use dioxus_native_core::node_ref::{AttributeMask, NodeMask, NodeView};
+use dioxus_native_core::node_ref::NodeView;
+
+pub struct Focused(pub bool);
 
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
 pub(crate) enum FocusLevel {
@@ -62,8 +64,9 @@ pub(crate) struct Focus {
 }
 
 impl Pass for Focus {
-    const NODE_MASK: NodeMask =
-        NodeMask::new_with_attrs(AttributeMask::Static(FOCUS_ATTRIBUTES)).with_listeners();
+    const NODE_MASK: NodeMaskBuilder = NodeMaskBuilder::new()
+        .with_attrs(AttributeMaskBuilder::Some(FOCUS_ATTRIBUTES))
+        .with_listeners();
 
     type ParentDependencies = ();
     type ChildDependencies = ();
@@ -72,18 +75,10 @@ impl Pass for Focus {
     fn pass<'a>(
         &mut self,
         node_view: NodeView,
-        _: <Self::NodeDependencies as dioxus_native_core::Dependancy>::ElementBorrowed<'a>,
-        _: Option<
-            <Self::ParentDependencies as dioxus_native_core::Dependancy>::ElementBorrowed<'a>,
-        >,
-        _: Option<
-            impl Iterator<
-                Item = <Self::ChildDependencies as dioxus_native_core::Dependancy>::ElementBorrowed<
-                    'a,
-                >,
-            >,
-        >,
-        _: &SendAnyMap,
+        node: <Self::NodeDependencies as Dependancy>::ElementBorrowed<'a>,
+        parent: Option<<Self::ParentDependencies as Dependancy>::ElementBorrowed<'a>>,
+        children: Option<Vec<<Self::ChildDependencies as Dependancy>::ElementBorrowed<'a>>>,
+        context: &SendAnyMap,
     ) -> bool {
         let new = Focus {
             level: if let Some(a) = node_view
@@ -128,8 +123,8 @@ impl Pass for Focus {
     }
 }
 
-const FOCUS_EVENTS: &[&str] = &sorted_str_slice!(["keydown", "keypress", "keyup"]);
-const FOCUS_ATTRIBUTES: &[&str] = &sorted_str_slice!(["tabindex"]);
+const FOCUS_EVENTS: &[&str] = &["keydown", "keypress", "keyup"];
+const FOCUS_ATTRIBUTES: &[&str] = &["tabindex"];
 
 #[derive(Default)]
 pub(crate) struct FocusState {
@@ -141,9 +136,11 @@ pub(crate) struct FocusState {
 
 impl FocusState {
     /// Returns true if the focus has changed.
-    pub fn progress(&mut self, rdom: &mut TuiDom, forward: bool) -> bool {
+    pub fn progress(&mut self, rdom: &mut RealDom, forward: bool) -> bool {
         if let Some(last) = self.last_focused_id {
-            if rdom[last].state.prevent_default == PreventDefault::KeyDown {
+            if rdom.get(last).unwrap().get::<PreventDefault>().copied()
+                == Some(PreventDefault::KeyDown)
+            {
                 return false;
             }
         }
@@ -165,7 +162,7 @@ impl FocusState {
                 if forward {
                     // find the closest focusable element after the current level
                     rdom.traverse_depth_first(|n| {
-                        let node_level = n.state.focus.level;
+                        let node_level = n.get::<Focus>().unwrap().level;
                         if node_level != *focus_level
                             && node_level.focusable()
                             && node_level > *focus_level
@@ -182,7 +179,7 @@ impl FocusState {
                 } else {
                     // find the closest focusable element before the current level
                     rdom.traverse_depth_first(|n| {
-                        let node_level = n.state.focus.level;
+                        let node_level = n.get::<Focus>().unwrap().level;
                         if node_level != *focus_level
                             && node_level.focusable()
                             && node_level < *focus_level
@@ -219,7 +216,7 @@ impl FocusState {
                 loop_marker_id = Some(new_id);
             }
 
-            let current_level = rdom[new_id].state.focus.level;
+            let current_level = rdom.get(new_id).unwrap().get::<Focus>().unwrap().level;
             let after_previous_focused = if forward {
                 current_level >= *focus_level
             } else {
@@ -233,12 +230,16 @@ impl FocusState {
         }
 
         if let Some(id) = next_focus {
-            if !rdom[id].state.focus.level.focusable() {
+            let mut node = rdom.get_mut_raw(id).unwrap();
+            if !node.get::<Focus>().unwrap().level.focusable() {
                 panic!()
             }
-            rdom[id].state.focused = true;
+            let focused = node.get_mut::<Focused>().unwrap();
+            focused.0 = true;
             if let Some(old) = self.last_focused_id.replace(id) {
-                rdom[old].state.focused = false;
+                let mut old = rdom.get_mut_raw(old).unwrap();
+                let focused = old.get_mut::<Focused>().unwrap();
+                focused.0 = false;
             }
             // reset the position to the currently focused element
             while self.focus_iter.next(rdom).id() != id {}
@@ -249,8 +250,8 @@ impl FocusState {
         false
     }
 
-    pub(crate) fn prune(&mut self, mutations: &dioxus_core::Mutations, rdom: &TuiDom) {
-        fn remove_children(to_prune: &mut [&mut Option<NodeId>], rdom: &TuiDom, removed: NodeId) {
+    pub(crate) fn prune(&mut self, mutations: &dioxus_core::Mutations, rdom: &RealDom) {
+        fn remove_children(to_prune: &mut [&mut Option<NodeId>], rdom: &RealDom, removed: NodeId) {
             for opt in to_prune.iter_mut() {
                 if let Some(id) = opt {
                     if *id == removed {
@@ -258,8 +259,9 @@ impl FocusState {
                     }
                 }
             }
-            if let Some(children) = &rdom.children_ids(removed) {
-                for child in *children {
+            let node = rdom.get(removed).unwrap();
+            if let Some(children) = node.child_ids() {
+                for child in children {
                     remove_children(to_prune, rdom, *child);
                 }
             }
@@ -284,13 +286,14 @@ impl FocusState {
         }
     }
 
-    pub(crate) fn set_focus(&mut self, rdom: &mut TuiDom, id: NodeId) {
+    pub(crate) fn set_focus(&mut self, rdom: &mut RealDom, id: NodeId) {
         if let Some(old) = self.last_focused_id.replace(id) {
-            rdom[old].state.focused = false;
+            let mut node = rdom.get_mut_raw(old).unwrap();
+            node.get_mut::<Focused>().unwrap().0 = false;
         }
-        let state = &mut rdom[id].state;
-        state.focused = true;
-        self.focus_level = state.focus.level;
+        let mut node = &mut rdom.get_mut_raw(id).unwrap();
+        node.get_mut::<Focused>().unwrap().0 = true;
+        self.focus_level = node.get::<Focus>().unwrap().level;
         // reset the position to the currently focused element
         while self.focus_iter.next(rdom).id() != id {}
         self.dirty = true;

+ 31 - 23
packages/tui/src/hooks.rs

@@ -2,8 +2,8 @@ use crossterm::event::{
     Event as TermEvent, KeyCode as TermKeyCode, KeyModifiers, MouseButton, MouseEventKind,
 };
 use dioxus_core::*;
-use dioxus_native_core::tree::TreeView;
-use dioxus_native_core::NodeId;
+use dioxus_native_core::real_dom::NodeImmutable;
+use dioxus_native_core::{NodeId, NodeRef, RealDom};
 use rustc_hash::{FxHashMap, FxHashSet};
 
 use dioxus_html::geometry::euclid::{Point2D, Rect, Size2D};
@@ -23,8 +23,9 @@ use std::{
 use taffy::geometry::{Point, Size};
 use taffy::{prelude::Layout, Taffy};
 
+use crate::focus::{Focus, Focused};
+use crate::layout::TaffyLayout;
 use crate::{layout_to_screen_space, FocusState};
-use crate::{TuiDom, TuiNode};
 
 pub(crate) struct Event {
     pub id: ElementId,
@@ -173,7 +174,7 @@ impl InnerInputState {
         evts: &mut Vec<EventCore>,
         resolved_events: &mut Vec<Event>,
         layout: &Taffy,
-        dom: &mut TuiDom,
+        dom: &mut RealDom,
     ) {
         let previous_mouse = self.mouse.clone();
 
@@ -201,7 +202,7 @@ impl InnerInputState {
             // elements with listeners will always have a element id
             if let Some(id) = self.focus_state.last_focused_id {
                 let element = dom.get(id).unwrap();
-                if let Some(id) = element.node_data.element_id {
+                if let Some(id) = element.node_data().element_id {
                     resolved_events.push(Event {
                         name: "focus",
                         id,
@@ -218,7 +219,7 @@ impl InnerInputState {
             }
             if let Some(id) = old_focus {
                 let element = dom.get(id).unwrap();
-                if let Some(id) = element.node_data.element_id {
+                if let Some(id) = element.node_data().element_id {
                     resolved_events.push(Event {
                         name: "focusout",
                         id,
@@ -239,7 +240,7 @@ impl InnerInputState {
         previous_mouse: Option<MouseData>,
         resolved_events: &mut Vec<Event>,
         layout: &Taffy,
-        dom: &mut TuiDom,
+        dom: &mut RealDom,
     ) {
         fn layout_contains_point(layout: &Layout, point: ScreenPoint) -> bool {
             let Point { x, y } = layout.location;
@@ -262,17 +263,17 @@ impl InnerInputState {
             data: Rc<dyn Any>,
             will_bubble: &mut FxHashSet<NodeId>,
             resolved_events: &mut Vec<Event>,
-            node: &TuiNode,
-            dom: &TuiDom,
+            node: NodeRef,
+            dom: &RealDom,
         ) {
             // only trigger event if the event was not triggered already by a child
-            let id = node.node_data.node_id;
+            let id = node.node_data().node_id;
             if will_bubble.insert(id) {
-                let mut parent = dom.parent(id);
+                let mut parent = Some(node);
                 while let Some(current_parent) = parent {
-                    let parent_id = current_parent.node_data.node_id;
+                    let parent_id = current_parent.node_data().node_id;
                     will_bubble.insert(parent_id);
-                    parent = dom.parent(parent_id);
+                    parent = current_parent.parent_id().and_then(|id| dom.get(id));
                 }
                 if let Some(id) = node.mounted_id() {
                     resolved_events.push(Event {
@@ -564,11 +565,13 @@ impl InnerInputState {
             if was_released {
                 let mut focus_id = None;
                 dom.traverse_depth_first(|node| {
-                    let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
+                    let node_layout = layout
+                        .layout(node.get::<TaffyLayout>().unwrap().node.unwrap())
+                        .unwrap();
                     let currently_contains = layout_contains_point(node_layout, new_pos);
 
-                    if currently_contains && node.state.focus.level.focusable() {
-                        focus_id = Some(node.node_data.node_id);
+                    if currently_contains && node.get::<Focus>().unwrap().level.focusable() {
+                        focus_id = Some(node.node_data().node_id);
                     }
                 });
                 if let Some(id) = focus_id {
@@ -583,13 +586,18 @@ impl InnerInputState {
     // }
 }
 
-fn get_abs_layout(node: &TuiNode, dom: &TuiDom, taffy: &Taffy) -> Layout {
-    let mut node_layout = *taffy.layout(node.state.layout.node.unwrap()).unwrap();
+fn get_abs_layout(node: NodeRef, dom: &RealDom, taffy: &Taffy) -> Layout {
+    let mut node_layout = *taffy
+        .layout(node.get::<TaffyLayout>().unwrap().node.unwrap())
+        .unwrap();
     let mut current = node;
 
-    while let Some(parent) = dom.parent(current.node_data.node_id) {
+    while let Some(parent) = current.parent_id() {
+        let parent = dom.get(parent).unwrap();
         current = parent;
-        let parent_layout = taffy.layout(parent.state.layout.node.unwrap()).unwrap();
+        let parent_layout = taffy
+            .layout(parent.get::<TaffyLayout>().unwrap().node.unwrap())
+            .unwrap();
         node_layout.location.x += parent_layout.location.x;
         node_layout.location.y += parent_layout.location.y;
     }
@@ -632,11 +640,11 @@ impl RinkInputHandler {
         )
     }
 
-    pub(crate) fn prune(&self, mutations: &dioxus_core::Mutations, rdom: &TuiDom) {
+    pub(crate) fn prune(&self, mutations: &dioxus_core::Mutations, rdom: &RealDom) {
         self.state.borrow_mut().focus_state.prune(mutations, rdom);
     }
 
-    pub(crate) fn get_events(&self, layout: &Taffy, dom: &mut TuiDom) -> Vec<Event> {
+    pub(crate) fn get_events(&self, layout: &Taffy, dom: &mut RealDom) -> Vec<Event> {
         let mut resolved_events = Vec::new();
 
         (*self.state).borrow_mut().update(
@@ -680,7 +688,7 @@ impl RinkInputHandler {
         for (event, datas) in hm {
             for node in dom.get_listening_sorted(event) {
                 for data in &datas {
-                    if node.state.focused {
+                    if node.get::<Focused>().unwrap().0 {
                         if let Some(id) = node.mounted_id() {
                             resolved_events.push(Event {
                                 name: event,

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

@@ -4,9 +4,8 @@ use dioxus_native_core::layout_attributes::{
     apply_layout_attributes_cfg, BorderWidths, LayoutConfigeration,
 };
 use dioxus_native_core::node::OwnedAttributeView;
-use dioxus_native_core::node_ref::{AttributeMask, NodeMask, NodeView};
-use dioxus_native_core::{Pass, SendAnyMap};
-use dioxus_native_core_macro::sorted_str_slice;
+use dioxus_native_core::node_ref::{AttributeMaskBuilder, NodeMaskBuilder, NodeView};
+use dioxus_native_core::{Dependancy, Pass, SendAnyMap};
 use taffy::prelude::*;
 
 use crate::{screen_to_layout_space, unit_to_layout_space};
@@ -48,23 +47,16 @@ impl Pass for TaffyLayout {
     type ParentDependencies = ();
     type NodeDependencies = ();
 
-    const NODE_MASK: NodeMask =
-        NodeMask::new_with_attrs(AttributeMask::Static(SORTED_LAYOUT_ATTRS)).with_text();
+    const NODE_MASK: NodeMaskBuilder = NodeMaskBuilder::new()
+        .with_attrs(AttributeMaskBuilder::Some(SORTED_LAYOUT_ATTRS))
+        .with_text();
 
     fn pass<'a>(
         &mut self,
         node_view: NodeView,
-        _: <Self::NodeDependencies as dioxus_native_core::Dependancy>::ElementBorrowed<'a>,
-        _: Option<
-            <Self::ParentDependencies as dioxus_native_core::Dependancy>::ElementBorrowed<'a>,
-        >,
-        children: Option<
-            impl Iterator<
-                Item = <Self::ChildDependencies as dioxus_native_core::Dependancy>::ElementBorrowed<
-                    'a,
-                >,
-            >,
-        >,
+        node: <Self::NodeDependencies as Dependancy>::ElementBorrowed<'a>,
+        parent: Option<<Self::ParentDependencies as Dependancy>::ElementBorrowed<'a>>,
+        children: Option<Vec<<Self::ChildDependencies as Dependancy>::ElementBorrowed<'a>>>,
         ctx: &SendAnyMap,
     ) -> bool {
         let mut changed = false;
@@ -203,7 +195,7 @@ impl Pass for TaffyLayout {
 }
 
 // these are the attributes in layout_attiributes in native-core
-const SORTED_LAYOUT_ATTRS: &[&str] = &sorted_str_slice!([
+const SORTED_LAYOUT_ATTRS: &[&str] = &[
     "align-content",
     "align-items",
     "align-self",
@@ -355,5 +347,5 @@ const SORTED_LAYOUT_ATTRS: &[&str] = &sorted_str_slice!([
     "word-break",
     "word-spacing",
     "word-wrap",
-    "z-index"
-]);
+    "z-index",
+];

+ 17 - 6
packages/tui/src/lib.rs

@@ -6,6 +6,7 @@ use crossterm::{
     terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
 };
 use dioxus_core::*;
+use dioxus_native_core::{node_ref::NodeMaskBuilder, real_dom::NodeImmutable, Pass};
 use dioxus_native_core::{real_dom::RealDom, FxDashSet, NodeId, NodeMask, SendAnyMap};
 use focus::FocusState;
 use futures::{
@@ -13,6 +14,7 @@ use futures::{
     pin_mut, StreamExt,
 };
 use futures_channel::mpsc::unbounded;
+use layout::TaffyLayout;
 use query::Query;
 use std::rc::Rc;
 use std::{
@@ -101,7 +103,9 @@ pub fn launch_cfg_with_props<Props: 'static>(app: Component<Props>, props: Props
     }
 
     let cx = dom.base_scope();
-    let rdom = Rc::new(RefCell::new(RealDom::new()));
+    let rdom = Rc::new(RefCell::new(RealDom::new(Box::new([
+        TaffyLayout::to_type_erased(),
+    ]))));
     let taffy = Arc::new(Mutex::new(Taffy::new()));
     cx.provide_context(state);
     cx.provide_context(TuiContext { tx: event_tx_clone });
@@ -136,7 +140,7 @@ fn render_vdom(
     mut event_reciever: UnboundedReceiver<InputEvent>,
     handler: RinkInputHandler,
     cfg: Config,
-    rdom: Rc<RefCell<TuiDom>>,
+    rdom: Rc<RefCell<RealDom>>,
     taffy: Arc<Mutex<Taffy>>,
     mut register_event: impl FnMut(crossterm::event::Event),
 ) -> Result<()> {
@@ -177,10 +181,16 @@ fn render_vdom(
 
                 if !to_rerender.is_empty() || updated {
                     updated = false;
-                    fn resize(dims: Rect, taffy: &mut Taffy, rdom: &TuiDom) {
+                    fn resize(dims: Rect, taffy: &mut Taffy, rdom: &RealDom) {
                         let width = screen_to_layout_space(dims.width);
                         let height = screen_to_layout_space(dims.height);
-                        let root_node = rdom[NodeId(0)].state.layout.node.unwrap();
+                        let root_node = rdom
+                            .get(NodeId(0))
+                            .unwrap()
+                            .get::<TaffyLayout>()
+                            .unwrap()
+                            .node
+                            .unwrap();
 
                         // the root node fills the entire area
 
@@ -204,7 +214,7 @@ fn render_vdom(
                             let mut taffy = taffy.lock().expect("taffy lock poisoned");
                             // size is guaranteed to not change when rendering
                             resize(frame.size(), &mut taffy, &rdom);
-                            let root = &rdom[NodeId(0)];
+                            let root = rdom.get(NodeId(0)).unwrap();
                             render::render_vnode(frame, &taffy, &rdom, root, cfg, Point::ZERO);
                         })?;
                         execute!(terminal.backend_mut(), RestorePosition, Show).unwrap();
@@ -277,8 +287,9 @@ fn render_vdom(
                     any_map.insert(taffy.clone());
                     let (new_to_rerender, dirty) = rdom.update_state(any_map);
                     to_rerender = new_to_rerender;
+                    let text_mask = NodeMaskBuilder::new().with_text().build();
                     for (id, mask) in dirty {
-                        if mask.overlaps(&NodeMask::new().with_text()) {
+                        if mask.overlaps(&text_mask) {
                             to_rerender.insert(id);
                         }
                     }

+ 14 - 22
packages/tui/src/node.rs

@@ -1,23 +1,18 @@
 use crate::focus::Focus;
 use crate::layout::TaffyLayout;
 use crate::style_attributes::StyleModifier;
-use dioxus_native_core::{real_dom::RealDom, Dependancy, Pass, SendAnyMap};
-use dioxus_native_core_macro::{sorted_str_slice, AnyMapLike, State};
+use dioxus_native_core::{node_ref::NodeView, Dependancy, Pass, SendAnyMap};
 
-pub(crate) type TuiDom = RealDom<NodeState>;
-pub(crate) type TuiNode = dioxus_native_core::node::Node<NodeState>;
-
-#[derive(Debug, Clone, State, AnyMapLike, Default)]
+#[derive(Debug, Clone, Default)]
 pub(crate) struct NodeState {
     pub layout: TaffyLayout,
     pub style: StyleModifier,
     pub prevent_default: PreventDefault,
     pub focus: Focus,
-    #[skip]
     pub focused: bool,
 }
 
-#[derive(PartialEq, Debug, Clone)]
+#[derive(PartialEq, Debug, Clone, Copy)]
 pub(crate) enum PreventDefault {
     Focus,
     KeyPress,
@@ -47,23 +42,20 @@ impl Pass for PreventDefault {
     type ChildDependencies = ();
     type NodeDependencies = ();
 
-    const NODE_MASK: dioxus_native_core::node_ref::NodeMask =
-        dioxus_native_core::node_ref::NodeMask::new_with_attrs(
-            dioxus_native_core::node_ref::AttributeMask::Static(&sorted_str_slice!([
-                "dioxus-prevent-default"
-            ])),
-        )
-        .with_listeners();
+    const NODE_MASK: dioxus_native_core::node_ref::NodeMaskBuilder =
+        dioxus_native_core::node_ref::NodeMaskBuilder::new()
+            .with_attrs(dioxus_native_core::node_ref::AttributeMaskBuilder::Some(&[
+                "dioxus-prevent-default",
+            ]))
+            .with_listeners();
 
     fn pass<'a>(
         &mut self,
-        node_view: dioxus_native_core::node_ref::NodeView,
-        _: <Self::NodeDependencies as Dependancy>::ElementBorrowed<'a>,
-        _: Option<<Self::ParentDependencies as Dependancy>::ElementBorrowed<'a>>,
-        _: Option<
-            impl Iterator<Item = <Self::ChildDependencies as Dependancy>::ElementBorrowed<'a>>,
-        >,
-        _: &SendAnyMap,
+        node_view: NodeView,
+        node: <Self::NodeDependencies as Dependancy>::ElementBorrowed<'a>,
+        parent: Option<<Self::ParentDependencies as Dependancy>::ElementBorrowed<'a>>,
+        children: Option<Vec<<Self::ChildDependencies as Dependancy>::ElementBorrowed<'a>>>,
+        context: &SendAnyMap,
     ) -> bool {
         let new = match node_view.attributes().and_then(|mut attrs| {
             attrs

+ 14 - 5
packages/tui/src/query.rs

@@ -5,13 +5,14 @@ use std::{
 };
 
 use dioxus_core::ElementId;
+use dioxus_native_core::{real_dom::NodeImmutable, RealDom};
 use taffy::{
     geometry::Point,
     prelude::{Layout, Size},
     Taffy,
 };
 
-use crate::{layout_to_screen_space, TuiDom};
+use crate::{layout::TaffyLayout, layout_to_screen_space};
 
 /// Allows querying the layout of nodes after rendering. It will only provide a correct value after a node is rendered.
 /// Provided as a root context for all tui applictions.
@@ -46,7 +47,7 @@ use crate::{layout_to_screen_space, TuiDom};
 /// ```
 #[derive(Clone)]
 pub struct Query {
-    pub(crate) rdom: Rc<RefCell<TuiDom>>,
+    pub(crate) rdom: Rc<RefCell<RealDom>>,
     pub(crate) stretch: Arc<Mutex<Taffy>>,
 }
 
@@ -61,13 +62,13 @@ impl Query {
 }
 
 pub struct ElementRef<'a> {
-    inner: Ref<'a, TuiDom>,
+    inner: Ref<'a, RealDom>,
     stretch: MutexGuard<'a, Taffy>,
     id: ElementId,
 }
 
 impl<'a> ElementRef<'a> {
-    fn new(inner: Ref<'a, TuiDom>, stretch: MutexGuard<'a, Taffy>, id: ElementId) -> Self {
+    fn new(inner: Ref<'a, RealDom>, stretch: MutexGuard<'a, Taffy>, id: ElementId) -> Self {
         Self { inner, stretch, id }
     }
 
@@ -85,7 +86,15 @@ impl<'a> ElementRef<'a> {
     pub fn layout(&self) -> Option<Layout> {
         let layout = self
             .stretch
-            .layout(self.inner[self.id].state.layout.node.ok()?)
+            .layout(
+                self.inner
+                    .get(self.id)
+                    .unwrap()
+                    .get::<TaffyLayout>()
+                    .unwrap()
+                    .node
+                    .ok()?,
+            )
             .ok();
         layout.map(|layout| Layout {
             order: layout.order,

+ 30 - 20
packages/tui/src/render.rs

@@ -1,18 +1,24 @@
-use dioxus_native_core::tree::TreeView;
+use dioxus_native_core::{real_dom::NodeImmutable, NodeRef, RealDom};
 use std::io::Stdout;
 use taffy::{
     geometry::Point,
     prelude::{Dimension, Layout, Size},
     Taffy,
 };
-use tui::{backend::CrosstermBackend, layout::Rect, style::Color};
+use tui::{
+    backend::CrosstermBackend,
+    layout::Rect,
+    style::{Color, Style},
+};
 
 use crate::{
+    focus::Focused,
+    layout::TaffyLayout,
     layout_to_screen_space,
     style::{RinkColor, RinkStyle},
-    style_attributes::{BorderEdge, BorderStyle},
+    style_attributes::{BorderEdge, BorderStyle, StyleModifier},
     widget::{RinkBuffer, RinkCell, RinkWidget, WidgetWithContext},
-    Config, TuiDom, TuiNode,
+    Config,
 };
 
 const RADIUS_MULTIPLIER: [f32; 2] = [1.0, 0.5];
@@ -20,20 +26,22 @@ const RADIUS_MULTIPLIER: [f32; 2] = [1.0, 0.5];
 pub(crate) fn render_vnode(
     frame: &mut tui::Frame<CrosstermBackend<Stdout>>,
     layout: &Taffy,
-    rdom: &TuiDom,
-    node: &TuiNode,
+    rdom: &RealDom,
+    node: NodeRef,
     cfg: Config,
     parent_location: Point<f32>,
 ) {
     use dioxus_native_core::node::NodeType;
 
-    if let NodeType::Placeholder = &node.node_data.node_type {
+    if let NodeType::Placeholder = &node.node_type() {
         return;
     }
 
     let Layout {
         mut location, size, ..
-    } = layout.layout(node.state.layout.node.unwrap()).unwrap();
+    } = layout
+        .layout(node.get::<TaffyLayout>().unwrap().node.unwrap())
+        .unwrap();
     location.x += parent_location.x;
     location.y += parent_location.y;
 
@@ -44,7 +52,7 @@ pub(crate) fn render_vnode(
     let width = layout_to_screen_space(fx + width).round() as u16 - x;
     let height = layout_to_screen_space(fy + height).round() as u16 - y;
 
-    match &node.node_data.node_type {
+    match node.node_type() {
         NodeType::Text(text) => {
             #[derive(Default)]
             struct Label<'a> {
@@ -65,7 +73,7 @@ pub(crate) fn render_vnode(
 
             let label = Label {
                 text,
-                style: node.state.style.core,
+                style: node.get::<StyleModifier>().unwrap().core,
             };
             let area = Rect::new(x, y, width, height);
 
@@ -82,15 +90,15 @@ pub(crate) fn render_vnode(
                 frame.render_widget(WidgetWithContext::new(node, cfg), area);
             }
 
-            for c in rdom.children_ids(node.node_data.node_id).unwrap() {
-                render_vnode(frame, layout, rdom, &rdom[*c], cfg, location);
+            for c in node.children().unwrap() {
+                render_vnode(frame, layout, rdom, c, cfg, location);
             }
         }
         NodeType::Placeholder => unreachable!(),
     }
 }
 
-impl RinkWidget for &TuiNode {
+impl RinkWidget for NodeRef<'_> {
     fn render(self, area: Rect, mut buf: RinkBuffer<'_>) {
         use tui::symbols::line::*;
 
@@ -275,10 +283,10 @@ impl RinkWidget for &TuiNode {
         for x in area.left()..area.right() {
             for y in area.top()..area.bottom() {
                 let mut new_cell = RinkCell::default();
-                if let Some(c) = self.state.style.core.bg {
+                if let Some(c) = self.get::<StyleModifier>().unwrap().core.bg {
                     new_cell.bg = c;
                 }
-                if self.state.focused {
+                if self.get::<Focused>().unwrap().0 {
                     new_cell.bg.alpha = 100;
                     new_cell.bg.color = new_cell.bg.blend(Color::White);
                 }
@@ -286,7 +294,9 @@ impl RinkWidget for &TuiNode {
             }
         }
 
-        let borders = &self.state.style.modifier.borders;
+        let style = self.get::<StyleModifier>().unwrap();
+
+        let borders = &style.modifier.borders;
 
         let last_edge = &borders.left;
         let current_edge = &borders.top;
@@ -303,7 +313,7 @@ impl RinkWidget for &TuiNode {
                 (last_r * RADIUS_MULTIPLIER[0]) as u16,
                 (last_r * RADIUS_MULTIPLIER[1]) as u16,
             ];
-            let color = current_edge.color.or(self.state.style.core.fg);
+            let color = current_edge.color.or(style.core.fg);
             let mut new_cell = RinkCell::default();
             if let Some(c) = color {
                 new_cell.fg = c;
@@ -338,7 +348,7 @@ impl RinkWidget for &TuiNode {
                 (last_r * RADIUS_MULTIPLIER[0]) as u16,
                 (last_r * RADIUS_MULTIPLIER[1]) as u16,
             ];
-            let color = current_edge.color.or(self.state.style.core.fg);
+            let color = current_edge.color.or(style.core.fg);
             let mut new_cell = RinkCell::default();
             if let Some(c) = color {
                 new_cell.fg = c;
@@ -373,7 +383,7 @@ impl RinkWidget for &TuiNode {
                 (last_r * RADIUS_MULTIPLIER[0]) as u16,
                 (last_r * RADIUS_MULTIPLIER[1]) as u16,
             ];
-            let color = current_edge.color.or(self.state.style.core.fg);
+            let color = current_edge.color.or(style.core.fg);
             let mut new_cell = RinkCell::default();
             if let Some(c) = color {
                 new_cell.fg = c;
@@ -408,7 +418,7 @@ impl RinkWidget for &TuiNode {
                 (last_r * RADIUS_MULTIPLIER[0]) as u16,
                 (last_r * RADIUS_MULTIPLIER[1]) as u16,
             ];
-            let color = current_edge.color.or(self.state.style.core.fg);
+            let color = current_edge.color.or(style.core.fg);
             let mut new_cell = RinkCell::default();
             if let Some(c) = color {
                 new_cell.fg = c;

+ 12 - 20
packages/tui/src/style_attributes.rs

@@ -32,10 +32,9 @@
 use dioxus_native_core::{
     layout_attributes::parse_value,
     node::OwnedAttributeView,
-    node_ref::{AttributeMask, NodeMask, NodeView},
-    Pass, SendAnyMap,
+    node_ref::{AttributeMaskBuilder, NodeMaskBuilder, NodeView},
+    Dependancy, Pass, SendAnyMap,
 };
-use dioxus_native_core_macro::sorted_str_slice;
 use taffy::prelude::*;
 
 use crate::style::{RinkColor, RinkStyle};
@@ -52,24 +51,17 @@ impl Pass for StyleModifier {
     type NodeDependencies = ();
 
     // todo: seperate each attribute into it's own class
-    const NODE_MASK: NodeMask =
-        NodeMask::new_with_attrs(AttributeMask::Static(SORTED_STYLE_ATTRS)).with_element();
+    const NODE_MASK: NodeMaskBuilder = NodeMaskBuilder::new()
+        .with_attrs(AttributeMaskBuilder::Some(SORTED_STYLE_ATTRS))
+        .with_element();
 
     fn pass<'a>(
         &mut self,
         node_view: NodeView,
-        _: <Self::NodeDependencies as dioxus_native_core::Dependancy>::ElementBorrowed<'a>,
-        parent: Option<
-            <Self::ParentDependencies as dioxus_native_core::Dependancy>::ElementBorrowed<'a>,
-        >,
-        _: Option<
-            impl Iterator<
-                Item = <Self::ChildDependencies as dioxus_native_core::Dependancy>::ElementBorrowed<
-                    'a,
-                >,
-            >,
-        >,
-        _: &SendAnyMap,
+        node: <Self::NodeDependencies as Dependancy>::ElementBorrowed<'a>,
+        parent: Option<<Self::ParentDependencies as Dependancy>::ElementBorrowed<'a>>,
+        children: Option<Vec<<Self::ChildDependencies as Dependancy>::ElementBorrowed<'a>>>,
+        context: &SendAnyMap,
     ) -> bool {
         let mut new = StyleModifier::default();
         if parent.is_some() {
@@ -615,7 +607,7 @@ fn apply_transition(_name: &str, _value: &str, _style: &mut StyleModifier) {
     todo!()
 }
 
-const SORTED_STYLE_ATTRS: &[&str] = &sorted_str_slice!([
+const SORTED_STYLE_ATTRS: &[&str] = &[
     "animation",
     "animation-delay",
     "animation-direction",
@@ -816,5 +808,5 @@ const SORTED_STYLE_ATTRS: &[&str] = &sorted_str_slice!([
     "text-justify",
     "text-overflow",
     "text-shadow",
-    "text-transform"
-]);
+    "text-transform",
+];