Feat: major overhaul, wire up event system
This commit is contained in:
1 parent
f47651b32a
commit
8295ac4b3d
20 files changed
+1418
-188
No files matched your search
@@ -40,7 +40,7 @@ use std::{
|
||||
pub struct VirtualDom<P: Properties> {
|
||||
/// All mounted components are arena allocated to make additions, removals, and references easy to work with
|
||||
/// A generational arean is used to re-use slots of deleted scopes without having to resize the underlying arena.
|
||||
components: Arena<Scope>,
|
||||
pub(crate) components: Arena<Scope>,
|
||||
|
||||
/// The index of the root component.
|
||||
base_scope: Index,
|
||||
@@ -48,7 +48,8 @@ pub struct VirtualDom<P: Properties> {
|
||||
/// Components generate lifecycle events
|
||||
event_queue: Vec<LifecycleEvent>,
|
||||
|
||||
root_props: P,
|
||||
// mark the root props with P, even though they're held by the root component
|
||||
_p: PhantomData<P>,
|
||||
}
|
||||
|
||||
/// Implement VirtualDom with no props for components that initialize their state internal to the VDom rather than externally.
|
||||
@@ -83,7 +84,7 @@ impl<P: Properties + 'static> VirtualDom<P> {
|
||||
let base_scope = components.insert(Scope::new(root, None));
|
||||
|
||||
// Create a new mount event with no root container
|
||||
let first_event = LifecycleEvent::mount(base_scope, None, 0);
|
||||
let first_event = LifecycleEvent::mount(base_scope, None, 0, root_props);
|
||||
|
||||
// Create an event queue with a mount for the base scope
|
||||
let event_queue = vec![first_event];
|
||||
@@ -92,83 +93,119 @@ impl<P: Properties + 'static> VirtualDom<P> {
|
||||
components,
|
||||
base_scope,
|
||||
event_queue,
|
||||
root_props,
|
||||
_p: PhantomData {},
|
||||
}
|
||||
}
|
||||
|
||||
/// Pop an event off the even queue and process it
|
||||
pub fn progress(&mut self) -> Result<(), ()> {
|
||||
let LifecycleEvent { index, event_type } = self.event_queue.pop().ok_or(())?;
|
||||
/// Pop an event off the event queue and process it
|
||||
pub fn progress(&mut self) -> Result<()> {
|
||||
let event = self.event_queue.pop().ok_or(Error::NoEvent)?;
|
||||
|
||||
let scope = self.components.get(index).ok_or(())?;
|
||||
|
||||
match event_type {
|
||||
// Component needs to be mounted to the virtual dom
|
||||
LifecycleType::Mount { to, under } => {
|
||||
// todo! run the FC with the bump allocator
|
||||
// Run it with its properties
|
||||
if let Some(other) = to {
|
||||
// mount to another component
|
||||
let p = ();
|
||||
} else {
|
||||
// mount to the root
|
||||
}
|
||||
}
|
||||
|
||||
// The parent for this component generated new props and the component needs update
|
||||
LifecycleType::PropsChanged {} => {}
|
||||
|
||||
// Component was successfully mounted to the dom
|
||||
LifecycleType::Mounted {} => {}
|
||||
|
||||
// Component was removed from the DOM
|
||||
// Run any destructors and cleanup for the hooks and the dump the component
|
||||
LifecycleType::Removed {} => {
|
||||
let f = self.components.remove(index);
|
||||
}
|
||||
|
||||
// Component was messaged via the internal subscription service
|
||||
LifecycleType::Messaged => {}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
process_event(self, event)
|
||||
}
|
||||
|
||||
/// Update the root props, causing a full event cycle
|
||||
pub fn update_props(&mut self, new_props: P) {}
|
||||
}
|
||||
|
||||
/// Run through every event in the event queue until the events are empty.
|
||||
/// Function is asynchronous to allow for async components to finish their work.
|
||||
pub async fn progess_completely() {}
|
||||
/// Using mutable access to the Virtual Dom, progress a given lifecycle event
|
||||
///
|
||||
///
|
||||
///
|
||||
///
|
||||
///
|
||||
///
|
||||
fn process_event<P: Properties>(
|
||||
dom: &mut VirtualDom<P>,
|
||||
LifecycleEvent { index, event_type }: LifecycleEvent,
|
||||
) -> Result<()> {
|
||||
let scope = dom.components.get(index).ok_or(Error::NoEvent)?;
|
||||
|
||||
/// Create a new context object for a given component and scope
|
||||
fn new_context<T: Properties>(&self) -> Context {
|
||||
// fn new_context<T: Properties>(&self) -> Context<T> {
|
||||
todo!()
|
||||
match event_type {
|
||||
// Component needs to be mounted to the virtual dom
|
||||
LifecycleType::Mount { to, under, props } => {
|
||||
if let Some(other) = to {
|
||||
// mount to another component
|
||||
} else {
|
||||
// mount to the root
|
||||
}
|
||||
|
||||
let g = props.as_ref();
|
||||
scope.run(g);
|
||||
// scope.run(runner, props, dom);
|
||||
}
|
||||
|
||||
// The parent for this component generated new props and the component needs update
|
||||
LifecycleType::PropsChanged { props } => {
|
||||
//
|
||||
}
|
||||
|
||||
// Component was successfully mounted to the dom
|
||||
LifecycleType::Mounted {} => {
|
||||
//
|
||||
}
|
||||
|
||||
// Component was removed from the DOM
|
||||
// Run any destructors and cleanup for the hooks and the dump the component
|
||||
LifecycleType::Removed {} => {
|
||||
let f = dom.components.remove(index);
|
||||
}
|
||||
|
||||
// Component was messaged via the internal subscription service
|
||||
LifecycleType::Messaged => {
|
||||
//
|
||||
}
|
||||
|
||||
// Event from renderer was fired with a given listener ID
|
||||
//
|
||||
LifecycleType::Callback { listener_id } => {}
|
||||
}
|
||||
|
||||
/// Stop writing to the current buffer and start writing to the new one.
|
||||
/// This should be done inbetween CallbackEvent handling, but not between lifecycle events.
|
||||
pub fn swap_buffers(&mut self) {}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub struct LifecycleEvent {
|
||||
pub index: Index,
|
||||
pub event_type: LifecycleType,
|
||||
}
|
||||
impl LifecycleEvent {
|
||||
fn mount(which: Index, to: Option<Index>, under: usize) -> Self {
|
||||
Self {
|
||||
index: which,
|
||||
event_type: LifecycleType::Mount { to, under },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The internal lifecycle event system is managed by these
|
||||
/// Right now, we box the properties and but them in the enum
|
||||
/// Later, we could directly call the chain of children without boxing
|
||||
/// We could try to reuse the boxes somehow
|
||||
pub enum LifecycleType {
|
||||
Mount { to: Option<Index>, under: usize },
|
||||
PropsChanged,
|
||||
Mount {
|
||||
to: Option<Index>,
|
||||
under: usize,
|
||||
props: Box<dyn Properties>,
|
||||
},
|
||||
PropsChanged {
|
||||
props: Box<dyn Properties>,
|
||||
},
|
||||
Mounted,
|
||||
Removed,
|
||||
Messaged,
|
||||
Callback {
|
||||
listener_id: i32,
|
||||
},
|
||||
}
|
||||
|
||||
impl LifecycleEvent {
|
||||
// helper method for shortcutting to the enum type
|
||||
// probably not necessary
|
||||
fn mount<P: Properties + 'static>(
|
||||
which: Index,
|
||||
to: Option<Index>,
|
||||
under: usize,
|
||||
props: P,
|
||||
) -> Self {
|
||||
Self {
|
||||
index: which,
|
||||
event_type: LifecycleType::Mount {
|
||||
to,
|
||||
under,
|
||||
props: Box::new(props),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user