diff --git a/notes/CHANGELOG.md b/notes/CHANGELOG.md
index 242208ab0..3ab2f409a 100644
--- a/notes/CHANGELOG.md
+++ b/notes/CHANGELOG.md
@@ -1,55 +1,14 @@
-
-
-
-# Project: Live-View 🤲 🍨
-> Combine the server and client into a single file :)
-
-
-# Project: Sanitization (TBD)
-> Improve code health
-- [ ] (Macro) Clippy sanity for html macro
-- [ ] (Macro) Error sanitization
-
-# Project: Examples
-> Get *all* the examples
-- [ ] (Examples) Tide example with templating
-
-# Project: State management
-> Get some global state management installed with the hooks API
-
-
-# Project: Concurrency (TBD)
-> Ensure the concurrency model works well, play with lifetimes to check if it can be multithreaded + halted
-
-
-# Project: Web-View 🤲 🍨
-> Proof of concept: stream render edits from server to client
-- [x] Prove that the diffing and patching framework can support patch streaming
-
-# Project: Web_sys renderer (TBD)
-- [x] WebSys edit interpreter
-- [x] Event system using async channels
-- [ ] Implement conversion of all event types into synthetic events
-# Project: String Render (TBD)
-> Implement a light-weight string renderer with basic caching
-- [x] (Macro) Make VText nodes automatically capture and format IE allow "Text is {blah}"
-- [ ] (SSR) Implement stateful 3rd party string renderer
-
-# Project: Hooks + Context + Subscriptions (TBD)
-> Implement the foundations for state management
-- [x] Implement context object
-- [x] Implement use_state (rewrite to use the use_reducer api like rei)
-- [x] Implement use_ref
-- [x] Implement use_context (only the API, not the state management solution)
-- [ ] Implement use_reducer (WIP)
-
-# Project: QOL
-> Make it easier to write components
-- [x] (Macro) Tweak event syntax to not be dependent on wasm32 target (just return regular closures which get boxed/alloced)
-- [x] (Macro) Tweak component syntax to accept a new custom element
-- [ ] (Macro) Allow components to specify their props as function args
-
-# Project: Initial VDOM support (TBD)
+# Dioxus v0.1.0
+Welcome to the first iteration of the Dioxus Virtual DOM! This release brings support for:
+- Web via WASM
+- Desktop via webview integration
+- Server-rendering with custom Display Impl
+- Liveview (experimental)
+- Mobile (experimental)
+- State management
+- Build CLI
+----
+## Project: Initial VDOM support (TBD)
> Get the initial VDom + Event System + Patching + Diffing + Component framework up and running
> Get a demo working using just the web
- [x] (Core) Migrate virtual node into new VNode type
@@ -61,3 +20,73 @@
- [x] (Core) Implement child nodes, scope creation
- [ ] (Core) Implement dirty tagging and compression
+## Project: QOL
+> Make it easier to write components
+- [x] (Macro) Tweak event syntax to not be dependent on wasm32 target (just return regular closures which get boxed/alloced)
+- [x] (Macro) Tweak component syntax to accept a new custom element
+- [ ] (Macro) Allow components to specify their props as function args (not going to do)
+
+## Project: Hooks + Context + Subscriptions (TBD)
+> Implement the foundations for state management
+- [x] Implement context object
+- [x] Implement use_state (rewrite to use the use_reducer api like rei)
+- [x] Implement use_ref
+- [x] Implement use_context (only the API, not the state management solution)
+- [ ] Implement use_reducer (WIP)
+
+## Project: String Render (TBD)
+> Implement a light-weight string renderer with basic caching
+- [x] (Macro) Make VText nodes automatically capture and format IE allow "Text is {blah}"
+- [x] (SSR) Implement stateful 3rd party string renderer
+
+## Project: Web_sys renderer (TBD)
+- [x] WebSys edit interpreter
+- [x] Event system using async channels
+- [ ] Implement conversion of all event types into synthetic events
+
+## Project: Web-View 🤲 🍨
+> Proof of concept: stream render edits from server to client
+- [x] Prove that the diffing and patching framework can support patch streaming
+
+## Project: Examples
+> Get *all* the examples
+- [ ] (Examples) Tide example with templating
+
+## Project: State management
+> Get some global state management installed with the hooks + context API
+
+
+## Project: Concurrency (TBD)
+> Ensure the concurrency model works well, play with lifetimes to check if it can be multithreaded + halted
+?
+
+
+## Project: Mobile exploration
+
+
+## Project: Live-View 🤲 🍨
+> Combine the server and client into a single file :)
+
+
+## Project: Sanitization (TBD)
+> Improve code health
+- [ ] (Macro) Clippy sanity for html macro
+- [ ] (Macro) Error sanitization
+
+
+## Outstanding todos:
+> anything missed so far
+- dirty tagging, compression
+- fragments
+- make ssr follow HTML spec
+- code health
+- miri tests
+- todo mvc
+- fix
+- node refs (postpone for future release?)
+- styling built-in (future release?)
+- key handler?
+- FC macro
+- Documentation overhaul
+- Website
+- keys on components
diff --git a/packages/core-macro/src/rsxt.rs b/packages/core-macro/src/rsxt.rs
index 0cb16f5f8..19e123416 100644
--- a/packages/core-macro/src/rsxt.rs
+++ b/packages/core-macro/src/rsxt.rs
@@ -16,7 +16,24 @@ use {
// ==============================================
pub struct RsxRender {
custom_context: Option,
- el: Element,
+ root: RootOption,
+}
+
+enum RootOption {
+ // for lists of components
+ Fragment(),
+ Element(Element),
+ Component(Component),
+}
+
+impl ToTokens for RootOption {
+ fn to_tokens(&self, tokens: &mut TokenStream2) {
+ match self {
+ RootOption::Fragment() => todo!(),
+ RootOption::Element(el) => el.to_tokens(tokens),
+ RootOption::Component(comp) => comp.to_tokens(tokens),
+ }
+ }
}
impl Parse for RsxRender {
@@ -33,14 +50,24 @@ impl Parse for RsxRender {
})
.ok();
- let el: Element = input.parse()?;
- Ok(Self { el, custom_context })
+ let forked = input.fork();
+ let name = forked.parse::()?;
+
+ let root = match crate::util::is_valid_tag(&name.to_string()) {
+ true => input.parse::().map(|el| RootOption::Element(el)),
+ false => input.parse::().map(|c| RootOption::Component(c)),
+ }?;
+
+ Ok(Self {
+ root,
+ custom_context,
+ })
}
}
impl ToTokens for RsxRender {
fn to_tokens(&self, out_tokens: &mut TokenStream2) {
- let new_toks = (&self.el).to_token_stream();
+ let new_toks = (&self.root).to_token_stream();
// create a lazy tree that accepts a bump allocator
let final_tokens = match &self.custom_context {
diff --git a/packages/core/Cargo.toml b/packages/core/Cargo.toml
index e92f5d2fc..39787b78f 100644
--- a/packages/core/Cargo.toml
+++ b/packages/core/Cargo.toml
@@ -17,10 +17,7 @@ dioxus-core-macro = { path = "../core-macro", version = "0.1.1" }
generational-arena = { version = "0.2.8", features = ["serde"] }
# Bumpalo backs the VNode creation
-bumpalo = { version = "3.6.0", features = ["collections"] }
-
-# Backs hook data - might move away from this arena
-typed-arena = "2.0.1"
+bumpalo = { version = "3.6.0", features = ["collections", "boxed"] }
# custom error type
thiserror = "1.0.23"
@@ -34,7 +31,7 @@ longest-increasing-subsequence = "0.1.0"
# internall used
log = "0.4.14"
-serde = { version = "1.0.123", features = ["derive"], optional=true }
+serde = { version = "1.0.123", features = ["derive"], optional = true }
[features]
default = []
diff --git a/packages/core/examples/borrowed.rs b/packages/core/examples/borrowed.rs
index d1fd7728d..97b8ea801 100644
--- a/packages/core/examples/borrowed.rs
+++ b/packages/core/examples/borrowed.rs
@@ -22,7 +22,7 @@ struct ListItem {
}
fn app<'a>(ctx: Context<'a>, props: &Props) -> DomTree {
- let val = use_state(&ctx, || 0);
+ let (val, set_val) = use_state(&ctx, || 0);
ctx.render(dioxus::prelude::LazyNodes::new(move |c| {
let mut root = builder::ElementBuilder::new(c, "div");
@@ -36,7 +36,7 @@ fn app<'a>(ctx: Context<'a>, props: &Props) -> DomTree {
// create the props with nothing but the fc
fc_to_builder(ChildItem)
.item(child)
- .item_handler(val.setter())
+ .item_handler(set_val)
.build(),
));
}
diff --git a/packages/core/examples/listener.rs b/packages/core/examples/listener.rs
index 93f7416ec..fe87513a7 100644
--- a/packages/core/examples/listener.rs
+++ b/packages/core/examples/listener.rs
@@ -11,13 +11,13 @@ fn main() {
}
static Example: FC<()> = |ctx, props| {
- let name = use_state(&ctx, || "...?");
+ let (name, set_name) = use_state(&ctx, || "...?");
ctx.render(html! {
"Hello, {name}"
-
-
+
+
})
};
diff --git a/packages/core/src/context.rs b/packages/core/src/context.rs
index 3a1d2d013..718d3b64d 100644
--- a/packages/core/src/context.rs
+++ b/packages/core/src/context.rs
@@ -2,7 +2,7 @@ use crate::{nodebuilder::IntoDomTree, prelude::*};
use crate::{nodebuilder::LazyNodes, nodes::VNode};
use bumpalo::Bump;
use hooks::Hook;
-use std::{cell::RefCell, future::Future, ops::Deref, rc::Rc, sync::atomic::AtomicUsize};
+use std::{cell::RefCell, future::Future, ops::Deref, pin::Pin, rc::Rc, sync::atomic::AtomicUsize};
/// Components in Dioxus use the "Context" object to interact with their lifecycle.
/// This lets components schedule updates, integrate hooks, and expose their context via the context api.
@@ -25,13 +25,14 @@ use std::{cell::RefCell, future::Future, ops::Deref, rc::Rc, sync::atomic::Atomi
// todo: force lifetime of source into T as a valid lifetime too
// it's definitely possible, just needs some more messing around
pub struct Context<'src> {
- pub idx: AtomicUsize,
+ pub idx: RefCell,
pub scope: ScopeIdx,
// Borrowed from scope
- pub(crate) arena: &'src typed_arena::Arena,
- pub(crate) hooks: &'src RefCell>,
+ // pub(crate) arena: &'src typed_arena::Arena,
+ pub(crate) hooks: &'src RefCell>,
+ // pub(crate) hooks: &'src RefCell>,
pub(crate) bump: &'src Bump,
pub listeners: &'src RefCell>,
@@ -114,14 +115,16 @@ impl<'a> Context<'a> {
/// This module provides internal state management functionality for Dioxus components
pub mod hooks {
+ use std::any::Any;
+
use super::*;
#[derive(Debug)]
- pub struct Hook(pub Box);
+ pub struct Hook(pub Pin>);
impl Hook {
- pub fn new(state: Box) -> Self {
- Self(state)
+ pub fn new(state: T) -> Self {
+ Self(Box::pin(state))
}
}
@@ -139,28 +142,27 @@ pub mod hooks {
// TODO: add this to the "clean up" group for when the component is dropped
_cleanup: impl FnOnce(InternalHookState),
) -> Output {
- let raw_hook = {
- let idx = self.idx.load(std::sync::atomic::Ordering::Relaxed);
+ let idx = *self.idx.borrow();
- // Mutate hook list if necessary
- let mut hooks = self.hooks.borrow_mut();
+ // Mutate hook list if necessary
+ let mut hooks = self.hooks.borrow_mut();
- // Initialize the hook by allocating it in the typed arena.
- // We get a reference from the arena which is owned by the component scope
- // This is valid because "Context" is only valid while the scope is borrowed
- if idx >= hooks.len() {
- let new_state = initializer();
- let boxed_state: Box = Box::new(new_state);
- let hook = self.arena.alloc(Hook::new(boxed_state));
+ // Initialize the hook by allocating it in the typed arena.
+ // We get a reference from the arena which is owned by the component scope
+ // This is valid because "Context" is only valid while the scope is borrowed
+ if idx >= hooks.len() {
+ let new_state = initializer();
+ hooks.push(Hook::new(new_state));
+ }
+ *self.idx.borrow_mut() = 1;
- // Push the raw pointer instead of the &mut
- // A "poor man's OwningRef"
- hooks.push(hook);
- }
- self.idx.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
+ let stable_ref = hooks.get_mut(idx).unwrap().0.as_mut();
+ let v = unsafe { Pin::get_unchecked_mut(stable_ref) };
+ let internal_state = v.downcast_mut::().unwrap();
- *hooks.get(idx).unwrap()
- };
+ // we extend the lifetime from borrowed in this scope to borrowed from self.
+ // This is okay because the hook is pinned
+ runner(unsafe { &mut *(internal_state as *mut _) })
/*
** UNSAFETY ALERT **
@@ -178,11 +180,17 @@ pub mod hooks {
- We don't expose the raw hook pointer outside of the scope of use_hook
- The reference is tied to context, meaning it can only be used while ctx is around to free it
*/
- let borrowed_hook: &'a mut _ = unsafe { raw_hook.as_mut().unwrap() };
+ // let raw_hook: &'scope mut _ = unsafe { &mut *raw_hook };
+ // let p = raw_hook.0.downcast_mut::();
+ // let r = p.unwrap();
+ // let v = unsafe { Pin::get_unchecked_mut(raw_hook) };
+ // // let carreied_ref: &'scope mut dyn Any = unsafe { &mut *v };
+ // let internal_state = v.downcast_mut::().unwrap();
- let internal_state = borrowed_hook.0.downcast_mut::().unwrap();
+ // let real_internal = unsafe { internal_state as *mut _ };
- runner(internal_state)
+ // runner(unsafe { &mut *real_internal })
+ // runner(internal_state)
}
}
}
@@ -247,6 +255,8 @@ Context should *never* be dangling!. If a Context is torn down, so should anythi
pub fn use_context(&'a self, _narrow: impl Fn(&'_ I) -> &'_ O) -> RemoteState {
todo!()
}
+
+ pub fn create_context(&self, creator: impl FnOnce() -> T) {}
}
/// # SAFETY ALERT
diff --git a/packages/core/src/hooks.rs b/packages/core/src/hooks.rs
index bc0f470f6..3ba5333e3 100644
--- a/packages/core/src/hooks.rs
+++ b/packages/core/src/hooks.rs
@@ -5,6 +5,7 @@
//! - [ ] use_reducer
//! - [ ] use_effect
+pub use new_use_state_def::use_state_new;
pub use use_reducer_def::use_reducer;
pub use use_ref_def::use_ref;
pub use use_state_def::use_state;
@@ -13,15 +14,94 @@ mod use_state_def {
use crate::innerlude::*;
use std::{
cell::RefCell,
- fmt::Display,
ops::{Deref, DerefMut},
rc::Rc,
};
+ struct UseState {
+ new_val: Rc>>,
+ current_val: T,
+ caller: Box,
+ }
+
+ /// Store state between component renders!
+ /// When called, this hook retrives a stored value and provides a setter to update that value.
+ /// When the setter is called, the component is re-ran with the new value.
+ ///
+ /// This is behaves almost exactly the same way as React's "use_state".
+ ///
+ /// Usage:
+ /// ```ignore
+ /// static Example: FC<()> = |ctx| {
+ /// let (counter, set_counter) = use_state(ctx, || 0);
+ /// let increment = |_| set_couter(counter + 1);
+ /// let decrement = |_| set_couter(counter + 1);
+ ///
+ /// html! {
+ ///
+ ///
"Counter: {counter}"
+ ///
+ ///
+ ///
+ /// }
+ /// }
+ /// ```
+ pub fn use_state<'a, 'c, T: 'static, F: FnOnce() -> T>(
+ ctx: &'c Context<'a>,
+ initial_state_fn: F,
+ ) -> (&'a T, &'a impl Fn(T)) {
+ ctx.use_hook(
+ move || UseState {
+ new_val: Rc::new(RefCell::new(None)),
+ current_val: initial_state_fn(),
+ caller: Box::new(|_| println!("setter called!")),
+ },
+ move |hook| {
+ log::debug!("Use_state set called");
+ let inner = hook.new_val.clone();
+ let scheduled_update = ctx.schedule_update();
+
+ // get ownership of the new val and replace the current with the new
+ // -> as_ref -> borrow_mut -> deref_mut -> take
+ // -> rc -> &RefCell -> RefMut -> &Option -> T
+ if let Some(new_val) = hook.new_val.as_ref().borrow_mut().deref_mut().take() {
+ hook.current_val = new_val;
+ }
+
+ // todo: swap out the caller with a subscription call and an internal update
+ hook.caller = Box::new(move |new_val| {
+ // update the setter with the new value
+ let mut new_inner = inner.as_ref().borrow_mut();
+ *new_inner = Some(new_val);
+
+ // Ensure the component gets updated
+ scheduled_update();
+ });
+
+ // box gets derefed into a ref which is then taken as ref with the hook
+ (&hook.current_val, &hook.caller)
+ },
+ |_| {},
+ )
+ }
+}
+
+mod new_use_state_def {
+ use crate::innerlude::*;
+ use std::{
+ cell::RefCell,
+ fmt::{Debug, Display},
+ ops::{Deref, DerefMut},
+ pin::Pin,
+ rc::Rc,
+ };
+
pub struct UseState {
modifier: Rc>>>,
current_val: T,
update: Box,
+ setter: Box,
+ // setter: Box,
}
// #[derive(Clone, Copy)]
@@ -33,8 +113,11 @@ mod use_state_def {
impl<'a, T: 'static> UseState {
pub fn setter(&self) -> &dyn Fn(T) {
- todo!()
+ &self.setter
+ // let r = self.setter.as_mut();
+ // unsafe { Pin::get_unchecked_mut(r) }
}
+
pub fn set(&self, new_val: T) {
self.modify(|f| *f = new_val);
}
@@ -84,7 +167,7 @@ mod use_state_def {
/// }
/// }
/// ```
- pub fn use_state<'a, 'c, T: 'static, F: FnOnce() -> T>(
+ pub fn use_state_new<'a, 'c, T: 'static, F: FnOnce() -> T>(
ctx: &'c Context<'a>,
initial_state_fn: F,
) -> &'a UseState {
@@ -93,19 +176,32 @@ mod use_state_def {
modifier: Rc::new(RefCell::new(None)),
current_val: initial_state_fn(),
update: Box::new(|| {}),
+ setter: Box::new(|_| {}),
},
move |hook| {
+ log::debug!("addr of hook: {:#?}", hook as *const _);
let scheduled_update = ctx.schedule_update();
+ // log::debug!("Checking if new value {:#?}", &hook.current_val);
// get ownership of the new val and replace the current with the new
// -> as_ref -> borrow_mut -> deref_mut -> take
// -> rc -> &RefCell -> RefMut -> &Option -> T
if let Some(new_val) = hook.modifier.as_ref().borrow_mut().deref_mut().take() {
+ // log::debug!("setting prev {:#?}", &hook.current_val);
(new_val)(&mut hook.current_val);
+ // log::debug!("setting new value {:#?}", &hook.current_val);
}
hook.update = Box::new(move || scheduled_update());
+ let modifier = hook.modifier.clone();
+ hook.setter = Box::new(move |new_val: T| {
+ let mut slot = modifier.as_ref().borrow_mut();
+
+ let slot2 = slot.deref_mut();
+ *slot2 = Some(Box::new(move |old: &mut T| *old = new_val));
+ });
+
&*hook
},
|_| {},
diff --git a/packages/core/src/nodebuilder.rs b/packages/core/src/nodebuilder.rs
index b938e4fe2..3e0a04173 100644
--- a/packages/core/src/nodebuilder.rs
+++ b/packages/core/src/nodebuilder.rs
@@ -566,6 +566,11 @@ where
std::iter::once(self)
}
}
+impl<'a> IntoDomTree<'a> for () {
+ fn into_vnode(self, ctx: &NodeCtx<'a>) -> VNode<'a> {
+ VNode::Suspended
+ }
+}
#[test]
fn test_iterator_of_nodes<'b>() {
@@ -646,9 +651,6 @@ pub fn text2<'a>(contents: bumpalo::collections::String<'a>) -> VNode<'a> {
let f: &'a str = contents.into_bump_str();
VNode::text(f)
}
-// pub fn text<'a>(contents: &'a str) -> VNode<'a> {
-// VNode::text(contents)
-// }
/// Construct an attribute for an element.
///
@@ -666,35 +668,9 @@ pub fn attr<'a>(name: &'static str, value: &'a str) -> Attribute<'a> {
Attribute { name, value }
}
-// /// Create an event listener.
-// ///
-// /// `event` is the type of event to listen for, e.g. `"click"`. The `callback`
-// /// is the function that will be invoked when the event occurs.
-// ///
-// /// # Example
-// ///
-// /// ```no_run
-// /// use dioxus::{builder::*, bumpalo::Bump};
-// ///
-// /// let b = Bump::new();
-// ///
-// /// let listener = on(&b, "click", |root, vdom, event| {
-// /// // do something when a click happens...
-// /// });
-// /// ```
-// pub fn on<'a, 'b>(
-// // pub fn on<'a, F: 'static>(
-// bump: &'a Bump,
-// event: &'static str,
-// callback: impl Fn(VirtualEvent) + 'a,
-// ) -> Listener<'a> {
-// Listener {
-// event,
-// callback: bump.alloc(callback),
-// }
-// }
-
pub fn virtual_child<'a, T: Properties + 'a>(ctx: &NodeCtx<'a>, f: FC, p: T) -> VNode<'a> {
+ // currently concerned about if props have a custom drop implementation
+ // might override it with the props macro
let propsd: &'a mut _ = ctx.bump.alloc(p);
VNode::Component(crate::nodes::VComponent::new(f, propsd))
}
diff --git a/packages/core/src/scope.rs b/packages/core/src/scope.rs
index 040e080b8..c5e4e6c63 100644
--- a/packages/core/src/scope.rs
+++ b/packages/core/src/scope.rs
@@ -36,9 +36,9 @@ pub struct Scope {
// These two could be combined with "OwningRef" to remove unsafe usage
// or we could dedicate a tiny bump arena just for them
// could also use ourborous
- pub hooks: RefCell>,
+ pub hooks: RefCell>,
- pub hook_arena: typed_arena::Arena,
+ pub hook_arena: Vec,
// Unsafety:
// - is self-refenrential and therefore needs to point into the bump
@@ -63,7 +63,7 @@ impl Scope {
Self {
caller: broken_caller,
- hook_arena: typed_arena::Arena::new(),
+ hook_arena: Vec::new(),
hooks: RefCell::new(Vec::new()),
frames: ActiveFrame::new(),
children: HashSet::new(),
@@ -92,7 +92,7 @@ impl Scope {
};
let ctx: Context<'b> = Context {
- arena: &self.hook_arena,
+ // arena: &self.hook_arena,
hooks: &self.hooks,
bump: &frame.bump,
idx: 0.into(),
@@ -145,7 +145,7 @@ impl Scope {
// Run the callback with the user event
log::debug!("Running listener");
listener(source);
- log::debug!("Running listener");
+ log::debug!("Listener finished");
// drain all the event listeners
// if we don't, then they'll stick around and become invalid
@@ -203,7 +203,7 @@ impl ActiveFrame {
}
}
- fn current_head_node<'b>(&'b self) -> &'b VNode<'b> {
+ pub fn current_head_node<'b>(&'b self) -> &'b VNode<'b> {
let raw_node = match *self.idx.borrow() & 1 == 0 {
true => &self.frames[0],
false => &self.frames[1],
@@ -217,7 +217,7 @@ impl ActiveFrame {
}
}
- fn prev_head_node<'b>(&'b self) -> &'b VNode<'b> {
+ pub fn prev_head_node<'b>(&'b self) -> &'b VNode<'b> {
let raw_node = match *self.idx.borrow() & 1 != 0 {
true => &self.frames[0],
false => &self.frames[1],
diff --git a/packages/core/src/virtual_dom.rs b/packages/core/src/virtual_dom.rs
index edbea9b70..a328d3a41 100644
--- a/packages/core/src/virtual_dom.rs
+++ b/packages/core/src/virtual_dom.rs
@@ -6,6 +6,8 @@ use generational_arena::Arena;
use std::{
any::TypeId,
borrow::{Borrow, BorrowMut},
+ cell::RefCell,
+ collections::{BTreeMap, BTreeSet},
rc::{Rc, Weak},
};
use thiserror::private::AsDynError;
@@ -19,11 +21,13 @@ pub(crate) type OpaqueComponent<'a> = dyn for<'b> Fn(Context<'b>) -> DomTree + '
pub struct VirtualDom {
/// All mounted components are arena allocated to make additions, removals, and references easy to work with
/// A generational arena is used to re-use slots of deleted scopes without having to resize the underlying arena.
- components: Arena,
+ pub components: Arena,
/// The index of the root component.
/// Will not be ready if the dom is fresh
- base_scope: ScopeIdx,
+ pub base_scope: ScopeIdx,
+
+ pub(crate) update_schedule: Rc>>,
// a strong allocation to the "caller" for the original props
#[doc(hidden)]
@@ -70,6 +74,7 @@ impl VirtualDom {
components,
_root_caller: root_caller,
base_scope,
+ update_schedule: Rc::new(RefCell::new(Vec::new())),
_root_prop_type: TypeId::of::
(),
}
}
@@ -85,13 +90,14 @@ impl VirtualDom {
let mut diff_machine = DiffMachine::new();
let very_unsafe_components = &mut self.components as *mut generational_arena::Arena;
- let mut component = self
+ let component = self
.components
.get_mut(self.base_scope)
.ok_or_else(|| Error::FatalInternal("Acquring base component should never fail"))?;
component.run_scope()?;
diff_machine.diff_node(component.old_frame(), component.new_frame());
+ // log::debug!("New events generated: {:#?}", diff_machine.lifecycle_events);
// chew down the the lifecycle events until all dirty nodes are computed
while let Some(event) = diff_machine.lifecycle_events.pop_front() {
match event {
@@ -119,6 +125,7 @@ impl VirtualDom {
}
}
LifeCycleEvent::PropsChanged { caller, id, scope } => {
+ log::debug!("PROPS CHANGED");
let idx = scope.upgrade().unwrap().as_ref().borrow().unwrap();
unsafe {
let p = &mut *(very_unsafe_components);
@@ -131,6 +138,7 @@ impl VirtualDom {
// break 'render;
}
LifeCycleEvent::SameProps { caller, id, scope } => {
+ log::debug!("SAME PROPS RECEIVED");
//
// break 'render;
}
@@ -181,7 +189,15 @@ impl VirtualDom {
.expect("Borrowing should not fail");
component.call_listener(event);
- component.run_scope()?;
+
+ /*
+ -> call listener
+ -> sort through accumulated queue by the top
+ -> run each component, running its children
+ -> add new updates to the tree of updates (these are dirty)
+ ->
+ */
+ // component.run_scope()?;
// let mut diff_machine = DiffMachine::new();
// let mut diff_machine = DiffMachine::new(&self.diff_bump);
@@ -192,3 +208,8 @@ impl VirtualDom {
self.rebuild()
}
}
+
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
+pub struct HierarchyMarker {
+ height: u32,
+}
diff --git a/packages/ssr/index.html b/packages/ssr/index.html
new file mode 100644
index 000000000..9021c236e
--- /dev/null
+++ b/packages/ssr/index.html
@@ -0,0 +1,102 @@
+