Feat: WIP ctx
This commit is contained in:
1 parent
b3e6886351
commit
7a6aabe4f3
18 files changed
+430
-99
No files matched your search
@@ -2,44 +2,47 @@
|
||||
//! for components to be used within Nodes.
|
||||
//!
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
use crate::innerlude::*;
|
||||
|
||||
/// The `Component` trait refers to any struct or funciton that can be used as a component
|
||||
/// We automatically implement Component for FC<T>
|
||||
pub trait Component {
|
||||
type Props: Properties;
|
||||
fn builder(&'static self) -> Self::Props;
|
||||
}
|
||||
// pub trait Component {
|
||||
// type Props: Properties<'static>;
|
||||
// fn builder(&'static self) -> Self::Props;
|
||||
// }
|
||||
|
||||
// Auto implement component for a FC
|
||||
// Calling the FC is the same as "rendering" it
|
||||
impl<P: Properties> Component for FC<P> {
|
||||
type Props = P;
|
||||
// // Auto implement component for a FC
|
||||
// // Calling the FC is the same as "rendering" it
|
||||
// impl<P: Properties<'static>> Component for FC<P> {
|
||||
// type Props = P;
|
||||
|
||||
fn builder(&self) -> Self::Props {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
// fn builder(&self) -> Self::Props {
|
||||
// todo!()
|
||||
// }
|
||||
// }
|
||||
|
||||
/// The `Properties` trait defines any struct that can be constructed using a combination of default / optional fields.
|
||||
/// Components take a "properties" object
|
||||
pub trait Properties // where
|
||||
// Self: Sized,
|
||||
{
|
||||
fn call(&self, ptr: *const ()) {}
|
||||
}
|
||||
// pub trait Properties<'a>
|
||||
// where
|
||||
// Self: Debug,
|
||||
// {
|
||||
// fn call(&self, ptr: *const ()) {}
|
||||
// }
|
||||
|
||||
// Auto implement for no-prop components
|
||||
impl Properties for () {
|
||||
fn call(&self, ptr: *const ()) {}
|
||||
}
|
||||
// // Auto implement for no-prop components
|
||||
// impl<'a> Properties<'a> for () {
|
||||
// fn call(&self, ptr: *const ()) {}
|
||||
// }
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::prelude::bumpalo::Bump;
|
||||
|
||||
fn test_static_fn<'a, P: Properties>(b: &'a Bump, r: FC<P>) -> VNode<'a> {
|
||||
fn test_static_fn<'a, P>(b: &'a Bump, r: FC<P>) -> VNode<'a> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
|
||||
@@ -68,8 +68,12 @@ impl<'a> Context<'a> {
|
||||
/// ctx.view(lazy_tree)
|
||||
/// }
|
||||
///```
|
||||
pub fn view(self, lazy_nodes: impl FnOnce(&'a Bump) -> VNode<'a> + 'a) -> VNode<'a> {
|
||||
lazy_nodes(self.bump)
|
||||
pub fn view(self, lazy_nodes: impl FnOnce(&'a Bump) -> VNode<'a> + 'a) -> DomTree {
|
||||
// pub fn view(self, lazy_nodes: impl for<'b> FnOnce(&'b Bump) -> VNode<'b> + 'a + 'p) -> DomTree {
|
||||
// pub fn view<'p>(self, lazy_nodes: impl FnOnce(&'a Bump) -> VNode<'a> + 'a + 'p) -> DomTree {
|
||||
// pub fn view(self, lazy_nodes: impl FnOnce(&'a Bump) -> VNode<'a> + 'a) -> VNode<'a> {
|
||||
let g = lazy_nodes(self.bump);
|
||||
DomTree {}
|
||||
}
|
||||
|
||||
pub fn callback(&self, f: impl Fn(()) + 'static) {}
|
||||
@@ -103,12 +107,12 @@ pub mod hooks {
|
||||
/// TODO: @jon, rework this so we dont have to use unsafe to make hooks and then return them
|
||||
/// use_hook provides a way to store data between renders for functional components.
|
||||
/// todo @jon: ensure the hook arena is stable with pin or is stable by default
|
||||
pub fn use_hook<'internal, 'scope, InternalHookState: 'static, Output: 'internal>(
|
||||
pub fn use_hook<'scope, InternalHookState: 'static, Output: 'a>(
|
||||
&'scope self,
|
||||
// The closure that builds the hook state
|
||||
initializer: impl FnOnce() -> InternalHookState,
|
||||
// The closure that takes the hookstate and returns some value
|
||||
runner: impl FnOnce(&'internal mut InternalHookState) -> Output,
|
||||
runner: impl FnOnce(&'a mut InternalHookState) -> Output,
|
||||
// The closure that cleans up whatever mess is left when the component gets torn down
|
||||
// TODO: add this to the "clean up" group for when the component is dropped
|
||||
cleanup: impl FnOnce(InternalHookState),
|
||||
@@ -152,7 +156,7 @@ 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: &'internal mut _ = unsafe { raw_hook.as_mut().unwrap() };
|
||||
let borrowed_hook: &'a mut _ = unsafe { raw_hook.as_mut().unwrap() };
|
||||
|
||||
let internal_state = borrowed_hook.0.downcast_mut::<InternalHookState>().unwrap();
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
//!
|
||||
//! Renderers don't actually need to own the virtual dom (it's up to the implementer).
|
||||
|
||||
use crate::prelude::{Properties, VirtualDom};
|
||||
use crate::prelude::VirtualDom;
|
||||
|
||||
pub struct DebugRenderer {
|
||||
vdom: VirtualDom,
|
||||
|
||||
@@ -40,8 +40,8 @@ mod use_state_def {
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub fn use_state<'a, T: 'static, F: FnOnce() -> T + 'static>(
|
||||
ctx: &'_ Context<'a>,
|
||||
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(
|
||||
@@ -93,7 +93,7 @@ mod use_ref_def {
|
||||
}
|
||||
}
|
||||
|
||||
fn modify(&self, modifier: impl FnOnce(&mut T)) {
|
||||
pub fn modify(&self, modifier: impl FnOnce(&mut T)) {
|
||||
let mut val = self._current.borrow_mut();
|
||||
let val_as_ref = val.deref_mut();
|
||||
modifier(val_as_ref);
|
||||
|
||||
@@ -87,7 +87,7 @@ pub mod builder {
|
||||
|
||||
// types used internally that are important
|
||||
pub(crate) mod innerlude {
|
||||
pub(crate) use crate::component::{Component, Properties};
|
||||
// pub(crate) use crate::component::Properties;
|
||||
use crate::context::hooks::Hook;
|
||||
pub(crate) use crate::context::Context;
|
||||
pub(crate) use crate::error::{Error, Result};
|
||||
@@ -99,7 +99,15 @@ pub(crate) mod innerlude {
|
||||
// pub use nodes::iterables::IterableNodes;
|
||||
/// This type alias is an internal way of abstracting over the static functions that represent components.
|
||||
|
||||
pub type FC<P> = for<'a> fn(Context<'a>, &'a P) -> VNode<'a>;
|
||||
pub type FC<P> = for<'scope> fn(Context<'scope>, &'scope P) -> DomTree;
|
||||
|
||||
mod fc2 {
|
||||
use super::*;
|
||||
}
|
||||
// pub type FC<'a, P: 'a> = for<'scope> fn(Context<'scope>, &'scope P) -> DomTree;
|
||||
// pub type FC<P> = for<'scope, 'r> fn(Context<'scope>, &'scope P) -> DomTree;
|
||||
// pub type FC<P> = for<'scope, 'r> fn(Context<'scope>, &'r P) -> VNode<'scope>;
|
||||
// pub type FC<P> = for<'scope, 'r> fn(Context<'scope>, &'r P) -> VNode<'scope>;
|
||||
// pub type FC<P> = for<'a> fn(Context<'a, P>) -> VNode<'a>;
|
||||
|
||||
// TODO @Jon, fix this
|
||||
@@ -116,7 +124,7 @@ pub(crate) mod innerlude {
|
||||
/// Re-export common types for ease of development use.
|
||||
/// Essential when working with the html! macro
|
||||
pub mod prelude {
|
||||
pub use crate::component::{Component, Properties};
|
||||
// pub use crate::component::Properties;
|
||||
pub use crate::context::Context;
|
||||
use crate::nodes;
|
||||
pub use crate::virtual_dom::VirtualDom;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
//! Helpers for building virtual DOM VNodes.
|
||||
|
||||
use crate::{
|
||||
innerlude::VComponent,
|
||||
nodes::{Attribute, Listener, NodeKey, VNode},
|
||||
prelude::VElement,
|
||||
};
|
||||
@@ -1079,3 +1080,8 @@ pub fn on<'a, 'b, F: 'static>(
|
||||
callback: bump.alloc(callback),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn virtual_child<'a, T>(bump: &'a Bump, props: T, f: crate::innerlude::FC<T>) -> VNode<'a> {
|
||||
todo!()
|
||||
// VNode::Component()
|
||||
}
|
||||
+25
-10
@@ -12,6 +12,10 @@ pub use velement::{Attribute, Listener, NodeKey};
|
||||
pub use vnode::VNode;
|
||||
pub use vtext::VText;
|
||||
|
||||
/// A domtree represents the result of "Viewing" the context
|
||||
/// It's a placeholder over vnodes, to make working with lifetimes easier
|
||||
pub struct DomTree;
|
||||
|
||||
/// Tools for the base unit of the virtual dom - the VNode
|
||||
/// VNodes are intended to be quickly-allocated, lightweight enum values.
|
||||
///
|
||||
@@ -20,6 +24,7 @@ pub use vtext::VText;
|
||||
mod vnode {
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum VNode<'src> {
|
||||
/// An element node (node type `ELEMENT_NODE`).
|
||||
Element(&'src VElement<'src>),
|
||||
@@ -92,8 +97,9 @@ mod vnode {
|
||||
|
||||
mod velement {
|
||||
use super::*;
|
||||
use std::collections::HashMap;
|
||||
use std::{collections::HashMap, fmt::Debug};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct VElement<'a> {
|
||||
/// Elements have a tag name, zero or more attributes, and zero or more
|
||||
pub key: NodeKey,
|
||||
@@ -186,6 +192,13 @@ mod velement {
|
||||
// /// The callback to invoke when the event happens.
|
||||
pub(crate) callback: &'bump (dyn Fn(())),
|
||||
}
|
||||
impl Debug for Listener<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("Listener")
|
||||
.field("event", &self.event)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// The key for keyed children.
|
||||
///
|
||||
@@ -231,7 +244,7 @@ mod velement {
|
||||
}
|
||||
|
||||
mod vtext {
|
||||
#[derive(PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct VText<'bump> {
|
||||
pub text: &'bump str,
|
||||
}
|
||||
@@ -251,28 +264,30 @@ mod vtext {
|
||||
/// Virtual Components for custom user-defined components
|
||||
/// Only supports the functional syntax
|
||||
mod vcomponent {
|
||||
use crate::innerlude::{Properties, FC};
|
||||
use crate::innerlude::FC;
|
||||
use std::{any::TypeId, fmt, future::Future, marker::PhantomData};
|
||||
|
||||
use super::VNode;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct VComponent<'src> {
|
||||
_p: PhantomData<&'src ()>,
|
||||
props: Box<dyn Properties>,
|
||||
props: Box<dyn std::any::Any>,
|
||||
// props: Box<dyn Properties + 'src>,
|
||||
caller: *const (),
|
||||
}
|
||||
|
||||
impl<'a> VComponent<'a> {
|
||||
pub fn new<P: Properties + 'static>(caller: FC<P>, props: P) -> Self {
|
||||
pub fn new<P>(caller: FC<P>, props: P) -> Self {
|
||||
let caller = caller as *const ();
|
||||
let props = Box::new(props);
|
||||
|
||||
Self {
|
||||
_p: PhantomData {},
|
||||
props,
|
||||
caller,
|
||||
}
|
||||
todo!()
|
||||
// Self {
|
||||
// _p: PhantomData {},
|
||||
// props,
|
||||
// caller,
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
+164
-29
@@ -33,39 +33,39 @@ pub struct Scope {
|
||||
// Map to the parent
|
||||
pub parent: Option<Index>,
|
||||
|
||||
// todo, do better with the active frame stuff
|
||||
// somehow build this vnode with a lifetime tied to self
|
||||
// This root node has "static" lifetime, but it's really not static.
|
||||
// It's goverened by the oldest of the two frames and is switched every time a new render occurs
|
||||
// Use this node as if it were static is unsafe, and needs to be fixed with ourborous or owning ref
|
||||
// ! do not copy this reference are things WILL break !
|
||||
pub frames: ActiveFrame,
|
||||
|
||||
// IE Which listeners need to be woken up?
|
||||
pub listeners: Vec<Box<dyn Fn()>>,
|
||||
|
||||
// lying, cheating reference >:(
|
||||
pub props: Box<dyn std::any::Any>,
|
||||
// pub props: Box<dyn Properties>,
|
||||
|
||||
//
|
||||
pub props_type: TypeId,
|
||||
pub caller: *const i32,
|
||||
// pub props_type: TypeId,
|
||||
pub caller: *const (),
|
||||
}
|
||||
|
||||
impl Scope {
|
||||
// create a new scope from a function
|
||||
pub fn new<T: 'static>(
|
||||
// pub(crate) fn new<T: 'static>(
|
||||
f: FC<T>,
|
||||
props: impl Properties + 'static,
|
||||
pub fn new<'a, P1, P2: 'static>(
|
||||
// pub fn new<'a, P: Properties, PFree: P + 'a, PLocked: P + 'static>(
|
||||
f: FC<P1>,
|
||||
props: P1,
|
||||
parent: Option<Index>,
|
||||
) -> Self {
|
||||
) -> Self
|
||||
// where
|
||||
// PFree: 'a,
|
||||
// PLocked: 'static,
|
||||
{
|
||||
// Capture the props type
|
||||
let props_type = TypeId::of::<T>();
|
||||
// let props_type = TypeId::of::<P>();
|
||||
let hook_arena = typed_arena::Arena::new();
|
||||
let hooks = RefCell::new(Vec::new());
|
||||
|
||||
// Capture the caller
|
||||
let caller = f as *const i32;
|
||||
let caller = f as *const ();
|
||||
|
||||
let listeners = Vec::new();
|
||||
|
||||
@@ -80,12 +80,20 @@ impl Scope {
|
||||
};
|
||||
|
||||
let frames = ActiveFrame::from_frames(old_frame, new_frame);
|
||||
|
||||
// box the props
|
||||
let props = Box::new(props);
|
||||
|
||||
// erase the lifetime
|
||||
// we'll manage this with dom lifecycle
|
||||
|
||||
let props = unsafe { std::mem::transmute::<_, Box<P2>>(props) };
|
||||
|
||||
// todo!()
|
||||
Self {
|
||||
hook_arena,
|
||||
hooks,
|
||||
props_type,
|
||||
// props_type,
|
||||
caller,
|
||||
frames,
|
||||
listeners,
|
||||
@@ -94,13 +102,10 @@ impl Scope {
|
||||
}
|
||||
}
|
||||
|
||||
/// Update this component's props with a new set of props
|
||||
/// Update this component's props with a new set of props, remotely
|
||||
///
|
||||
///
|
||||
pub(crate) fn update_props<P: Properties + Sized + 'static>(
|
||||
&mut self,
|
||||
new_props: Box<P>,
|
||||
) -> crate::error::Result<()> {
|
||||
pub(crate) fn update_props<'a, P>(&self, new_props: P) -> crate::error::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -108,7 +113,7 @@ impl Scope {
|
||||
/// This function downcasts the function pointer based on the stored props_type
|
||||
///
|
||||
/// Props is ?Sized because we borrow the props and don't need to know the size. P (sized) is used as a marker (unsized)
|
||||
pub fn run<'bump, P: Properties + Sized + 'static>(&'bump mut self) {
|
||||
pub fn run<'bump, PLocked: Sized + 'static>(&'bump mut self) {
|
||||
let frame = {
|
||||
let frame = self.frames.next();
|
||||
frame.bump.reset();
|
||||
@@ -123,6 +128,18 @@ impl Scope {
|
||||
_p: PhantomData {},
|
||||
};
|
||||
|
||||
unsafe {
|
||||
// we use plocked to be able to remove the borrowed lifetime
|
||||
// these lifetimes could be very broken, so we need to dynamically manage them
|
||||
let caller = std::mem::transmute::<*const (), FC<PLocked>>(self.caller);
|
||||
let props = self.props.downcast_ref::<PLocked>().unwrap();
|
||||
let nodes: DomTree = caller(ctx, props);
|
||||
todo!("absorb domtree into self")
|
||||
// let nodes: VNode<'bump> = caller(ctx, props);
|
||||
|
||||
// let unsafe_node = std::mem::transmute::<VNode<'bump>, VNode<'static>>(nodes);
|
||||
// frame.head_node = unsafe_node;
|
||||
}
|
||||
/*
|
||||
SAFETY ALERT
|
||||
|
||||
@@ -135,9 +152,6 @@ impl Scope {
|
||||
This is safe because we check that the generic type matches before casting.
|
||||
*/
|
||||
|
||||
let caller = unsafe { std::mem::transmute::<*const i32, FC<P>>(self.caller) };
|
||||
let nodes: VNode<'bump> = caller(ctx, self.props.downcast_ref::<P>().unwrap());
|
||||
|
||||
/*
|
||||
SAFETY ALERT
|
||||
|
||||
@@ -149,9 +163,6 @@ impl Scope {
|
||||
- The VNode has a private API and can only be used from accessors.
|
||||
- Public API cannot drop or destructure VNode
|
||||
*/
|
||||
|
||||
let unsafe_node = unsafe { std::mem::transmute::<VNode<'bump>, VNode<'static>>(nodes) };
|
||||
frame.head_node = unsafe_node;
|
||||
}
|
||||
|
||||
/// Accessor to get the root node and its children (safely)\
|
||||
@@ -159,6 +170,7 @@ impl Scope {
|
||||
pub fn current_root_node<'bump>(&'bump self) -> &'bump VNode<'bump> {
|
||||
self.frames.current_head_node()
|
||||
}
|
||||
|
||||
pub fn prev_root_node<'bump>(&'bump self) -> &'bump VNode<'bump> {
|
||||
todo!()
|
||||
}
|
||||
@@ -169,6 +181,12 @@ pub struct BumpFrame {
|
||||
pub head_node: VNode<'static>,
|
||||
}
|
||||
|
||||
// todo, do better with the active frame stuff
|
||||
// somehow build this vnode with a lifetime tied to self
|
||||
// This root node has "static" lifetime, but it's really not static.
|
||||
// It's goverened by the oldest of the two frames and is switched every time a new render occurs
|
||||
// Use this node as if it were static is unsafe, and needs to be fixed with ourborous or owning ref
|
||||
// ! do not copy this reference are things WILL break !
|
||||
pub struct ActiveFrame {
|
||||
pub idx: AtomicUsize,
|
||||
pub frames: [BumpFrame; 2],
|
||||
@@ -183,7 +201,7 @@ impl ActiveFrame {
|
||||
}
|
||||
|
||||
fn current_head_node<'b>(&'b self) -> &'b VNode<'b> {
|
||||
let cur_idx = self.idx.borrow().load(std::sync::atomic::Ordering::Relaxed);
|
||||
let cur_idx = self.idx.borrow().load(std::sync::atomic::Ordering::Relaxed) % 1;
|
||||
let raw_node = &self.frames[cur_idx];
|
||||
unsafe {
|
||||
let unsafe_head = &raw_node.head_node;
|
||||
@@ -202,3 +220,120 @@ impl ActiveFrame {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_scope() {
|
||||
let example: FC<()> = |ctx, props| {
|
||||
use crate::builder::*;
|
||||
ctx.view(|b| div(b).child(text("a")).finish())
|
||||
};
|
||||
|
||||
let props = ();
|
||||
let parent = None;
|
||||
let scope = Scope::new::<(), ()>(example, props, parent);
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ExampleProps<'src> {
|
||||
name: &'src String,
|
||||
}
|
||||
// impl<'src> Properties<'src> for ExampleProps<'src> {}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct EmptyProps<'src> {
|
||||
name: &'src String,
|
||||
}
|
||||
// impl<'src> Properties<'src> for EmptyProps<'src> {}
|
||||
|
||||
use crate::{builder::*, hooks::use_ref};
|
||||
|
||||
fn example_fc<'a>(ctx: Context<'a>, props: &'a EmptyProps) -> DomTree {
|
||||
// fn example_fc<'a>(ctx: Context<'a>, props: &'a EmptyProps<'a>) -> DomTree {
|
||||
let (content, _): (&'a String, _) = crate::hooks::use_state(&ctx, || "abcd".to_string());
|
||||
// let (content, _): (&'a String, _) = crate::hooks::use_state(&ctx, || "abcd".to_string());
|
||||
// let (text, set_val) = crate::hooks::use_state(&ctx, || "abcd".to_string());
|
||||
|
||||
let childprops: ExampleProps<'a> = ExampleProps { name: content };
|
||||
// let childprops: ExampleProps<'a> = ExampleProps { name: content };
|
||||
ctx.view(move |b: &'a Bump| {
|
||||
div(b)
|
||||
.child(text(props.name))
|
||||
// .child(text(props.name))
|
||||
.child(virtual_child::<ExampleProps>(b, childprops, child_example))
|
||||
// .child(virtual_child::<ExampleProps<'a>>(b, childprops, CHILD))
|
||||
// as for<'scope> fn(Context<'_>, &'scope ExampleProps<'scope>) -> DomTree
|
||||
// |ctx, pops| todo!(),
|
||||
// .child(virtual_child::<'a>(
|
||||
// b,
|
||||
// child_example,
|
||||
// ExampleProps { name: text },
|
||||
// ))
|
||||
.finish()
|
||||
})
|
||||
}
|
||||
|
||||
fn child_example(ctx: Context, props: &ExampleProps) -> DomTree {
|
||||
ctx.view(move |b| {
|
||||
div(b)
|
||||
.child(text(props.name))
|
||||
//
|
||||
.finish()
|
||||
})
|
||||
}
|
||||
|
||||
static CHILD: FC<ExampleProps> = |ctx, props: &'_ ExampleProps| {
|
||||
// todo!()
|
||||
ctx.view(move |b| {
|
||||
div(b)
|
||||
.child(text(props.name))
|
||||
//
|
||||
.finish()
|
||||
})
|
||||
};
|
||||
#[test]
|
||||
fn test_borrowed_scope() {
|
||||
// use crate::builder::*;
|
||||
|
||||
let example: FC<EmptyProps> = |ctx, props| {
|
||||
// render counter
|
||||
// let mut val = crate::hooks::use_ref(&ctx, || 0);
|
||||
// val.modify(|f| {
|
||||
// *f += 1;
|
||||
// });
|
||||
// dbg!(val.current());
|
||||
// only needs to be valid when ran?
|
||||
// can only borrow from parent?
|
||||
// props are boxed in parent's scope?
|
||||
// passing complex structures down to child?
|
||||
// stored value
|
||||
// let (text, set_val) = crate::hooks::use_state(&ctx, || "abcd".to_string());
|
||||
|
||||
ctx.view(move |b| {
|
||||
todo!()
|
||||
// div(b)
|
||||
// // .child(text(props.name))
|
||||
// // .child(virtual_child(b, CHILD, ExampleProps { name: val.as_str() }))
|
||||
// .child(virtual_child(b, CHILD, ExampleProps { name: }))
|
||||
// .finish()
|
||||
})
|
||||
};
|
||||
|
||||
let source_text = "abcd123".to_string();
|
||||
let props = ExampleProps { name: &source_text };
|
||||
|
||||
// let parent = None;
|
||||
// let mut scope =
|
||||
// Scope::new::<EmptyProps, EmptyProps>(example, EmptyProps { name: &() }, parent);
|
||||
// scope.run::<ExampleProps>();
|
||||
// scope.run::<ExampleProps>();
|
||||
// scope.run::<ExampleProps>();
|
||||
// scope.run::<ExampleProps>();
|
||||
// scope.run::<ExampleProps>();
|
||||
// let nodes = scope.current_root_node();
|
||||
// dbg!(nodes);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,9 @@
|
||||
// use crate::{changelist::EditList, nodes::VNode};
|
||||
use crate::{changelist::{self, EditList}, dodriodiff::DiffMachine, nodes::VNode};
|
||||
use crate::{
|
||||
changelist::{self, EditList},
|
||||
dodriodiff::DiffMachine,
|
||||
nodes::VNode,
|
||||
};
|
||||
use crate::{events::EventTrigger, innerlude::*};
|
||||
use any::Any;
|
||||
use bumpalo::Bump;
|
||||
@@ -51,7 +55,7 @@ impl VirtualDom {
|
||||
///
|
||||
/// This is useful when a component tree can be driven by external state (IE SSR) but it would be too expensive
|
||||
/// to toss out the entire tree.
|
||||
pub fn new_with_props<P: Properties + 'static>(root: FC<P>, root_props: P) -> Self {
|
||||
pub fn new_with_props<P: 'static>(root: FC<P>, root_props: P) -> Self {
|
||||
// 1. Create the component arena
|
||||
// 2. Create the base scope (can never be removed)
|
||||
// 3. Create the lifecycle queue
|
||||
@@ -82,7 +86,7 @@ impl VirtualDom {
|
||||
}
|
||||
|
||||
/// With access to the virtual dom, schedule an update to the Root component's props
|
||||
pub fn update_props<P: Properties + 'static>(&mut self, new_props: P) -> Result<()> {
|
||||
pub fn update_props<P: 'static>(&mut self, new_props: P) -> Result<()> {
|
||||
// Ensure the props match
|
||||
if TypeId::of::<P>() != self._root_prop_type {
|
||||
return Err(Error::WrongProps);
|
||||
@@ -262,10 +266,10 @@ pub enum LifecycleType {
|
||||
Mount {
|
||||
to: Option<Index>,
|
||||
under: usize,
|
||||
props: Box<dyn Properties>,
|
||||
props: Box<dyn std::any::Any>,
|
||||
},
|
||||
PropsChanged {
|
||||
props: Box<dyn Properties>,
|
||||
props: Box<dyn std::any::Any>,
|
||||
},
|
||||
Rendered,
|
||||
Mounted,
|
||||
@@ -279,12 +283,7 @@ pub enum LifecycleType {
|
||||
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 {
|
||||
fn mount<P: 'static>(which: Index, to: Option<Index>, under: usize, props: P) -> Self {
|
||||
Self {
|
||||
component_index: which,
|
||||
event_type: LifecycleType::Mount {
|
||||
|
||||
Reference in new issue
Block a user