WIP fix event bubbling

This commit is contained in:
Evan Almloff committed 2023-08-23 13:01:37 -05:00
1 parent e337aff0a4
commit dc4707ee2a
6 files changed
+161 -94

No files matched your search

+12 -27
View File
@@ -1,5 +1,3 @@
use std::ptr::NonNull;
use crate::{ use crate::{
innerlude::DirtyScope, nodes::RenderReturn, nodes::VNode, virtual_dom::VirtualDom, innerlude::DirtyScope, nodes::RenderReturn, nodes::VNode, virtual_dom::VirtualDom,
AttributeValue, DynamicNode, ScopeId, AttributeValue, DynamicNode, ScopeId,
@@ -21,13 +19,13 @@ pub struct ElementId(pub usize);
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct BubbleId(pub usize); pub struct BubbleId(pub usize);
#[derive(Debug, Clone)] #[derive(Debug, Clone, Copy)]
pub struct ElementRef { pub struct ElementRef<'a> {
// the pathway of the real element inside the template // the pathway of the real element inside the template
pub(crate) path: ElementPath, pub(crate) path: ElementPath,
// The actual template // The actual template
pub(crate) template: NonNull<VNode<'static>>, pub(crate) template: &'a VNode<'a>,
// The scope the element belongs to // The scope the element belongs to
pub(crate) scope: ScopeId, pub(crate) scope: ScopeId,
@@ -35,7 +33,7 @@ pub struct ElementRef {
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct ElementPath { pub struct ElementPath {
path: &'static [u8], pub(crate) path: &'static [u8],
} }
impl VirtualDom { impl VirtualDom {
@@ -43,22 +41,11 @@ impl VirtualDom {
ElementId(self.elements.insert(None)) ElementId(self.elements.insert(None))
} }
pub(crate) fn next_element_ref(&mut self, template: &VNode, path: &'static [u8]) -> BubbleId { pub(crate) fn next_element_ref(&mut self, element_ref: ElementRef) -> BubbleId {
self.next_reference(template, ElementPath { path }) BubbleId(
} self.element_refs
.insert(unsafe { std::mem::transmute(element_ref) }),
fn next_reference(&mut self, template: &VNode, path: ElementPath) -> BubbleId { )
let entry = self.element_refs.vacant_entry();
let id = entry.key();
let scope = self.runtime.current_scope_id().unwrap_or(ScopeId(0));
entry.insert(ElementRef {
// We know this is non-null because it comes from a reference
template: unsafe { NonNull::new_unchecked(template as *const _ as *mut _) },
path,
scope,
});
BubbleId(id)
} }
pub(crate) fn reclaim(&mut self, el: ElementId) { pub(crate) fn reclaim(&mut self, el: ElementId) {
@@ -77,15 +64,13 @@ impl VirtualDom {
self.elements.try_remove(el.0).map(|_| ()) self.elements.try_remove(el.0).map(|_| ())
} }
pub(crate) fn set_template(&mut self, el: ElementId, node: &VNode, path: &'static [u8]) { pub(crate) fn set_template(&mut self, el: ElementId, element_ref: ElementRef) {
match self.elements[el.0] { match self.elements[el.0] {
Some(bubble_id) => { Some(bubble_id) => {
self.element_refs[bubble_id.0].path = ElementPath { path }; self.element_refs[bubble_id.0] = unsafe { std::mem::transmute(element_ref) };
self.element_refs[bubble_id.0].template =
unsafe { NonNull::new_unchecked(node as *const _ as *mut _) };
} }
None => { None => {
self.elements[el.0] = Some(self.next_reference(node, ElementPath { path })); self.elements[el.0] = Some(self.next_element_ref(element_ref));
} }
} }
} }
+32 -12
View File
@@ -1,6 +1,7 @@
use crate::any_props::AnyProps; use crate::any_props::AnyProps;
use crate::diff::BoundaryRef; use crate::innerlude::{
use crate::innerlude::{BorrowedAttributeValue, VComponent, VPlaceholder, VText}; BorrowedAttributeValue, ElementPath, ElementRef, VComponent, VPlaceholder, VText,
};
use crate::mutations::Mutation; use crate::mutations::Mutation;
use crate::mutations::Mutation::*; use crate::mutations::Mutation::*;
use crate::nodes::VNode; use crate::nodes::VNode;
@@ -182,7 +183,14 @@ impl<'b> VirtualDom {
use DynamicNode::*; use DynamicNode::*;
match &template.dynamic_nodes[idx] { match &template.dynamic_nodes[idx] {
node @ Component { .. } | node @ Fragment(_) => { node @ Component { .. } | node @ Fragment(_) => {
self.create_dynamic_node(template, idx, node, idx) let template_ref = ElementRef {
path: ElementPath {
path: &template.template.get().node_paths[idx],
},
template: &template,
scope: self.runtime.current_scope_id().unwrap_or(ScopeId(0)),
};
self.create_dynamic_node(template_ref, node)
} }
Placeholder(VPlaceholder { id }) => { Placeholder(VPlaceholder { id }) => {
let id = self.set_slot(id); let id = self.set_slot(id);
@@ -266,7 +274,14 @@ impl<'b> VirtualDom {
.map(|sorted_index| dynamic_nodes[sorted_index].0); .map(|sorted_index| dynamic_nodes[sorted_index].0);
for idx in reversed_iter { for idx in reversed_iter {
let m = self.create_dynamic_node(template, idx, &template.dynamic_nodes[idx], idx); let boundary_ref = ElementRef {
path: ElementPath {
path: &template.template.get().node_paths[idx],
},
template,
scope: self.runtime.current_scope_id().unwrap_or(ScopeId(0)),
};
let m = self.create_dynamic_node(boundary_ref, &template.dynamic_nodes[idx]);
if m > 0 { if m > 0 {
// The path is one shorter because the top node is the root // The path is one shorter because the top node is the root
let path = &template.template.get().node_paths[idx][1..]; let path = &template.template.get().node_paths[idx][1..];
@@ -315,7 +330,12 @@ impl<'b> VirtualDom {
match &attribute.value { match &attribute.value {
AttributeValue::Listener(_) => { AttributeValue::Listener(_) => {
let path = &template.template.get().attr_paths[idx]; let path = &template.template.get().attr_paths[idx];
self.set_template(id, template, path); let element_ref = ElementRef {
path: ElementPath { path },
template,
scope: self.runtime.current_scope_id().unwrap_or(ScopeId(0)),
};
self.set_template(id, element_ref);
self.mutations.push(NewEventListener { self.mutations.push(NewEventListener {
// all listeners start with "on" // all listeners start with "on"
name: &unbounded_name[2..], name: &unbounded_name[2..],
@@ -446,19 +466,19 @@ impl<'b> VirtualDom {
pub(crate) fn create_dynamic_node( pub(crate) fn create_dynamic_node(
&mut self, &mut self,
parent: BoundaryRef<'b>, parent: ElementRef<'b>,
node: &'b DynamicNode<'b>, node: &'b DynamicNode<'b>,
) -> usize { ) -> usize {
use DynamicNode::*; use DynamicNode::*;
match node { match node {
Text(text) => self.create_dynamic_text(parent, text), Text(text) => self.create_dynamic_text(parent, text),
Placeholder(place) => self.create_placeholder(place, parent), Placeholder(place) => self.create_placeholder(place, parent),
Component(component) => self.create_component_node(parent, component), Component(component) => self.create_component_node(Some(parent), component),
Fragment(frag) => frag.iter().map(|child| self.create(child)).sum(), Fragment(frag) => frag.iter().map(|child| self.create(child)).sum(),
} }
} }
fn create_dynamic_text(&mut self, parent: BoundaryRef<'b>, text: &'b VText<'b>) -> usize { fn create_dynamic_text(&mut self, parent: ElementRef<'b>, text: &'b VText<'b>) -> usize {
// Allocate a dynamic element reference for this text node // Allocate a dynamic element reference for this text node
let new_id = self.next_element(); let new_id = self.next_element();
@@ -471,7 +491,7 @@ impl<'b> VirtualDom {
// Add the mutation to the list // Add the mutation to the list
self.mutations.push(HydrateText { self.mutations.push(HydrateText {
id: new_id, id: new_id,
path: &parent.parent.template.get().node_paths[parent.dyn_node_idx][1..], path: &parent.path.path[1..],
value, value,
}); });
@@ -482,7 +502,7 @@ impl<'b> VirtualDom {
pub(crate) fn create_placeholder( pub(crate) fn create_placeholder(
&mut self, &mut self,
placeholder: &VPlaceholder, placeholder: &VPlaceholder,
parent: BoundaryRef<'b>, parent: ElementRef<'b>,
) -> usize { ) -> usize {
// Allocate a dynamic element reference for this text node // Allocate a dynamic element reference for this text node
let id = self.next_element(); let id = self.next_element();
@@ -492,7 +512,7 @@ impl<'b> VirtualDom {
// Assign the ID to the existing node in the template // Assign the ID to the existing node in the template
self.mutations.push(AssignId { self.mutations.push(AssignId {
path: &parent.parent.template.get().node_paths[parent.dyn_node_idx][1..], path: &parent.path.path[1..],
id, id,
}); });
@@ -502,7 +522,7 @@ impl<'b> VirtualDom {
pub(super) fn create_component_node( pub(super) fn create_component_node(
&mut self, &mut self,
parent: BoundaryRef<'b>, parent: Option<ElementRef<'b>>,
component: &'b VComponent<'b>, component: &'b VComponent<'b>,
) -> usize { ) -> usize {
use RenderReturn::*; use RenderReturn::*;
+51 -48
View File
@@ -1,7 +1,10 @@
use crate::{ use crate::{
any_props::AnyProps, any_props::AnyProps,
arena::ElementId, arena::ElementId,
innerlude::{BorrowedAttributeValue, DirtyScope, VComponent, VPlaceholder, VText}, innerlude::{
BorrowedAttributeValue, DirtyScope, ElementPath, ElementRef, VComponent, VPlaceholder,
VText,
},
mutations::Mutation, mutations::Mutation,
nodes::RenderReturn, nodes::RenderReturn,
nodes::{DynamicNode, VNode}, nodes::{DynamicNode, VNode},
@@ -81,7 +84,10 @@ impl<'b> VirtualDom {
if let Some(&template) = map.get(&byte_index) { if let Some(&template) = map.get(&byte_index) {
right_template.template.set(template); right_template.template.set(template);
if template != left_template.template.get() { if template != left_template.template.get() {
return self.replace(left_template, [right_template], todo!()); let parent = left_template.parent.take().map(|parent_id| unsafe {
std::mem::transmute(self.element_refs[parent_id.0])
});
return self.replace(left_template, [right_template], parent);
} }
} }
} }
@@ -99,7 +105,7 @@ impl<'b> VirtualDom {
// If the templates are different by name, we need to replace the entire template // If the templates are different by name, we need to replace the entire template
if templates_are_different(left_template, right_template) { if templates_are_different(left_template, right_template) {
return self.light_diff_templates(left_template, right_template, todo!()); return self.light_diff_templates(left_template, right_template);
} }
// If the templates are the same, we can diff the attributes and children // If the templates are the same, we can diff the attributes and children
@@ -129,9 +135,12 @@ impl<'b> VirtualDom {
.zip(right_template.dynamic_nodes.iter()) .zip(right_template.dynamic_nodes.iter())
.enumerate() .enumerate()
.for_each(|(dyn_node_idx, (left_node, right_node))| { .for_each(|(dyn_node_idx, (left_node, right_node))| {
let current_ref = BoundaryRef { let current_ref = ElementRef {
parent: right_template, template: right_template.into(),
dyn_node_idx, path: ElementPath {
path: left_template.template.get().node_paths[dyn_node_idx],
},
scope: self.runtime.scope_stack.borrow().last().copied().unwrap(),
}; };
self.diff_dynamic_node(left_node, right_node, current_ref); self.diff_dynamic_node(left_node, right_node, current_ref);
}); });
@@ -150,13 +159,13 @@ impl<'b> VirtualDom {
&mut self, &mut self,
left_node: &'b DynamicNode<'b>, left_node: &'b DynamicNode<'b>,
right_node: &'b DynamicNode<'b>, right_node: &'b DynamicNode<'b>,
parent: BoundaryRef<'b>, parent: ElementRef<'b>,
) { ) {
match (left_node, right_node) { match (left_node, right_node) {
(Text(left), Text(right)) => self.diff_vtext(left, right), (Text(left), Text(right)) => self.diff_vtext(left, right),
(Fragment(left), Fragment(right)) => self.diff_non_empty_fragment(left, right, parent), (Fragment(left), Fragment(right)) => self.diff_non_empty_fragment(left, right, parent),
(Placeholder(left), Placeholder(right)) => right.id.set(left.id.get()), (Placeholder(left), Placeholder(right)) => right.id.set(left.id.get()),
(Component(left), Component(right)) => self.diff_vcomponent(left, right, parent), (Component(left), Component(right)) => self.diff_vcomponent(left, right, Some(parent)),
(Placeholder(left), Fragment(right)) => self.replace_placeholder(left, *right, parent), (Placeholder(left), Fragment(right)) => self.replace_placeholder(left, *right, parent),
(Fragment(left), Placeholder(right)) => self.node_to_placeholder(left, right), (Fragment(left), Placeholder(right)) => self.node_to_placeholder(left, right),
_ => todo!("This is an usual custom case for dynamic nodes. We don't know how to handle it yet."), _ => todo!("This is an usual custom case for dynamic nodes. We don't know how to handle it yet."),
@@ -179,7 +188,7 @@ impl<'b> VirtualDom {
&mut self, &mut self,
left: &'b VComponent<'b>, left: &'b VComponent<'b>,
right: &'b VComponent<'b>, right: &'b VComponent<'b>,
parent: BoundaryRef<'b>, parent: Option<ElementRef<'b>>,
) { ) {
if std::ptr::eq(left, right) { if std::ptr::eq(left, right) {
return; return;
@@ -224,7 +233,7 @@ impl<'b> VirtualDom {
&mut self, &mut self,
right: &'b VComponent<'b>, right: &'b VComponent<'b>,
left: &'b VComponent<'b>, left: &'b VComponent<'b>,
parent: BoundaryRef<'b>, parent: Option<ElementRef<'b>>,
) { ) {
let m = self.create_component_node(parent, right); let m = self.create_component_node(parent, right);
@@ -280,17 +289,16 @@ impl<'b> VirtualDom {
/// Component { ..props } /// Component { ..props }
/// } /// }
/// ``` /// ```
fn light_diff_templates( fn light_diff_templates(&mut self, left: &'b VNode<'b>, right: &'b VNode<'b>) {
&mut self, let parent = left
left: &'b VNode<'b>, .parent
right: &'b VNode<'b>, .take()
parent: BoundaryRef<'b>, .map(|parent_id| unsafe { std::mem::transmute(self.element_refs[parent_id.0]) });
) {
match matching_components(left, right) { match matching_components(left, right) {
None => self.replace(left, [right], parent), None => self.replace(left, [right], parent),
Some(components) => components Some(components) => components
.into_iter() .into_iter()
.for_each(|(idx, l, r)| self.diff_vcomponent(l, r, parent)), .for_each(|(l, r)| self.diff_vcomponent(l, r, parent)),
} }
} }
@@ -312,7 +320,7 @@ impl<'b> VirtualDom {
&mut self, &mut self,
old: &'b [VNode<'b>], old: &'b [VNode<'b>],
new: &'b [VNode<'b>], new: &'b [VNode<'b>],
parent: BoundaryRef<'b>, parent: ElementRef<'b>,
) { ) {
let new_is_keyed = new[0].key.is_some(); let new_is_keyed = new[0].key.is_some();
let old_is_keyed = old[0].key.is_some(); let old_is_keyed = old[0].key.is_some();
@@ -344,7 +352,7 @@ impl<'b> VirtualDom {
&mut self, &mut self,
old: &'b [VNode<'b>], old: &'b [VNode<'b>],
new: &'b [VNode<'b>], new: &'b [VNode<'b>],
parent: BoundaryRef<'b>, parent: ElementRef<'b>,
) { ) {
use std::cmp::Ordering; use std::cmp::Ordering;
@@ -385,7 +393,7 @@ impl<'b> VirtualDom {
&mut self, &mut self,
old: &'b [VNode<'b>], old: &'b [VNode<'b>],
new: &'b [VNode<'b>], new: &'b [VNode<'b>],
parent: BoundaryRef<'b>, parent: ElementRef<'b>,
) { ) {
if cfg!(debug_assertions) { if cfg!(debug_assertions) {
let mut keys = rustc_hash::FxHashSet::default(); let mut keys = rustc_hash::FxHashSet::default();
@@ -464,7 +472,7 @@ impl<'b> VirtualDom {
&mut self, &mut self,
old: &'b [VNode<'b>], old: &'b [VNode<'b>],
new: &'b [VNode<'b>], new: &'b [VNode<'b>],
parent: BoundaryRef<'b>, parent: ElementRef<'b>,
) -> Option<(usize, usize)> { ) -> Option<(usize, usize)> {
let mut left_offset = 0; let mut left_offset = 0;
@@ -523,7 +531,7 @@ impl<'b> VirtualDom {
&mut self, &mut self,
old: &'b [VNode<'b>], old: &'b [VNode<'b>],
new: &'b [VNode<'b>], new: &'b [VNode<'b>],
parent: BoundaryRef<'b>, parent: ElementRef<'b>,
) { ) {
/* /*
1. Map the old keys into a numerical ordering based on indices. 1. Map the old keys into a numerical ordering based on indices.
@@ -581,7 +589,7 @@ impl<'b> VirtualDom {
if shared_keys.is_empty() { if shared_keys.is_empty() {
if old.get(0).is_some() { if old.get(0).is_some() {
self.remove_nodes(&old[1..]); self.remove_nodes(&old[1..]);
self.replace(&old[0], new, parent); self.replace(&old[0], new, Some(parent));
} else { } else {
// I think this is wrong - why are we appending? // I think this is wrong - why are we appending?
// only valid of the if there are no trailing elements // only valid of the if there are no trailing elements
@@ -762,7 +770,7 @@ impl<'b> VirtualDom {
fn create_children( fn create_children(
&mut self, &mut self,
nodes: impl IntoIterator<Item = &'b VNode<'b>>, nodes: impl IntoIterator<Item = &'b VNode<'b>>,
parent: BoundaryRef<'b>, parent: Option<ElementRef<'b>>,
) -> usize { ) -> usize {
nodes.into_iter().fold(0, |acc, child| { nodes.into_iter().fold(0, |acc, child| {
self.assign_boundary_ref(parent, child); self.assign_boundary_ref(parent, child);
@@ -774,9 +782,9 @@ impl<'b> VirtualDom {
&mut self, &mut self,
new: &'b [VNode<'b>], new: &'b [VNode<'b>],
before: &'b VNode<'b>, before: &'b VNode<'b>,
parent: BoundaryRef<'b>, parent: ElementRef<'b>,
) { ) {
let m = self.create_children(new, parent); let m = self.create_children(new, Some(parent));
let id = self.find_first_element(before); let id = self.find_first_element(before);
self.mutations.push(Mutation::InsertBefore { id, m }) self.mutations.push(Mutation::InsertBefore { id, m })
} }
@@ -785,9 +793,9 @@ impl<'b> VirtualDom {
&mut self, &mut self,
new: &'b [VNode<'b>], new: &'b [VNode<'b>],
after: &'b VNode<'b>, after: &'b VNode<'b>,
parent: BoundaryRef<'b>, parent: ElementRef<'b>,
) { ) {
let m = self.create_children(new, parent); let m = self.create_children(new, Some(parent));
let id = self.find_last_element(after); let id = self.find_last_element(after);
self.mutations.push(Mutation::InsertAfter { id, m }) self.mutations.push(Mutation::InsertAfter { id, m })
} }
@@ -797,9 +805,9 @@ impl<'b> VirtualDom {
&mut self, &mut self,
l: &'b VPlaceholder, l: &'b VPlaceholder,
r: impl IntoIterator<Item = &'b VNode<'b>>, r: impl IntoIterator<Item = &'b VNode<'b>>,
parent: BoundaryRef<'b>, parent: ElementRef<'b>,
) { ) {
let m = self.create_children(r, parent); let m = self.create_children(r, Some(parent));
let id = l.id.get().unwrap(); let id = l.id.get().unwrap();
self.mutations.push(Mutation::ReplaceWith { id, m }); self.mutations.push(Mutation::ReplaceWith { id, m });
self.reclaim(id); self.reclaim(id);
@@ -809,7 +817,7 @@ impl<'b> VirtualDom {
&mut self, &mut self,
left: &'b VNode<'b>, left: &'b VNode<'b>,
right: impl IntoIterator<Item = &'b VNode<'b>>, right: impl IntoIterator<Item = &'b VNode<'b>>,
parent: BoundaryRef<'b>, parent: Option<ElementRef<'b>>,
) { ) {
let m = self.create_children(right, parent); let m = self.create_children(right, parent);
@@ -1031,13 +1039,15 @@ impl<'b> VirtualDom {
} }
} }
pub(crate) fn assign_boundary_ref(&mut self, parent: BoundaryRef, child: &VNode<'_>) { pub(crate) fn assign_boundary_ref(
// assign the parent &mut self,
let path = parent.parent.template.get().node_paths[parent.dyn_node_idx]; parent: Option<ElementRef<'b>>,
child: &'b VNode<'b>,
child ) {
.parent if let Some(parent) = parent {
.set(Some(self.next_element_ref(parent.parent, path))); // assign the parent of the child
child.parent.set(Some(self.next_element_ref(parent)));
}
} }
} }
@@ -1060,7 +1070,7 @@ fn templates_are_different(left_template: &VNode, right_template: &VNode) -> boo
fn matching_components<'a>( fn matching_components<'a>(
left: &'a VNode<'a>, left: &'a VNode<'a>,
right: &'a VNode<'a>, right: &'a VNode<'a>,
) -> Option<Vec<(usize, &'a VComponent<'a>, &'a VComponent<'a>)>> { ) -> Option<Vec<(&'a VComponent<'a>, &'a VComponent<'a>)>> {
let left_template = left.template.get(); let left_template = left.template.get();
let right_template = right.template.get(); let right_template = right.template.get();
if left_template.roots.len() != right_template.roots.len() { if left_template.roots.len() != right_template.roots.len() {
@@ -1072,8 +1082,7 @@ fn matching_components<'a>(
.roots .roots
.iter() .iter()
.zip(right_template.roots.iter()) .zip(right_template.roots.iter())
.enumerate() .map(|(l, r)| {
.map(|(idx, (l, r))| {
let (l, r) = match (l, r) { let (l, r) = match (l, r) {
(TemplateNode::Dynamic { id: l }, TemplateNode::Dynamic { id: r }) => (l, r), (TemplateNode::Dynamic { id: l }, TemplateNode::Dynamic { id: r }) => (l, r),
_ => return None, _ => return None,
@@ -1084,7 +1093,7 @@ fn matching_components<'a>(
_ => return None, _ => return None,
}; };
Some((idx, l, r)) Some((l, r))
}) })
.collect() .collect()
} }
@@ -1116,9 +1125,3 @@ fn is_dyn_node_only_child(node: &VNode, idx: usize) -> bool {
_ => false, _ => false,
} }
} }
// A parent that can be used for bubbling
pub(crate) struct BoundaryRef<'b> {
pub parent: &'b VNode<'b>,
pub dyn_node_idx: usize,
}
+1 -5
View File
@@ -183,7 +183,7 @@ pub struct VirtualDom {
pub(crate) templates: FxHashMap<TemplateId, FxHashMap<usize, Template<'static>>>, pub(crate) templates: FxHashMap<TemplateId, FxHashMap<usize, Template<'static>>>,
// Every element is actually a dual reference - one to the template and the other to the dynamic node in that template // Every element is actually a dual reference - one to the template and the other to the dynamic node in that template
pub(crate) element_refs: Slab<ElementRef>, pub(crate) element_refs: Slab<ElementRef<'static>>,
// The element ids that are used in the renderer // The element ids that are used in the renderer
pub(crate) elements: Slab<Option<BubbleId>>, pub(crate) elements: Slab<Option<BubbleId>>,
@@ -353,13 +353,11 @@ impl VirtualDom {
| | | <-- no, broke early | | | <-- no, broke early
| <-- no, broke early | <-- no, broke early
*/ */
println!("calling {:?}", element);
let element = match self.elements.get(element.0) { let element = match self.elements.get(element.0) {
Some(Some(el)) => el, Some(Some(el)) => el,
_ => return, _ => return,
}; };
let mut parent_path = self.element_refs.get(element.0).cloned(); let mut parent_path = self.element_refs.get(element.0).cloned();
println!("parent path {:?}", parent_path);
let mut listeners = vec![]; let mut listeners = vec![];
// We will clone this later. The data itself is wrapped in RC to be used in callbacks if required // We will clone this later. The data itself is wrapped in RC to be used in callbacks if required
@@ -374,7 +372,6 @@ impl VirtualDom {
while let Some(el_ref) = parent_path { while let Some(el_ref) = parent_path {
// safety: we maintain references of all vnodes in the element slab // safety: we maintain references of all vnodes in the element slab
let template = el_ref.template; let template = el_ref.template;
let template = unsafe { template.as_ref() };
let node_template = template.template.get(); let node_template = template.template.get();
let target_path = el_ref.path; let target_path = el_ref.path;
@@ -425,7 +422,6 @@ impl VirtualDom {
if let Some(el_ref) = parent_path { if let Some(el_ref) = parent_path {
// safety: we maintain references of all vnodes in the element slab // safety: we maintain references of all vnodes in the element slab
let template = el_ref.template; let template = el_ref.template;
let template = unsafe { template.as_ref() };
let node_template = template.template.get(); let node_template = template.template.get();
let target_path = el_ref.path; let target_path = el_ref.path;
+64
View File
@@ -0,0 +1,64 @@
use dioxus::prelude::*;
use dioxus_core::ElementId;
use std::{rc::Rc, sync::Mutex};
static CLICKS: Mutex<usize> = Mutex::new(0);
#[test]
fn events_propagate() {
let mut dom = VirtualDom::new(app);
_ = dom.rebuild();
// Top-level click is registered
dom.handle_event("click", Rc::new(MouseData::default()), ElementId(1), true);
assert_eq!(*CLICKS.lock().unwrap(), 1);
// break reference....
for _ in 0..5 {
dom.mark_dirty(ScopeId(0));
_ = dom.rebuild();
}
// Lower click is registered
dom.handle_event("click", Rc::new(MouseData::default()), ElementId(2), true);
assert_eq!(*CLICKS.lock().unwrap(), 3);
// break reference....
for _ in 0..5 {
dom.mark_dirty(ScopeId(0));
_ = dom.rebuild();
}
// Stop propagation occurs
dom.handle_event("click", Rc::new(MouseData::default()), ElementId(2), true);
assert_eq!(*CLICKS.lock().unwrap(), 3);
}
fn app(cx: Scope) -> Element {
render! {
div {
onclick: move |_| {
println!("top clicked");
*CLICKS.lock().unwrap() += 1;
},
problematic_child {}
}
}
}
fn problematic_child(cx: Scope) -> Element {
render! {
button {
onclick: move |evt| {
let mut clicks = CLICKS.lock().unwrap();
if *clicks == 3 {
evt.stop_propagation();
} else {
*clicks += 1;
}
}
}
}
}
+1 -2
View File
@@ -271,10 +271,9 @@ fn create_random_element(cx: Scope<DepthProps>) -> Element {
) )
.into_boxed_str(), .into_boxed_str(),
)); ));
// println!("{template:#?}");
let node = VNode { let node = VNode {
key: None, key: None,
parent: None, parent: Default::default(),
template: Cell::new(template), template: Cell::new(template),
root_ids: bumpalo::collections::Vec::new_in(cx.bump()).into(), root_ids: bumpalo::collections::Vec::new_in(cx.bump()).into(),
dynamic_nodes: { dynamic_nodes: {