Ver código fonte

Feat: introduce children for walking down the tree

Jonathan Kelley 4 anos atrás
pai
commit
0d44f00

+ 15 - 3
packages/core/src/arena.rs

@@ -29,12 +29,20 @@ impl ScopeArena {
         })))
     }
 
+    /// THIS METHOD IS CURRENTLY UNSAFE
+    /// THERE ARE NO CHECKS TO VERIFY THAT WE ARE ALLOWED TO DO THIS
     pub fn try_get(&self, idx: ScopeIdx) -> Result<&Scope> {
-        todo!()
+        let inner = unsafe { &*self.0.borrow().arena.get() };
+        let scope = inner.get(idx);
+        scope.ok_or_else(|| Error::FatalInternal("Scope not found"))
     }
 
+    /// THIS METHOD IS CURRENTLY UNSAFE
+    /// THERE ARE NO CHECKS TO VERIFY THAT WE ARE ALLOWED TO DO THIS
     pub fn try_get_mut(&self, idx: ScopeIdx) -> Result<&mut Scope> {
-        todo!()
+        let inner = unsafe { &mut *self.0.borrow().arena.get() };
+        let scope = inner.get_mut(idx);
+        scope.ok_or_else(|| Error::FatalInternal("Scope not found"))
     }
 
     fn inner(&self) -> &Arena<Scope> {
@@ -45,8 +53,12 @@ impl ScopeArena {
         todo!()
     }
 
+    /// THIS METHOD IS CURRENTLY UNSAFE
+    /// THERE ARE NO CHECKS TO VERIFY THAT WE ARE ALLOWED TO DO THIS
     pub fn with<T>(&self, f: impl FnOnce(&mut Arena<Scope>) -> T) -> Result<T> {
-        todo!()
+        let inner = unsafe { &mut *self.0.borrow().arena.get() };
+        Ok(f(inner))
+        // todo!()
     }
 
     unsafe fn inner_unchecked<'s>() -> &'s mut Arena<Scope> {

+ 1 - 1
packages/core/src/events.rs

@@ -81,7 +81,7 @@ pub mod on {
                         Listener {
                             event: stringify!($name),
                             id: *c.listener_id.borrow(),
-                            scope: c.scope_ref.myidx,
+                            scope: c.scope_ref.arena_idx,
                             callback: bump.alloc(move |evt: VirtualEvent| match evt {
                                 VirtualEvent::$eventdata(event) => callback(event),
                                 _ => {

+ 1 - 1
packages/core/src/nodebuilder.rs

@@ -342,7 +342,7 @@ where
             event,
             callback: bump.alloc(callback),
             id: *self.ctx.listener_id.borrow(),
-            scope: self.ctx.scope_ref.myidx,
+            scope: self.ctx.scope_ref.arena_idx,
         };
         self.add_listener(listener)
     }

+ 25 - 15
packages/core/src/virtual_dom.rs

@@ -277,13 +277,13 @@ impl VirtualDom {
             // Start a new mutable borrow to components
             // We are guaranteeed that this scope is unique because we are tracking which nodes have modified
 
-            let component = self.components.try_get_mut(update.idx).unwrap();
+            let mut cur_component = self.components.try_get_mut(update.idx).unwrap();
 
-            component.run_scope()?;
+            cur_component.run_scope()?;
 
-            diff_machine.diff_node(component.old_frame(), component.next_frame());
+            diff_machine.diff_node(cur_component.old_frame(), cur_component.next_frame());
 
-            cur_height = component.height;
+            cur_height = cur_component.height;
 
             log::debug!(
                 "Processing update: {:#?} with height {}",
@@ -315,7 +315,7 @@ impl VirtualDom {
                                 Scope::new(
                                     caller,
                                     f,
-                                    None,
+                                    Some(cur_component.arena_idx),
                                     cur_height + 1,
                                     self.event_queue.clone(),
                                     self.components.clone(),
@@ -323,20 +323,23 @@ impl VirtualDom {
                             })
                         })?;
 
+                        cur_component.children.borrow_mut().insert(idx);
+
                         // Grab out that component
-                        let component = self.components.try_get_mut(idx).unwrap();
+                        let new_component = self.components.try_get_mut(idx).unwrap();
 
                         // Actually initialize the caller's slot with the right address
                         *stable_scope_addr.upgrade().unwrap().as_ref().borrow_mut() = Some(idx);
 
                         // Run the scope for one iteration to initialize it
-                        component.run_scope()?;
+                        new_component.run_scope()?;
 
                         // Navigate the diff machine to the right point in the output dom
                         diff_machine.change_list.load_known_root(id);
 
                         // And then run the diff algorithm
-                        diff_machine.diff_node(component.old_frame(), component.next_frame());
+                        diff_machine
+                            .diff_node(new_component.old_frame(), new_component.next_frame());
 
                         // Finally, insert this node as a seen node.
                         seen_nodes.insert(idx);
@@ -439,6 +442,8 @@ pub struct Scope {
     // The parent's scope ID
     pub parent: Option<ScopeIdx>,
 
+    pub children: RefCell<HashSet<ScopeIdx>>,
+
     // A reference to the list of components.
     // This lets us traverse the component list whenever we need to access our parent or children.
     arena_link: ScopeArena,
@@ -446,7 +451,7 @@ pub struct Scope {
     pub shared_contexts: RefCell<HashMap<TypeId, Rc<dyn Any>>>,
 
     // Our own ID accessible from the component map
-    pub myidx: ScopeIdx,
+    pub arena_idx: ScopeIdx,
 
     pub height: u32,
 
@@ -521,8 +526,9 @@ impl Scope {
             frames: ActiveFrame::new(),
             listeners: Default::default(),
             hookidx: Default::default(),
+            children: Default::default(),
             parent,
-            myidx,
+            arena_idx: myidx,
             height,
             event_queue,
             arena_link,
@@ -549,6 +555,8 @@ impl Scope {
         // This breaks any latent references, invalidating every pointer referencing into it.
         self.frames.next().bump.reset();
 
+        *self.hookidx.borrow_mut() = 0;
+
         let caller = self
             .caller
             .upgrade()
@@ -777,23 +785,24 @@ impl Scope {
         let mut ctxs = self.shared_contexts.borrow_mut();
         let ty = TypeId::of::<T>();
 
-        let initialized = self.use_hook(
+        let is_initialized = self.use_hook(
             || false,
             |s| {
-                let i = *s;
+                let i = s.clone();
                 *s = true;
                 i
             },
             |_| {},
         );
 
-        match (initialized, ctxs.contains_key(&ty)) {
+        match (is_initialized, ctxs.contains_key(&ty)) {
             // Do nothing, already initialized and already exists
             (true, true) => {}
 
             // Needs to be initialized
             (false, false) => {
-                ctxs.insert(ty, Rc::new(init())).unwrap();
+                log::debug!("Initializing context...");
+                ctxs.insert(ty, Rc::new(init()));
             }
 
             (false, true) => panic!("Cannot initialize two contexts of the same type"),
@@ -807,6 +816,7 @@ impl Scope {
         let mut scope = Some(self);
 
         while let Some(inner) = scope {
+            log::debug!("Searching {:#?} for valid shared_context", inner.arena_idx);
             let shared_contexts = inner.shared_contexts.borrow();
             if let Some(shared_ctx) = shared_contexts.get(&ty) {
                 return Ok(shared_ctx.clone().downcast().unwrap());
@@ -849,7 +859,7 @@ impl EventQueue {
         let inner = self.clone();
         let marker = HeightMarker {
             height: source.height,
-            idx: source.myidx,
+            idx: source.arena_idx,
         };
         move || inner.0.as_ref().borrow_mut().push(marker)
     }

+ 66 - 0
packages/web/examples/context.rs

@@ -0,0 +1,66 @@
+
+use std::fmt::Display;
+
+use dioxus::{events::on::MouseEvent, prelude::*};
+use dioxus_core as dioxus;
+use dioxus_web::WebsysRenderer;
+
+fn main() {
+    wasm_logger::init(wasm_logger::Config::new(log::Level::Trace));
+    console_error_panic_hook::set_once();
+
+    wasm_bindgen_futures::spawn_local(async {
+        WebsysRenderer::new_with_props(Example, ())
+            .run()
+            .await
+            .unwrap()
+    });
+}
+
+
+#[derive(Debug)]
+struct CustomContext([&'static str; 3]);
+
+
+static Example: FC<()> = |ctx, props| {
+    ctx.create_context(|| CustomContext(["Jack", "Jill", "Bob"]));
+
+        let names = ctx.use_context::<CustomContext>();
+    // let name = names.0[props.id as usize];
+
+    ctx.render(rsx! {
+        div {
+            class: "py-12 px-4 text-center w-full max-w-2xl mx-auto"
+            span {
+                class: "text-sm font-semibold"
+                "Dioxus Example: Jack and Jill"
+            }
+            h2 {
+                class: "text-5xl mt-2 mb-6 leading-tight font-semibold font-heading"
+                "Hello"
+            }
+
+            CustomButton { id: 0 }
+            CustomButton { id: 1 }
+            CustomButton { id: 2 }
+        }
+    })
+};
+
+
+#[derive(Props, PartialEq)]
+struct ButtonProps {
+    id: u8,
+}
+
+fn CustomButton<'b, 'a,>(ctx: Context<'a>, props: &'b ButtonProps) -> DomTree {
+    let names = ctx.use_context::<CustomContext>();
+    let name = names.0[props.id as usize];
+
+    ctx.render(rsx!{
+        button {  
+            class: "inline-block py-4 px-8 mr-6 leading-none text-white bg-indigo-600 hover:bg-indigo-900 font-semibold rounded shadow"
+            "{name}"
+        }
+    })
+}

+ 4 - 0
packages/web/examples/derive.rs

@@ -0,0 +1,4 @@
+use dioxus::{events::on::MouseEvent, prelude::*};
+use dioxus_core as dioxus;
+use dioxus_web::WebsysRenderer;
+fn main() {}

+ 53 - 57
packages/web/examples/todomvcsingle.rs

@@ -1,68 +1,24 @@
+#![allow(non_snake_case)]
 use dioxus_core::prelude::*;
 use dioxus_web::WebsysRenderer;
 
 static APP_STYLE: &'static str = include_str!("./todomvc/style.css");
 
-fn main() {
-    wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
-}
-// =======================
-// state-related items
-// =======================
 pub static TODOS: AtomFamily<uuid::Uuid, TodoItem> = atom_family(|_| {});
 pub static FILTER: Atom<FilterState> = atom(|_| FilterState::All);
 pub static SHOW_ALL_TODOS: selector<bool> = selector(|g| g.getter(|f| false));
 
-#[derive(PartialEq)]
-pub enum FilterState {
-    All,
-    Active,
-    Completed,
-}
-
-#[derive(Debug, PartialEq, Clone)]
-pub struct TodoItem {
-    pub id: uuid::Uuid,
-    pub checked: bool,
-    pub contents: String,
-}
-
-impl RecoilContext<()> {
-    pub fn add_todo(&self, contents: String) {}
-    pub fn remove_todo(&self, id: &uuid::Uuid) {}
-    pub fn select_all_todos(&self) {}
-    pub fn toggle_todo(&self, id: &uuid::Uuid) {}
-    pub fn clear_completed(&self) {}
-    pub fn set_filter(&self, filter: &FilterState) {}
-}
-
-// =======================
-// Components
-// =======================
-pub fn App(ctx: Context, props: &()) -> DomTree {
-    ctx.render(rsx! {
-        div {
-            id: "app"
-            style { "{APP_STYLE}" }
-
-            // list
-            TodoList {}
-
-            // footer
-            footer {
-                class: "info"
-                p {"Double-click to edit a todo"}
-                p {
-                    "Created by "
-                    a { "jkelleyrtp", href: "http://github.com/jkelleyrtp/" }
-                }
-                p {
-                    "Part of "
-                    a { "TodoMVC", href: "http://todomvc.com" }
-                }
+fn main() {
+    wasm_bindgen_futures::spawn_local(WebsysRenderer::start(|ctx, props| {
+        ctx.render(rsx! {
+            div {
+                id: "app",
+                style { "{APP_STYLE}" }
+                TodoList {}
+                Footer {}
             }
-        }
-    })
+        })
+    }));
 }
 
 pub fn TodoList(ctx: Context, props: &()) -> DomTree {
@@ -125,11 +81,11 @@ pub fn TodoEntry(ctx: Context, props: &TodoEntryProps) -> DomTree {
                 type: "checkbox"
                 "{todo.checked}"
             }
-            {is_editing.then(|| rsx!(
+           {is_editing.then(|| rsx!(
                 input {
                     value: "{contents}"
                 }
-            ))}
+           ))}
         }
     ))
 }
@@ -175,6 +131,46 @@ pub fn FilterToggles(ctx: Context, props: &()) -> DomTree {
     })
 }
 
+pub fn Footer(ctx: Context, props: &()) -> DomTree {
+    ctx.render(rsx! {
+        footer {
+            class: "info"
+            p {"Double-click to edit a todo"}
+            p {
+                "Created by "
+                a { "jkelleyrtp", href: "http://github.com/jkelleyrtp/" }
+            }
+            p {
+                "Part of "
+                a { "TodoMVC", href: "http://todomvc.com" }
+            }
+        }
+    })
+}
+
+#[derive(PartialEq)]
+pub enum FilterState {
+    All,
+    Active,
+    Completed,
+}
+
+#[derive(Debug, PartialEq, Clone)]
+pub struct TodoItem {
+    pub id: uuid::Uuid,
+    pub checked: bool,
+    pub contents: String,
+}
+
+impl RecoilContext<()> {
+    pub fn add_todo(&self, contents: String) {}
+    pub fn remove_todo(&self, id: &uuid::Uuid) {}
+    pub fn select_all_todos(&self) {}
+    pub fn toggle_todo(&self, id: &uuid::Uuid) {}
+    pub fn clear_completed(&self) {}
+    pub fn set_filter(&self, filter: &FilterState) {}
+}
+
 pub use recoil::*;
 mod recoil {
     use dioxus_core::context::Context;