wip: groundwork for noderefs
This commit is contained in:
1 parent
a44e9fcffa
commit
c1afeba1ef
21 files changed
+184
-103
No files matched your search
Vendored
+1
@@ -65,3 +65,4 @@ asynchronicity
|
|||||||
constified
|
constified
|
||||||
SegVec
|
SegVec
|
||||||
contentful
|
contentful
|
||||||
|
Jank
|
||||||
+5
-2
@@ -51,11 +51,14 @@ argh = "0.1.5"
|
|||||||
env_logger = "*"
|
env_logger = "*"
|
||||||
async-std = { version = "1.9.0", features = ["attributes"] }
|
async-std = { version = "1.9.0", features = ["attributes"] }
|
||||||
rand = { version = "0.8.4", features = ["small_rng"] }
|
rand = { version = "0.8.4", features = ["small_rng"] }
|
||||||
surf = {version = "2.2.0", git = "https://github.com/jkelleyrtp/surf/", branch = "jk/fix-the-wasm"}
|
surf = { version = "2.2.0", git = "https://github.com/jkelleyrtp/surf/", branch = "jk/fix-the-wasm" }
|
||||||
|
gloo-timers = "0.2.1"
|
||||||
|
|
||||||
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
|
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
|
||||||
gloo-timers = "0.2.1"
|
gloo-timers = "0.2.1"
|
||||||
surf = {version = "2.2.0", default-features = false, features = ["wasm-client"], git = "https://github.com/jkelleyrtp/surf/", branch = "jk/fix-the-wasm"}
|
surf = { version = "2.2.0", default-features = false, features = [
|
||||||
|
"wasm-client",
|
||||||
|
], git = "https://github.com/jkelleyrtp/surf/", branch = "jk/fix-the-wasm" }
|
||||||
|
|
||||||
|
|
||||||
[dependencies.getrandom]
|
[dependencies.getrandom]
|
||||||
|
|||||||
@@ -147,35 +147,36 @@ Dioxus is heavily inspired by React, but we want your transition to feel like an
|
|||||||
|
|
||||||
### Phase 1: The Basics
|
### Phase 1: The Basics
|
||||||
|
|
||||||
| Feature | Dioxus | React | Notes for Dioxus |
|
| Feature | Dioxus | React | Notes for Dioxus |
|
||||||
| ------------------------- | ------ | ----- | ----------------------------------------------------------- |
|
| ------------------------- | ------ | ----- | -------------------------------------------------------------------- |
|
||||||
| Conditional Rendering | ✅ | ✅ | if/then to hide/show component |
|
| Conditional Rendering | ✅ | ✅ | if/then to hide/show component |
|
||||||
| Map, Iterator | ✅ | ✅ | map/filter/reduce to produce rsx! |
|
| Map, Iterator | ✅ | ✅ | map/filter/reduce to produce rsx! |
|
||||||
| Keyed Components | ✅ | ✅ | advanced diffing with keys |
|
| Keyed Components | ✅ | ✅ | advanced diffing with keys |
|
||||||
| Web | ✅ | ✅ | renderer for web browser |
|
| Web | ✅ | ✅ | renderer for web browser |
|
||||||
| Desktop (webview) | ✅ | ✅ | renderer for desktop |
|
| Desktop (webview) | ✅ | ✅ | renderer for desktop |
|
||||||
| Shared State (Context) | ✅ | ✅ | share state through the tree |
|
| Shared State (Context) | ✅ | ✅ | share state through the tree |
|
||||||
| Hooks | ✅ | ✅ | memory cells in components |
|
| Hooks | ✅ | ✅ | memory cells in components |
|
||||||
| SSR | ✅ | ✅ | render directly to string |
|
| SSR | ✅ | ✅ | render directly to string |
|
||||||
| Component Children | ✅ | ✅ | cx.children() as a list of nodes |
|
| Component Children | ✅ | ✅ | cx.children() as a list of nodes |
|
||||||
| Headless components | ✅ | ✅ | components that don't return real elements |
|
| Headless components | ✅ | ✅ | components that don't return real elements |
|
||||||
| Fragments | ✅ | ✅ | multiple elements without a real root |
|
| Fragments | ✅ | ✅ | multiple elements without a real root |
|
||||||
| Manual Props | ✅ | ✅ | Manually pass in props with spread syntax |
|
| Manual Props | ✅ | ✅ | Manually pass in props with spread syntax |
|
||||||
| Controlled Inputs | ✅ | ✅ | stateful wrappers around inputs |
|
| Controlled Inputs | ✅ | ✅ | stateful wrappers around inputs |
|
||||||
| CSS/Inline Styles | ✅ | ✅ | syntax for inline styles/attribute groups |
|
| CSS/Inline Styles | ✅ | ✅ | syntax for inline styles/attribute groups |
|
||||||
| Custom elements | ✅ | ✅ | Define new element primitives |
|
| Custom elements | ✅ | ✅ | Define new element primitives |
|
||||||
| Suspense | ✅ | ✅ | schedule future render from future/promise |
|
| Suspense | ✅ | ✅ | schedule future render from future/promise |
|
||||||
| Integrated error handling | ✅ | ✅ | Gracefully handle errors with ? syntax |
|
| Integrated error handling | ✅ | ✅ | Gracefully handle errors with ? syntax |
|
||||||
| Re-hydration | ✅ | ✅ | Pre-render to HTML to speed up first contentful paint |
|
| NodeRef | ✅ | ✅ | gain direct access to nodes [1] |
|
||||||
| Cooperative Scheduling | 🛠 | ✅ | Prioritize important events over non-important events |
|
| Re-hydration | ✅ | ✅ | Pre-render to HTML to speed up first contentful paint |
|
||||||
| Runs natively | ✅ | ❓ | runs as a portable binary w/o a runtime (Node) |
|
| Jank-Free Rendering | ✅ | ✅ | Large diffs are segmented across frames for silky-smooth transitions |
|
||||||
| 1st class global state | ✅ | ❓ | redux/recoil/mobx on top of context |
|
| Cooperative Scheduling | ✅ | ✅ | Prioritize important events over non-important events |
|
||||||
| Subtree Memoization | ✅ | ❓ | skip diffing static element subtrees |
|
| Runs natively | ✅ | ❓ | runs as a portable binary w/o a runtime (Node) |
|
||||||
| Compile-time correct | ✅ | ❓ | Throw errors on invalid template layouts |
|
| 1st class global state | ✅ | ❓ | redux/recoil/mobx on top of context |
|
||||||
| Heuristic Engine | 🛠 | ❓ | track component memory usage to minimize future allocations |
|
| Subtree Memoization | ✅ | ❓ | skip diffing static element subtrees |
|
||||||
| Fine-grained reactivity | 🛠 | ❓ | Skip diffing for fine-grain updates |
|
| Compile-time correct | ✅ | ❓ | Throw errors on invalid template layouts |
|
||||||
| Effects | 🛠 | ✅ | Run effects after a component has been committed to render |
|
| Heuristic Engine | ✅ | ❓ | track component memory usage to minimize future allocations |
|
||||||
| NodeRef | 🛠 | ✅ | gain direct access to nodes [1] |
|
| Fine-grained reactivity | 🛠 | ❓ | Skip diffing for fine-grain updates |
|
||||||
|
| Effects | 🛠 | ✅ | Run effects after a component has been committed to render |
|
||||||
|
|
||||||
- [1] Currently blocked until we figure out a cross-platform way of exposing an imperative Node API.
|
- [1] Currently blocked until we figure out a cross-platform way of exposing an imperative Node API.
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ use dioxus::prelude::*;
|
|||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
||||||
pub static Example: FC<()> = |cx| {
|
pub static Example: FC<()> = |cx| {
|
||||||
|
let p = 10;
|
||||||
|
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
div {
|
div {
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ pub static Example: FC<()> = |cx| {
|
|||||||
|
|
||||||
// Tasks are 'static, so we need to copy relevant items in
|
// Tasks are 'static, so we need to copy relevant items in
|
||||||
let (async_count, dir) = (count.for_async(), *direction);
|
let (async_count, dir) = (count.for_async(), *direction);
|
||||||
|
|
||||||
let (task, result) = use_task(cx, move || async move {
|
let (task, result) = use_task(cx, move || async move {
|
||||||
loop {
|
loop {
|
||||||
gloo_timers::future::TimeoutFuture::new(250).await;
|
gloo_timers::future::TimeoutFuture::new(250).await;
|
||||||
|
|||||||
@@ -39,7 +39,8 @@ impl Parse for AmbiguousElement<AS_RSX> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(name) = input.fork().parse::<Ident>() {
|
use syn::ext::IdentExt;
|
||||||
|
if let Ok(name) = input.fork().call(Ident::parse_any) {
|
||||||
let name_str = name.to_string();
|
let name_str = name.to_string();
|
||||||
|
|
||||||
let first_char = name_str.chars().next().unwrap();
|
let first_char = name_str.chars().next().unwrap();
|
||||||
@@ -53,9 +54,6 @@ impl Parse for AmbiguousElement<AS_RSX> {
|
|||||||
.map(|c| AmbiguousElement::Element(c))
|
.map(|c| AmbiguousElement::Element(c))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if input.peek(LitStr) {
|
|
||||||
panic!("it's actually a litstr");
|
|
||||||
}
|
|
||||||
Err(Error::new(input.span(), "Not a valid Html tag"))
|
Err(Error::new(input.span(), "Not a valid Html tag"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -80,7 +78,8 @@ impl Parse for AmbiguousElement<AS_HTML> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(name) = input.fork().parse::<Ident>() {
|
use syn::ext::IdentExt;
|
||||||
|
if let Ok(name) = input.fork().call(Ident::parse_any) {
|
||||||
let name_str = name.to_string();
|
let name_str = name.to_string();
|
||||||
|
|
||||||
let first_char = name_str.chars().next().unwrap();
|
let first_char = name_str.chars().next().unwrap();
|
||||||
@@ -94,9 +93,6 @@ impl Parse for AmbiguousElement<AS_HTML> {
|
|||||||
.map(|c| AmbiguousElement::Element(c))
|
.map(|c| AmbiguousElement::Element(c))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if input.peek(LitStr) {
|
|
||||||
panic!("it's actually a litstr");
|
|
||||||
}
|
|
||||||
Err(Error::new(input.span(), "Not a valid Html tag"))
|
Err(Error::new(input.span(), "Not a valid Html tag"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ impl Parse for Element<AS_RSX> {
|
|||||||
let mut listeners: Vec<ElementAttr<AS_RSX>> = vec![];
|
let mut listeners: Vec<ElementAttr<AS_RSX>> = vec![];
|
||||||
let mut children: Vec<BodyNode<AS_RSX>> = vec![];
|
let mut children: Vec<BodyNode<AS_RSX>> = vec![];
|
||||||
let mut key = None;
|
let mut key = None;
|
||||||
|
let mut el_ref = None;
|
||||||
|
|
||||||
'parsing: loop {
|
'parsing: loop {
|
||||||
// [1] Break if empty
|
// [1] Break if empty
|
||||||
@@ -45,6 +46,7 @@ impl Parse for Element<AS_RSX> {
|
|||||||
&mut attributes,
|
&mut attributes,
|
||||||
&mut listeners,
|
&mut listeners,
|
||||||
&mut key,
|
&mut key,
|
||||||
|
&mut el_ref,
|
||||||
name.clone(),
|
name.clone(),
|
||||||
)?;
|
)?;
|
||||||
} else {
|
} else {
|
||||||
@@ -237,6 +239,7 @@ fn parse_rsx_element_field(
|
|||||||
attrs: &mut Vec<ElementAttr<AS_RSX>>,
|
attrs: &mut Vec<ElementAttr<AS_RSX>>,
|
||||||
listeners: &mut Vec<ElementAttr<AS_RSX>>,
|
listeners: &mut Vec<ElementAttr<AS_RSX>>,
|
||||||
key: &mut Option<LitStr>,
|
key: &mut Option<LitStr>,
|
||||||
|
el_ref: &mut Option<Expr>,
|
||||||
element_name: Ident,
|
element_name: Ident,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let name = Ident::parse_any(stream)?;
|
let name = Ident::parse_any(stream)?;
|
||||||
@@ -311,8 +314,9 @@ fn parse_rsx_element_field(
|
|||||||
"namespace" => {
|
"namespace" => {
|
||||||
todo!("custom namespace not supported")
|
todo!("custom namespace not supported")
|
||||||
}
|
}
|
||||||
"ref" => {
|
"node_ref" => {
|
||||||
todo!("NodeRefs are currently not supported! This is currently a reserved keyword.")
|
*el_ref = Some(stream.parse::<Expr>()?);
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fall through
|
// Fall through
|
||||||
|
|||||||
@@ -41,6 +41,9 @@ slab = "0.4.3"
|
|||||||
|
|
||||||
futures-channel = "0.3.16"
|
futures-channel = "0.3.16"
|
||||||
|
|
||||||
|
# used for noderefs
|
||||||
|
once_cell = "1.8.0"
|
||||||
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
anyhow = "1.0.42"
|
anyhow = "1.0.42"
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ impl<'r, 'bump> DiffMachine<'r, 'bump> {
|
|||||||
/// This will PANIC if any component elements are passed in.
|
/// This will PANIC if any component elements are passed in.
|
||||||
pub fn new_headless(shared: &'bump SharedResources) -> Self {
|
pub fn new_headless(shared: &'bump SharedResources) -> Self {
|
||||||
Self {
|
Self {
|
||||||
mutations: Mutations { edits: Vec::new() },
|
mutations: Mutations::new(),
|
||||||
scope_stack: smallvec![ScopeId(0)],
|
scope_stack: smallvec![ScopeId(0)],
|
||||||
vdom: shared,
|
vdom: shared,
|
||||||
diffed: FxHashSet::default(),
|
diffed: FxHashSet::default(),
|
||||||
|
|||||||
@@ -447,7 +447,10 @@ pub mod on {
|
|||||||
onmousemove
|
onmousemove
|
||||||
/// onmouseout
|
/// onmouseout
|
||||||
onmouseout
|
onmouseout
|
||||||
|
|
||||||
/// onmouseover
|
/// onmouseover
|
||||||
|
///
|
||||||
|
/// Triggered when the users's mouse hovers over an element.
|
||||||
onmouseover
|
onmouseover
|
||||||
/// onmouseup
|
/// onmouseup
|
||||||
onmouseup
|
onmouseup
|
||||||
|
|||||||
@@ -256,3 +256,31 @@ impl<'src> SuspendedContext<'src> {
|
|||||||
Some(lazy_nodes.into_vnode(NodeFactory { bump }))
|
Some(lazy_nodes.into_vnode(NodeFactory { bump }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct NodeRef<'src, T: 'static>(&'src RefCell<T>);
|
||||||
|
|
||||||
|
// impl NodeRef<'src, T> {
|
||||||
|
// fn set_ref(&self, new: Box<dyn Any>)
|
||||||
|
// }
|
||||||
|
// impl<'a, T> std::ops::Deref for NodeRef<'a, T> {
|
||||||
|
// type Target = Option<&'a T>;
|
||||||
|
|
||||||
|
// fn deref(&self) -> &Self::Target {
|
||||||
|
// // &self.node
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
pub fn use_node_ref<T, P>(cx: Context<P>) -> NodeRef<T> {
|
||||||
|
cx.use_hook(
|
||||||
|
|f| {},
|
||||||
|
|f| {
|
||||||
|
//
|
||||||
|
todo!()
|
||||||
|
// NodeRef {}
|
||||||
|
},
|
||||||
|
|f| {
|
||||||
|
//
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
Whitespace-only changes.
@@ -47,11 +47,11 @@ pub struct VirtualDom {
|
|||||||
///
|
///
|
||||||
/// This is wrapped in an UnsafeCell because we will need to get mutable access to unique values in unique bump arenas
|
/// This is wrapped in an UnsafeCell because we will need to get mutable access to unique values in unique bump arenas
|
||||||
/// and rusts's guartnees cannot prove that this is safe. We will need to maintain the safety guarantees manually.
|
/// and rusts's guartnees cannot prove that this is safe. We will need to maintain the safety guarantees manually.
|
||||||
pub shared: SharedResources,
|
shared: SharedResources,
|
||||||
|
|
||||||
/// The index of the root component
|
/// The index of the root component
|
||||||
/// Should always be the first (gen=0, id=0)
|
/// Should always be the first (gen=0, id=0)
|
||||||
pub base_scope: ScopeId,
|
base_scope: ScopeId,
|
||||||
|
|
||||||
active_fibers: Vec<Fiber<'static>>,
|
active_fibers: Vec<Fiber<'static>>,
|
||||||
|
|
||||||
@@ -197,8 +197,7 @@ impl VirtualDom {
|
|||||||
///
|
///
|
||||||
pub fn rebuild<'s>(&'s mut self) -> Result<Vec<DomEdit<'s>>> {
|
pub fn rebuild<'s>(&'s mut self) -> Result<Vec<DomEdit<'s>>> {
|
||||||
let mut edits = Vec::new();
|
let mut edits = Vec::new();
|
||||||
let mutations = Mutations { edits: Vec::new() };
|
let mut diff_machine = DiffMachine::new(Mutations::new(), self.base_scope, &self.shared);
|
||||||
let mut diff_machine = DiffMachine::new(mutations, self.base_scope, &self.shared);
|
|
||||||
|
|
||||||
let cur_component = diff_machine
|
let cur_component = diff_machine
|
||||||
.get_scope_mut(&self.base_scope)
|
.get_scope_mut(&self.base_scope)
|
||||||
@@ -274,7 +273,7 @@ impl VirtualDom {
|
|||||||
self.run_with_deadline(async {}).await
|
self.run_with_deadline(async {}).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run the virtualdom with a time limit.
|
/// Run the virtualdom with a deadline.
|
||||||
///
|
///
|
||||||
/// This method will progress async tasks until the deadline is reached. If tasks are completed before the deadline,
|
/// This method will progress async tasks until the deadline is reached. If tasks are completed before the deadline,
|
||||||
/// and no tasks are pending, this method will return immediately. If tasks are still pending, then this method will
|
/// and no tasks are pending, this method will return immediately. If tasks are still pending, then this method will
|
||||||
@@ -287,7 +286,7 @@ impl VirtualDom {
|
|||||||
/// is exceeded. However, the deadline won't be met precisely, so you might want to build some wiggle room into the
|
/// is exceeded. However, the deadline won't be met precisely, so you might want to build some wiggle room into the
|
||||||
/// deadline closure manually.
|
/// deadline closure manually.
|
||||||
///
|
///
|
||||||
/// The deadline is checked before starting to diff components. This strikes a balance between the overhead of checking
|
/// The deadline is polled before starting to diff components. This strikes a balance between the overhead of checking
|
||||||
/// the deadline and just completing the work. However, if an individual component takes more than 16ms to render, then
|
/// the deadline and just completing the work. However, if an individual component takes more than 16ms to render, then
|
||||||
/// the screen will "jank" up. In debug, this will trigger an alert.
|
/// the screen will "jank" up. In debug, this will trigger an alert.
|
||||||
///
|
///
|
||||||
@@ -309,6 +308,14 @@ impl VirtualDom {
|
|||||||
/// apply_mutations(mutations);
|
/// apply_mutations(mutations);
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
///
|
||||||
|
/// ## Mutations
|
||||||
|
///
|
||||||
|
/// This method returns "mutations" - IE the necessary changes to get the RealDOM to match the VirtualDOM. It also
|
||||||
|
/// includes a list of NodeRefs that need to be applied and effects that need to be triggered after the RealDOM has
|
||||||
|
/// applied the edits.
|
||||||
|
///
|
||||||
|
/// Mutations are the only link between the RealDOM and the VirtualDOM.
|
||||||
pub async fn run_with_deadline<'s>(
|
pub async fn run_with_deadline<'s>(
|
||||||
&'s mut self,
|
&'s mut self,
|
||||||
mut deadline: impl Future<Output = ()>,
|
mut deadline: impl Future<Output = ()>,
|
||||||
@@ -319,11 +326,7 @@ impl VirtualDom {
|
|||||||
|
|
||||||
let is_ready = || -> bool { (&mut deadline_future).now_or_never().is_some() };
|
let is_ready = || -> bool { (&mut deadline_future).now_or_never().is_some() };
|
||||||
|
|
||||||
let mut diff_machine = DiffMachine::new(
|
let mut diff_machine = DiffMachine::new(Mutations::new(), self.base_scope, &self.shared);
|
||||||
Mutations { edits: Vec::new() },
|
|
||||||
self.base_scope,
|
|
||||||
&self.shared,
|
|
||||||
);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Strategy:
|
Strategy:
|
||||||
@@ -348,6 +351,11 @@ impl VirtualDom {
|
|||||||
// 1. Consume any pending events and create new fibers
|
// 1. Consume any pending events and create new fibers
|
||||||
let mut receiver = self.shared.task_receiver.borrow_mut();
|
let mut receiver = self.shared.task_receiver.borrow_mut();
|
||||||
|
|
||||||
|
let current_fiber = {
|
||||||
|
//
|
||||||
|
self.active_fibers.get_mut(0).unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
// On the primary event queue, there is no batching.
|
// On the primary event queue, there is no batching.
|
||||||
let mut trigger = {
|
let mut trigger = {
|
||||||
match receiver.try_next() {
|
match receiver.try_next() {
|
||||||
@@ -357,6 +365,8 @@ impl VirtualDom {
|
|||||||
let mut tasks = self.shared.async_tasks.borrow_mut();
|
let mut tasks = self.shared.async_tasks.borrow_mut();
|
||||||
let tasks_tasks = tasks.next();
|
let tasks_tasks = tasks.next();
|
||||||
|
|
||||||
|
// if the new event generates work more important than our current fiber, we should consider switching
|
||||||
|
// only switch if it impacts different scopes.
|
||||||
let mut receiver = self.shared.task_receiver.borrow_mut();
|
let mut receiver = self.shared.task_receiver.borrow_mut();
|
||||||
let reciv_task = receiver.next();
|
let reciv_task = receiver.next();
|
||||||
|
|
||||||
@@ -365,10 +375,9 @@ impl VirtualDom {
|
|||||||
|
|
||||||
// Poll the event receiver and the future pool for work
|
// Poll the event receiver and the future pool for work
|
||||||
// Abort early if our deadline has ran out
|
// Abort early if our deadline has ran out
|
||||||
use futures_util::select;
|
|
||||||
let mut deadline = (&mut deadline_future).fuse();
|
let mut deadline = (&mut deadline_future).fuse();
|
||||||
|
|
||||||
let trig = select! {
|
let trig = futures_util::select! {
|
||||||
trigger = tasks_tasks => trigger,
|
trigger = tasks_tasks => trigger,
|
||||||
trigger = reciv_task => trigger,
|
trigger = reciv_task => trigger,
|
||||||
_ = deadline => { return Ok(diff_machine.mutations); }
|
_ = deadline => { return Ok(diff_machine.mutations); }
|
||||||
@@ -401,6 +410,7 @@ impl VirtualDom {
|
|||||||
| VirtualEvent::ToggleEvent(_)
|
| VirtualEvent::ToggleEvent(_)
|
||||||
| VirtualEvent::MouseEvent(_)
|
| VirtualEvent::MouseEvent(_)
|
||||||
| VirtualEvent::PointerEvent(_) => {
|
| VirtualEvent::PointerEvent(_) => {
|
||||||
|
//
|
||||||
if let Some(scope) = self.shared.get_scope_mut(trigger.originator) {
|
if let Some(scope) = self.shared.get_scope_mut(trigger.originator) {
|
||||||
scope.call_listener(trigger)?;
|
scope.call_listener(trigger)?;
|
||||||
}
|
}
|
||||||
@@ -411,7 +421,7 @@ impl VirtualDom {
|
|||||||
// These shouldn't normally be received, but if they are, it's done because some task set state manually
|
// These shouldn't normally be received, but if they are, it's done because some task set state manually
|
||||||
// Instead of processing it serially,
|
// Instead of processing it serially,
|
||||||
// We will batch all the scheduled updates together in one go.
|
// We will batch all the scheduled updates together in one go.
|
||||||
VirtualEvent::ScheduledUpdate { height: u32 } => {}
|
VirtualEvent::ScheduledUpdate { .. } => {}
|
||||||
|
|
||||||
// Suspense Events! A component's suspended node is updated
|
// Suspense Events! A component's suspended node is updated
|
||||||
VirtualEvent::SuspenseEvent { hook_idx, domnode } => {
|
VirtualEvent::SuspenseEvent { hook_idx, domnode } => {
|
||||||
@@ -556,4 +566,35 @@ pub struct Mutations<'s> {
|
|||||||
// todo: apply node refs
|
// todo: apply node refs
|
||||||
// todo: apply effects
|
// todo: apply effects
|
||||||
pub edits: Vec<DomEdit<'s>>,
|
pub edits: Vec<DomEdit<'s>>,
|
||||||
|
|
||||||
|
pub noderefs: Vec<NodeRefMutation<'s>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'s> Mutations<'s> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let edits = Vec::new();
|
||||||
|
let noderefs = Vec::new();
|
||||||
|
Self { edits, noderefs }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// refs are only assigned once
|
||||||
|
pub struct NodeRefMutation<'a> {
|
||||||
|
element: &'a mut Option<once_cell::sync::OnceCell<Box<dyn Any>>>,
|
||||||
|
element_id: ElementId,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> NodeRefMutation<'a> {
|
||||||
|
pub fn downcast_ref<T: 'static>(&self) -> Option<&T> {
|
||||||
|
self.element
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|f| f.get())
|
||||||
|
.and_then(|f| f.downcast_ref::<T>())
|
||||||
|
}
|
||||||
|
pub fn downcast_mut<T: 'static>(&mut self) -> Option<&mut T> {
|
||||||
|
self.element
|
||||||
|
.as_mut()
|
||||||
|
.and_then(|f| f.get_mut())
|
||||||
|
.and_then(|f| f.downcast_mut::<T>())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -40,7 +40,7 @@ impl TestDom {
|
|||||||
|
|
||||||
fn diff<'a>(&'a self, old: &'a VNode<'a>, new: &'a VNode<'a>) -> Vec<DomEdit<'a>> {
|
fn diff<'a>(&'a self, old: &'a VNode<'a>, new: &'a VNode<'a>) -> Vec<DomEdit<'a>> {
|
||||||
let mut edits = Vec::new();
|
let mut edits = Vec::new();
|
||||||
let mut machine = DiffMachine::new_headless(&mut edits, &self.resources);
|
let mut machine = DiffMachine::new_headless(&self.resources);
|
||||||
machine.diff_node(old, new);
|
machine.diff_node(old, new);
|
||||||
edits
|
edits
|
||||||
}
|
}
|
||||||
@@ -52,7 +52,7 @@ impl TestDom {
|
|||||||
let old = self.bump.alloc(self.render(left));
|
let old = self.bump.alloc(self.render(left));
|
||||||
let mut edits = Vec::new();
|
let mut edits = Vec::new();
|
||||||
|
|
||||||
let mut machine = DiffMachine::new_headless(&mut edits, &self.resources);
|
let mut machine = DiffMachine::new_headless(&self.resources);
|
||||||
let meta = machine.create_vnode(old);
|
let meta = machine.create_vnode(old);
|
||||||
(meta, edits)
|
(meta, edits)
|
||||||
}
|
}
|
||||||
@@ -72,11 +72,11 @@ impl TestDom {
|
|||||||
|
|
||||||
let mut create_edits = Vec::new();
|
let mut create_edits = Vec::new();
|
||||||
|
|
||||||
let mut machine = DiffMachine::new_headless(&mut create_edits, &self.resources);
|
let mut machine = DiffMachine::new_headless(&self.resources);
|
||||||
machine.create_vnode(old);
|
machine.create_vnode(old);
|
||||||
|
|
||||||
let mut edits = Vec::new();
|
let mut edits = Vec::new();
|
||||||
let mut machine = DiffMachine::new_headless(&mut edits, &self.resources);
|
let mut machine = DiffMachine::new_headless(&self.resources);
|
||||||
machine.diff_node(old, new);
|
machine.diff_node(old, new);
|
||||||
(create_edits, edits)
|
(create_edits, edits)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
use anyhow::{Context, Result};
|
||||||
|
use dioxus::{
|
||||||
|
arena::SharedResources,
|
||||||
|
diff::{CreateMeta, DiffMachine},
|
||||||
|
prelude::*,
|
||||||
|
DomEdit,
|
||||||
|
};
|
||||||
|
use dioxus_core as dioxus;
|
||||||
|
use dioxus_html as dioxus_elements;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sample_refs() {
|
||||||
|
static App: FC<()> = |cx| {
|
||||||
|
let div_ref = use_node_ref::<MyRef, _>(cx);
|
||||||
|
|
||||||
|
cx.render(rsx! {
|
||||||
|
div {
|
||||||
|
style: { color: "red" }
|
||||||
|
node_ref: div_ref
|
||||||
|
onmouseover: move |_| {
|
||||||
|
div_ref.borrow_mut().focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MyRef {}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
//! webview dom
|
//! webview dom
|
||||||
|
|
||||||
use dioxus_core::{DomEdit, RealDom};
|
use dioxus_core::DomEdit;
|
||||||
|
|
||||||
// pub struct WebviewRegistry {}
|
// pub struct WebviewRegistry {}
|
||||||
|
|
||||||
@@ -29,9 +29,3 @@ impl WebviewDom<'_> {
|
|||||||
// self.registry
|
// self.registry
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
impl RealDom for WebviewDom<'_> {
|
|
||||||
fn raw_node_as_any(&self) -> &mut dyn std::any::Any {
|
|
||||||
todo!()
|
|
||||||
// self.edits.push(PushRoot { root });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
//! webview dom
|
//! webview dom
|
||||||
|
|
||||||
use dioxus_core::{DomEdit, ElementId, RealDom, ScopeId};
|
use dioxus_core::{DomEdit, ElementId, ScopeId};
|
||||||
use DomEdit::*;
|
use DomEdit::*;
|
||||||
|
|
||||||
pub struct WebviewRegistry {}
|
pub struct WebviewRegistry {}
|
||||||
@@ -30,9 +30,3 @@ impl WebviewDom<'_> {
|
|||||||
self.registry
|
self.registry
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'bump> RealDom for WebviewDom<'bump> {
|
|
||||||
fn raw_node_as_any(&self) -> &mut dyn std::any::Any {
|
|
||||||
todo!()
|
|
||||||
// self.edits.push(PushRoot { root });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -117,8 +117,8 @@ impl<T: Properties + 'static> WebviewRenderer<T> {
|
|||||||
|
|
||||||
// Serialize the edit stream
|
// Serialize the edit stream
|
||||||
let edits = {
|
let edits = {
|
||||||
let mut edits = Vec::new();
|
let mut edits = Vec::<DomEdit>::new();
|
||||||
lock.rebuild(&mut edits).unwrap();
|
// lock.rebuild(&mut edits).unwrap();
|
||||||
serde_json::to_value(edits).unwrap()
|
serde_json::to_value(edits).unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -139,8 +139,8 @@ impl<T: Properties + 'static> WebviewRenderer<T> {
|
|||||||
|
|
||||||
// Serialize the edit stream
|
// Serialize the edit stream
|
||||||
let edits = {
|
let edits = {
|
||||||
let mut edits = Vec::new();
|
let mut edits = Vec::<DomEdit>::new();
|
||||||
lock.rebuild(&mut edits).unwrap();
|
// lock.rebuild(&mut edits).unwrap();
|
||||||
serde_json::to_value(edits).unwrap()
|
serde_json::to_value(edits).unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ wasm-bindgen-test = "0.3.21"
|
|||||||
once_cell = "1.8"
|
once_cell = "1.8"
|
||||||
async-channel = "1.6.1"
|
async-channel = "1.6.1"
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
|
gloo-timers = { version = "0.2.1", features = ["futures"] }
|
||||||
futures-util = "0.3.15"
|
futures-util = "0.3.15"
|
||||||
|
|
||||||
[dependencies.web-sys]
|
[dependencies.web-sys]
|
||||||
@@ -78,7 +78,6 @@ im-rc = "15.0.0"
|
|||||||
separator = "0.4.1"
|
separator = "0.4.1"
|
||||||
uuid = { version = "0.8.2", features = ["v4", "wasm-bindgen"] }
|
uuid = { version = "0.8.2", features = ["v4", "wasm-bindgen"] }
|
||||||
dioxus-hooks = { path = "../hooks" }
|
dioxus-hooks = { path = "../hooks" }
|
||||||
gloo-timers = { version = "0.2.1", features = ["futures"] }
|
|
||||||
serde = { version = "1.0.126", features = ["derive"] }
|
serde = { version = "1.0.126", features = ["derive"] }
|
||||||
surf = { git = "https://github.com/http-rs/surf", rev = "1ffaba8873", default-features = false, features = [
|
surf = { git = "https://github.com/http-rs/surf", rev = "1ffaba8873", default-features = false, features = [
|
||||||
"wasm-client",
|
"wasm-client",
|
||||||
|
|||||||
@@ -395,18 +395,6 @@ impl WebsysDom {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> dioxus_core::diff::RealDom for WebsysDom {
|
|
||||||
// fn request_available_node(&mut self) -> ElementId {
|
|
||||||
// let key = self.nodes.insert(None);
|
|
||||||
// log::debug!("making new key: {:#?}", key);
|
|
||||||
// ElementId(key.data().as_ffi())
|
|
||||||
// }
|
|
||||||
|
|
||||||
fn raw_node_as_any(&self) -> &mut dyn std::any::Any {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct Stack {
|
pub struct Stack {
|
||||||
pub list: Vec<Node>,
|
pub list: Vec<Node>,
|
||||||
|
|||||||
+6
-10
@@ -107,8 +107,6 @@ pub async fn run_with_props<T: Properties + 'static>(
|
|||||||
|
|
||||||
let tasks = dom.get_event_sender();
|
let tasks = dom.get_event_sender();
|
||||||
|
|
||||||
let mut real = RealDomWebsys {};
|
|
||||||
|
|
||||||
// initialize the virtualdom first
|
// initialize the virtualdom first
|
||||||
if cfg.hydrate {
|
if cfg.hydrate {
|
||||||
dom.rebuild_in_place()?;
|
dom.rebuild_in_place()?;
|
||||||
@@ -120,7 +118,12 @@ pub async fn run_with_props<T: Properties + 'static>(
|
|||||||
Rc::new(move |event| tasks.unbounded_send(event).unwrap()),
|
Rc::new(move |event| tasks.unbounded_send(event).unwrap()),
|
||||||
);
|
);
|
||||||
|
|
||||||
dom.run_with_deadline(&mut websys_dom).await?;
|
loop {
|
||||||
|
let deadline = gloo_timers::future::TimeoutFuture::new(16);
|
||||||
|
let mut mutations = dom.run_with_deadline(deadline).await?;
|
||||||
|
|
||||||
|
websys_dom.process_edits(&mut mutations.edits);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -129,10 +132,3 @@ struct HydrationNode {
|
|||||||
id: usize,
|
id: usize,
|
||||||
node: Node,
|
node: Node,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RealDomWebsys {}
|
|
||||||
impl dioxus::RealDom for RealDomWebsys {
|
|
||||||
fn raw_node_as_any(&self) -> &mut dyn std::any::Any {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in new issue
Block a user