feat: use walking pattern
This commit is contained in:
1 parent
7cbb4d52dd
commit
22d4bf7346
18 files changed
+751
-843
No files matched your search
@@ -34,17 +34,11 @@ slab = "0.4"
|
|||||||
|
|
||||||
futures-channel = "0.3.21"
|
futures-channel = "0.3.21"
|
||||||
|
|
||||||
# used for noderefs
|
|
||||||
once_cell = "1.8"
|
|
||||||
|
|
||||||
indexmap = "1.7"
|
indexmap = "1.7"
|
||||||
|
|
||||||
# Serialize the Edits for use in Webview/Liveview instances
|
# Serialize the Edits for use in Webview/Liveview instances
|
||||||
serde = { version = "1", features = ["derive"], optional = true }
|
serde = { version = "1", features = ["derive"], optional = true }
|
||||||
|
|
||||||
# todo: I want to get rid of this
|
|
||||||
backtrace = "0.3"
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
serialize = ["serde"]
|
serialize = ["serde"]
|
||||||
|
|||||||
@@ -114,6 +114,11 @@ Some essential reading:
|
|||||||
- https://web.dev/rail/
|
- https://web.dev/rail/
|
||||||
- https://indepth.dev/posts/1008/inside-fiber-in-depth-overview-of-the-new-reconciliation-algorithm-in-react
|
- https://indepth.dev/posts/1008/inside-fiber-in-depth-overview-of-the-new-reconciliation-algorithm-in-react
|
||||||
|
|
||||||
|
# Templates
|
||||||
|
|
||||||
|
If everything is a template, then we'll have the idea that the only children can b Templates
|
||||||
|
|
||||||
|
|
||||||
# What's going on?
|
# What's going on?
|
||||||
|
|
||||||
Dioxus is a framework for "user experience" - not just "user interfaces." Part of the "experience" is keeping the UI
|
Dioxus is a framework for "user experience" - not just "user interfaces." Part of the "experience" is keeping the UI
|
||||||
|
|||||||
+128
-201
@@ -112,9 +112,7 @@ impl<'a, 'b, R: Renderer<'b>> DiffState<'a, 'b, R> {
|
|||||||
|
|
||||||
self.scope_stack.push(scopeid);
|
self.scope_stack.push(scopeid);
|
||||||
self.element_stack.push(scope.container);
|
self.element_stack.push(scope.container);
|
||||||
{
|
self.diff_node(old, new);
|
||||||
self.diff_node(old, new);
|
|
||||||
}
|
|
||||||
self.element_stack.pop();
|
self.element_stack.pop();
|
||||||
self.scope_stack.pop();
|
self.scope_stack.pop();
|
||||||
|
|
||||||
@@ -122,58 +120,45 @@ impl<'a, 'b, R: Renderer<'b>> DiffState<'a, 'b, R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn diff_node(&mut self, old_node: &'b VNode<'b>, new_node: &'b VNode<'b>) {
|
pub fn diff_node(&mut self, old_node: &'b VNode<'b>, new_node: &'b VNode<'b>) {
|
||||||
use VNode::{Component, Element, Fragment, Placeholder, Template, Text};
|
use VNode::{Component, Element, Fragment, Template, Text};
|
||||||
|
|
||||||
|
// Same node by ref, no need to diff.
|
||||||
|
if std::ptr::eq(old_node, new_node) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
match (old_node, new_node) {
|
match (old_node, new_node) {
|
||||||
(Text(old), Text(new)) => {
|
(Text(old), Text(new)) => self.diff_text(old, new, old_node, new_node),
|
||||||
self.diff_text_nodes(old, new, old_node, new_node);
|
(Element(old), Element(new)) => self.diff_element(old, new, old_node, new_node),
|
||||||
}
|
(Component(old), Component(new)) => self.diff_component(old_node, new_node, *old, *new),
|
||||||
|
(Fragment(old), Fragment(new)) => self.diff_fragment(old, new),
|
||||||
(Element(old), Element(new)) => {
|
(Template(old), Template(new)) => self.diff_templates(old, new, old_node, new_node),
|
||||||
self.diff_element_nodes(old, new, old_node, new_node);
|
|
||||||
}
|
|
||||||
|
|
||||||
(Component(old), Component(new)) => {
|
|
||||||
self.diff_component_nodes(old_node, new_node, *old, *new);
|
|
||||||
}
|
|
||||||
|
|
||||||
(Fragment(old), Fragment(new)) => {
|
|
||||||
self.diff_fragment_nodes(old, new);
|
|
||||||
}
|
|
||||||
|
|
||||||
(Template(old), Template(new)) => {
|
|
||||||
self.diff_templates(old, new, old_node, new_node);
|
|
||||||
}
|
|
||||||
|
|
||||||
(Placeholder(_), Placeholder(_)) => {
|
|
||||||
self.diff_placeholder_nodes(old_node, new_node);
|
|
||||||
}
|
|
||||||
|
|
||||||
(
|
(
|
||||||
Component(_) | Text(_) | Element(_) | Template(_) | Fragment(_) | Placeholder(_),
|
Component(_) | Text(_) | Element(_) | Template(_) | Fragment(_),
|
||||||
Component(_) | Text(_) | Element(_) | Template(_) | Fragment(_) | Placeholder(_),
|
Component(_) | Text(_) | Element(_) | Template(_) | Fragment(_),
|
||||||
) => self.replace_node(old_node, new_node),
|
) => self.replace_node(old_node, new_node),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_node(&mut self, node: &'b VNode<'b>) -> usize {
|
pub fn create_node(&mut self, node: &'b VNode<'b>) -> usize {
|
||||||
match node {
|
match node {
|
||||||
VNode::Text(vtext) => self.create_text_node(vtext, node),
|
VNode::Text(vtext) => self.create_text(vtext, node),
|
||||||
VNode::Element(element) => self.create_element_node(element, node),
|
VNode::Element(element) => self.create_element(element, node),
|
||||||
VNode::Fragment(frag) => self.create_fragment_node(*frag),
|
VNode::Fragment(frag) => self.create_fragment(frag),
|
||||||
VNode::Component(component) => self.create_component_node(*component),
|
VNode::Component(component) => self.create_component_node(*component),
|
||||||
VNode::Template(template) => self.create_template_node(template, node),
|
VNode::Template(template) => self.create_template_node(template, node),
|
||||||
VNode::Placeholder(placeholder) => todo!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_text_node(&mut self, text: &'b VText<'b>, node: &'b VNode<'b>) -> usize {
|
fn create_text(&mut self, text: &'b VText<'b>, node: &'b VNode<'b>) -> usize {
|
||||||
let real_id = self.scopes.reserve_node(node);
|
let real_id = self.scopes.reserve_node(node);
|
||||||
text.id.set(Some(real_id));
|
text.id.set(Some(real_id));
|
||||||
self.mutations.create_text_node(text.text, real_id);
|
self.mutations.create_text_node(text.text, real_id);
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_element_node(&mut self, element: &'b VElement<'b>, node: &'b VNode<'b>) -> usize {
|
fn create_element(&mut self, element: &'b VElement<'b>, node: &'b VNode<'b>) -> usize {
|
||||||
let VElement {
|
let VElement {
|
||||||
tag: tag_name,
|
tag: tag_name,
|
||||||
listeners,
|
listeners,
|
||||||
@@ -198,7 +183,7 @@ impl<'a, 'b, R: Renderer<'b>> DiffState<'a, 'b, R> {
|
|||||||
let cur_scope_id = self.current_scope();
|
let cur_scope_id = self.current_scope();
|
||||||
|
|
||||||
for listener in listeners.iter() {
|
for listener in listeners.iter() {
|
||||||
listener.mounted_node.set(Some(real_id));
|
listener.mounted_node.set(real_id);
|
||||||
self.mutations.new_event_listener(listener, cur_scope_id);
|
self.mutations.new_event_listener(listener, cur_scope_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,7 +201,7 @@ impl<'a, 'b, R: Renderer<'b>> DiffState<'a, 'b, R> {
|
|||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_fragment_node(&mut self, frag: &'b VFragment<'b>) -> usize {
|
fn create_fragment(&mut self, frag: &'b VFragment<'b>) -> usize {
|
||||||
self.create_children(frag.children)
|
self.create_children(frag.children)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,17 +259,13 @@ impl<'a, 'b, R: Renderer<'b>> DiffState<'a, 'b, R> {
|
|||||||
created
|
created
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn diff_text_nodes(
|
pub(crate) fn diff_text(
|
||||||
&mut self,
|
&mut self,
|
||||||
old: &'b VText<'b>,
|
old: &'b VText<'b>,
|
||||||
new: &'b VText<'b>,
|
new: &'b VText<'b>,
|
||||||
_old_node: &'b VNode<'b>,
|
_old_node: &'b VNode<'b>,
|
||||||
new_node: &'b VNode<'b>,
|
new_node: &'b VNode<'b>,
|
||||||
) {
|
) {
|
||||||
if std::ptr::eq(old, new) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the node is comming back not assigned, that means it was borrowed but removed
|
// if the node is comming back not assigned, that means it was borrowed but removed
|
||||||
let root = match old.id.get() {
|
let root = match old.id.get() {
|
||||||
Some(id) => id,
|
Some(id) => id,
|
||||||
@@ -307,183 +288,138 @@ impl<'a, 'b, R: Renderer<'b>> DiffState<'a, 'b, R> {
|
|||||||
old_node: &'b VNode<'b>,
|
old_node: &'b VNode<'b>,
|
||||||
new_node: &'b VNode<'b>,
|
new_node: &'b VNode<'b>,
|
||||||
) {
|
) {
|
||||||
if old.template.id == new.template.id {
|
if old.template.id != new.template.id {
|
||||||
// if they're the same, just diff the dynamic nodes directly
|
return self.replace_node(old_node, new_node);
|
||||||
for (left, right) in old.dynamic_nodes.iter().zip(new.dynamic_nodes.iter()) {
|
}
|
||||||
self.diff_node(left, right);
|
|
||||||
|
// if they're the same, just diff the dynamic nodes directly
|
||||||
|
for (left, right) in old.dynamic_nodes.iter().zip(new.dynamic_nodes.iter()) {
|
||||||
|
self.diff_node(&left.node, &right.node);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (left, right) in old.dynamic_attrs.iter().zip(new.dynamic_attrs.iter()) {
|
||||||
|
let id = left.mounted_element.get();
|
||||||
|
right.mounted_element.set(id);
|
||||||
|
|
||||||
|
for (left, right) in right.attrs.iter().zip(left.attrs.iter()) {
|
||||||
|
if right.value != left.value || right.volatile {
|
||||||
|
self.mutations
|
||||||
|
.set_attribute(right.name, right.value, right.namespace, id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: need a way to load up the element bound to these attributes
|
// There's not really any diffing that needs to happen for listeners
|
||||||
for (left, right) in old.dynamic_attrs.iter().zip(new.dynamic_attrs.iter()) {
|
for listener in right.listeners {
|
||||||
//
|
listener.mounted_node.set(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// hmm, what we do here?
|
|
||||||
for (left, right) in old.listeners.iter().zip(new.listeners.iter()) {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// else, diff them manually, taking the slow path
|
|
||||||
self.replace_node(old_node, new_node);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_static_template_nodes(&mut self, node: &'b TemplateNode) {
|
fn create_static_template_nodes(&mut self, node: &'b TemplateNode, id: ElementId) {
|
||||||
let id = ElementId(999999);
|
match *node {
|
||||||
match node {
|
|
||||||
TemplateNode::Element {
|
TemplateNode::Element {
|
||||||
tag,
|
tag,
|
||||||
attrs,
|
attrs,
|
||||||
children,
|
children,
|
||||||
|
namespace,
|
||||||
} => {
|
} => {
|
||||||
self.mutations.create_element(tag, None, id);
|
self.mutations.create_element(tag, namespace, id);
|
||||||
|
for attr in attrs {
|
||||||
for attr in *attrs {
|
self.mutations.set_attribute(
|
||||||
match attr {
|
attr.name,
|
||||||
crate::TemplateAttribute::Dynamic(_) => todo!(),
|
AttributeValue::Text(attr.value),
|
||||||
crate::TemplateAttribute::Static { name, value } => {
|
attr.namespace,
|
||||||
self.mutations.set_attribute(
|
id,
|
||||||
name,
|
);
|
||||||
AttributeValue::Text(value),
|
|
||||||
None,
|
|
||||||
id,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for child in children.iter() {
|
for child in children.iter() {
|
||||||
self.create_static_template_nodes(child);
|
self.create_static_template_nodes(child, id);
|
||||||
}
|
}
|
||||||
self.mutations.append_children(children.len() as u32);
|
self.mutations.append_children(children.len() as u32);
|
||||||
}
|
}
|
||||||
TemplateNode::Text(ref text) => self.mutations.create_text_node(text, id),
|
TemplateNode::Text(text) => self.mutations.create_text_node(text, id),
|
||||||
TemplateNode::Dynamic(_) => self.mutations.create_placeholder(id),
|
TemplateNode::Dynamic(_) => self.mutations.create_placeholder(id),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create the template from scratch using instructions, cache it, and then use the instructions to build it
|
/// Create the template from scratch using instructions, cache it, and then use the instructions to build it
|
||||||
|
///
|
||||||
|
/// This would be way easier if the ID could just be unique *after* cloning
|
||||||
|
///
|
||||||
|
/// If we traversed the template
|
||||||
fn create_template_node(&mut self, template: &'b VTemplate<'b>, node: &'b VNode<'b>) -> usize {
|
fn create_template_node(&mut self, template: &'b VTemplate<'b>, node: &'b VNode<'b>) -> usize {
|
||||||
let template_id = template.template.id;
|
// Reserve a single node for all the template nodes to reuse
|
||||||
let templates = self.scopes.template_cache.borrow_mut();
|
template.node_id.set(self.scopes.reserve_node(node));
|
||||||
|
|
||||||
// create and insert the template if it doesn't exist within the VirtualDom (it won't exist on the renderer either)
|
// Save the template if it doesn't exist
|
||||||
|
// todo: use &mut cache instead of borrowed cache
|
||||||
|
let mut templates = self.scopes.template_cache.borrow_mut();
|
||||||
if !templates.contains(&template.template) {
|
if !templates.contains(&template.template) {
|
||||||
template
|
template
|
||||||
.template
|
.template
|
||||||
.roots
|
.roots
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.for_each(|node| self.create_static_template_nodes(node));
|
.for_each(|node| self.create_static_template_nodes(node, template.node_id.get()));
|
||||||
|
|
||||||
self.mutations
|
self.mutations
|
||||||
.save(template_id, template.template.roots.len() as u32);
|
.save(template.template.id, template.template.roots.len() as u32);
|
||||||
|
|
||||||
|
templates.insert(template.template);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.mutations.load(template_id);
|
// Walk the roots backwards, creating nodes and assigning IDs
|
||||||
|
let mut dynamic_attrs = template.dynamic_attrs.iter().peekable();
|
||||||
|
let mut dynamic_nodes = template.dynamic_nodes.iter().peekable();
|
||||||
|
|
||||||
let mut created = 0;
|
let mut on_stack = 0;
|
||||||
|
for (root_idx, root) in template.template.roots.iter().enumerate() {
|
||||||
|
on_stack += match root {
|
||||||
|
TemplateNode::Dynamic(id) => self.create_node(&template.dynamic_nodes[*id].node),
|
||||||
|
TemplateNode::Element { .. } | TemplateNode::Text(_) => 1,
|
||||||
|
};
|
||||||
|
|
||||||
// create the dynamic nodes
|
// we're on top of a node that has a dynamic attribute for a descndent
|
||||||
for node in template.dynamic_nodes.iter() {
|
// Set that attribute now before the stack gets in a weird state
|
||||||
created += self.create_node(node);
|
// Roots may not be more than 255 nodes long, enforced by the macro
|
||||||
|
while let Some(loc) = dynamic_attrs.next_if(|attr| attr.pathway[0] == root_idx as u8) {
|
||||||
|
// Attach all the elementIDs to the nodes with dynamic content
|
||||||
|
let id = self.scopes.reserve_node(node);
|
||||||
|
self.mutations.assign_id(&loc.pathway[1..], id);
|
||||||
|
loc.mounted_element.set(id);
|
||||||
|
|
||||||
|
for attr in loc.attrs {
|
||||||
|
self.mutations
|
||||||
|
.set_attribute(attr.name, attr.value, attr.namespace, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
for listener in loc.listeners {
|
||||||
|
listener.mounted_node.set(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while let Some(dyn_node) = dynamic_nodes.next_if(|f| f.pathway[0] == root_idx as u8) {
|
||||||
|
// we're on top of a node that has a dynamic node for a descndent
|
||||||
|
// Set that node now
|
||||||
|
// Roots may not be more than 255 nodes long, enforced by the macro
|
||||||
|
if dyn_node.pathway[0] == root_idx as u8 {
|
||||||
|
let created = self.create_node(&dyn_node.node);
|
||||||
|
|
||||||
|
self.mutations
|
||||||
|
.replace_descendant(&dyn_node.pathway[1..], created as u32);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// set any dynamic attributes
|
on_stack
|
||||||
for attr in template.dynamic_attrs.iter() {
|
|
||||||
// assign an ID to the element
|
|
||||||
let id = self.scopes.reserve_node(node);
|
|
||||||
|
|
||||||
self.mutations
|
|
||||||
.set_attribute(attr.name, attr.value, attr.namespace, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
todo!()
|
|
||||||
|
|
||||||
// let def = template.template;
|
|
||||||
|
|
||||||
// let mut templates = self.scopes.template_cache.borrow_mut();
|
|
||||||
|
|
||||||
// if !templates.contains(&def) {
|
|
||||||
// // self.create_template_def(def);
|
|
||||||
// templates.insert(def);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// let mut nodes_created = 0;
|
|
||||||
// let mut dynamic_nodes = template.dynamic_nodes.iter().enumerate().rev();
|
|
||||||
|
|
||||||
// for node in template.rendered_nodes {
|
|
||||||
// match node {
|
|
||||||
// // Give it an ID
|
|
||||||
// crate::innerlude::TemplateRoots::Static(_) => todo!(),
|
|
||||||
|
|
||||||
// // let the creation step give it an ID
|
|
||||||
// crate::innerlude::TemplateRoots::Runtime(_) => todo!(),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Create all the dynamic nodes and merge them into the template
|
|
||||||
// for (index, node) in dynamic_nodes {
|
|
||||||
// let new_created = self.create_node(node);
|
|
||||||
// self.mutations.edits.push(DomEdit::MergeTemplate {
|
|
||||||
// index: index as u32,
|
|
||||||
// num_children: new_created as u32,
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
|
|
||||||
// nodes_created
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_template_static_node(&mut self, nodes: &'static [VNode<'static>]) -> usize {
|
fn diff_element(
|
||||||
todo!()
|
|
||||||
// let mut created = 0;
|
|
||||||
// for node in nodes {
|
|
||||||
// match *node {
|
|
||||||
// TemplateNode::Element(el) => {
|
|
||||||
// for attr in el.attributes {
|
|
||||||
// match attr {
|
|
||||||
// crate::template::TemplateAttribute::Dynamic => todo!(),
|
|
||||||
// crate::template::TemplateAttribute::Static { attr } => {
|
|
||||||
// self.mutations.set_attribute(attr, 0);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// self.mutations.create_element(el.tag, None, ElementId(0));
|
|
||||||
|
|
||||||
// if !nodes.is_empty() {
|
|
||||||
// let res = self.create_template_static_node(nodes);
|
|
||||||
// self.mutations.append_children(res as u32);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// created += 1;
|
|
||||||
// }
|
|
||||||
// TemplateNode::StaticText(text) => {
|
|
||||||
// self.mutations.create_text_node(text, ElementId(0));
|
|
||||||
// created += 1;
|
|
||||||
// }
|
|
||||||
// TemplateNode::DynamicText(_)
|
|
||||||
// | TemplateNode::DynamicExpr(_)
|
|
||||||
// | TemplateNode::DynamicComponent(_) => {
|
|
||||||
// self.mutations.create_placeholder(ElementId(0));
|
|
||||||
// created += 1;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// created
|
|
||||||
}
|
|
||||||
|
|
||||||
fn diff_element_nodes(
|
|
||||||
&mut self,
|
&mut self,
|
||||||
old: &'b VElement<'b>,
|
old: &'b VElement<'b>,
|
||||||
new: &'b VElement<'b>,
|
new: &'b VElement<'b>,
|
||||||
old_node: &'b VNode<'b>,
|
old_node: &'b VNode<'b>,
|
||||||
new_node: &'b VNode<'b>,
|
new_node: &'b VNode<'b>,
|
||||||
) {
|
) {
|
||||||
if std::ptr::eq(old, new) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the node is comming back not assigned, that means it was borrowed but removed
|
// if the node is comming back not assigned, that means it was borrowed but removed
|
||||||
let root = match old.id.get() {
|
let root = match old.id.get() {
|
||||||
Some(id) => id,
|
Some(id) => id,
|
||||||
@@ -563,7 +499,7 @@ impl<'a, 'b, R: Renderer<'b>> DiffState<'a, 'b, R> {
|
|||||||
self.mutations.remove_event_listener(listener.event, root);
|
self.mutations.remove_event_listener(listener.event, root);
|
||||||
}
|
}
|
||||||
for listener in new.listeners {
|
for listener in new.listeners {
|
||||||
listener.mounted_node.set(Some(root));
|
listener.mounted_node.set(root);
|
||||||
self.mutations.new_event_listener(listener, cur_scope_id);
|
self.mutations.new_event_listener(listener, cur_scope_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -580,7 +516,7 @@ impl<'a, 'b, R: Renderer<'b>> DiffState<'a, 'b, R> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn diff_component_nodes(
|
fn diff_component(
|
||||||
&mut self,
|
&mut self,
|
||||||
old_node: &'b VNode<'b>,
|
old_node: &'b VNode<'b>,
|
||||||
new_node: &'b VNode<'b>,
|
new_node: &'b VNode<'b>,
|
||||||
@@ -592,10 +528,6 @@ impl<'a, 'b, R: Renderer<'b>> DiffState<'a, 'b, R> {
|
|||||||
.get()
|
.get()
|
||||||
.expect("existing component nodes should have a scope");
|
.expect("existing component nodes should have a scope");
|
||||||
|
|
||||||
if std::ptr::eq(old, new) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure we're dealing with the same component (by function pointer)
|
// Make sure we're dealing with the same component (by function pointer)
|
||||||
if old.user_fc == new.user_fc {
|
if old.user_fc == new.user_fc {
|
||||||
self.enter_scope(scope_addr);
|
self.enter_scope(scope_addr);
|
||||||
@@ -654,11 +586,7 @@ impl<'a, 'b, R: Renderer<'b>> DiffState<'a, 'b, R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn diff_fragment_nodes(&mut self, old: &'b VFragment<'b>, new: &'b VFragment<'b>) {
|
fn diff_fragment(&mut self, old: &'b VFragment<'b>, new: &'b VFragment<'b>) {
|
||||||
if std::ptr::eq(old, new) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
todo!()
|
todo!()
|
||||||
// // This is the case where options or direct vnodes might be used.
|
// // This is the case where options or direct vnodes might be used.
|
||||||
// // In this case, it's faster to just skip ahead to their diff
|
// // In this case, it's faster to just skip ahead to their diff
|
||||||
@@ -1086,7 +1014,8 @@ impl<'a, 'b, R: Renderer<'b>> DiffState<'a, 'b, R> {
|
|||||||
self.scopes.collect_garbage(id);
|
self.scopes.collect_garbage(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
VNode::Text(_) | VNode::Placeholder(_) => {
|
// | VNode::Placeholder(_)
|
||||||
|
VNode::Text(_) => {
|
||||||
let id = old
|
let id = old
|
||||||
.try_mounted_id()
|
.try_mounted_id()
|
||||||
.unwrap_or_else(|| panic!("broke on {:?}", old));
|
.unwrap_or_else(|| panic!("broke on {:?}", old));
|
||||||
@@ -1145,15 +1074,15 @@ impl<'a, 'b, R: Renderer<'b>> DiffState<'a, 'b, R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
VNode::Placeholder(a) => {
|
// VNode::Placeholder(a) => {
|
||||||
let id = a.id.get().unwrap();
|
// let id = a.id.get().unwrap();
|
||||||
self.scopes.collect_garbage(id);
|
// self.scopes.collect_garbage(id);
|
||||||
a.id.set(None);
|
// a.id.set(None);
|
||||||
|
|
||||||
if gen_muts {
|
// if gen_muts {
|
||||||
self.mutations.remove(id);
|
// self.mutations.remove(id);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
VNode::Element(e) => {
|
VNode::Element(e) => {
|
||||||
let id = e.id.get().unwrap();
|
let id = e.id.get().unwrap();
|
||||||
|
|
||||||
@@ -1242,8 +1171,7 @@ impl<'a, 'b, R: Renderer<'b>> DiffState<'a, 'b, R> {
|
|||||||
}
|
}
|
||||||
VNode::Template(c) => {
|
VNode::Template(c) => {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
} // VNode::Placeholder(_) => todo!(),
|
||||||
VNode::Placeholder(_) => todo!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1261,8 +1189,7 @@ impl<'a, 'b, R: Renderer<'b>> DiffState<'a, 'b, R> {
|
|||||||
}
|
}
|
||||||
VNode::Template(t) => {
|
VNode::Template(t) => {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
} // VNode::Placeholder(_) => todo!(),
|
||||||
VNode::Placeholder(_) => todo!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1270,7 +1197,7 @@ impl<'a, 'b, R: Renderer<'b>> DiffState<'a, 'b, R> {
|
|||||||
// recursively push all the nodes of a tree onto the stack and return how many are there
|
// recursively push all the nodes of a tree onto the stack and return how many are there
|
||||||
fn push_all_real_nodes(&mut self, node: &'b VNode<'b>) -> usize {
|
fn push_all_real_nodes(&mut self, node: &'b VNode<'b>) -> usize {
|
||||||
match node {
|
match node {
|
||||||
VNode::Text(_) | VNode::Element(_) | VNode::Placeholder(_) => {
|
VNode::Text(_) | VNode::Element(_) => {
|
||||||
self.mutations.push_root(node.mounted_id());
|
self.mutations.push_root(node.mounted_id());
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
@@ -1294,7 +1221,7 @@ impl<'a, 'b, R: Renderer<'b>> DiffState<'a, 'b, R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn diff_placeholder_nodes(&self, old_node: &VNode, new_node: &VNode) {
|
pub(crate) fn diff_placeholder(&self, old_node: &VNode, new_node: &VNode) {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -20,6 +20,7 @@ pub trait Renderer<'a> {
|
|||||||
fn pop_root(&mut self);
|
fn pop_root(&mut self);
|
||||||
/// Replace the given element with the next m elements on the stack
|
/// Replace the given element with the next m elements on the stack
|
||||||
fn replace_with(&mut self, root: ElementId, m: u32);
|
fn replace_with(&mut self, root: ElementId, m: u32);
|
||||||
|
|
||||||
/// Insert the next m elements on the stack after the given element
|
/// Insert the next m elements on the stack after the given element
|
||||||
fn insert_after(&mut self, root: ElementId, n: u32);
|
fn insert_after(&mut self, root: ElementId, n: u32);
|
||||||
/// Insert the next m elements on the stack before the given element
|
/// Insert the next m elements on the stack before the given element
|
||||||
@@ -41,6 +42,8 @@ pub trait Renderer<'a> {
|
|||||||
fn remove(&mut self, root: ElementId);
|
fn remove(&mut self, root: ElementId);
|
||||||
/// Remove an attribute from an existing element
|
/// Remove an attribute from an existing element
|
||||||
fn remove_attribute(&mut self, attribute: &Attribute, root: ElementId);
|
fn remove_attribute(&mut self, attribute: &Attribute, root: ElementId);
|
||||||
|
/// Remove all the children of the given element
|
||||||
|
fn remove_children(&mut self, root: ElementId);
|
||||||
|
|
||||||
/// Attach a new listener to the dom
|
/// Attach a new listener to the dom
|
||||||
fn new_event_listener(&mut self, listener: &Listener, scope: ScopeId);
|
fn new_event_listener(&mut self, listener: &Listener, scope: ScopeId);
|
||||||
@@ -58,13 +61,38 @@ pub trait Renderer<'a> {
|
|||||||
root: ElementId,
|
root: ElementId,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Save the current n nodes to the ID to be loaded later
|
/// General statistics for doing things that extend outside of the renderer
|
||||||
fn save(&mut self, id: &str, num: u32);
|
|
||||||
/// Loads a set of saved nodes from the ID
|
|
||||||
fn load(&mut self, id: &str);
|
|
||||||
|
|
||||||
// General statistics for doing things that extend outside of the renderer
|
|
||||||
|
|
||||||
///
|
|
||||||
fn mark_dirty_scope(&mut self, scope: ScopeId);
|
fn mark_dirty_scope(&mut self, scope: ScopeId);
|
||||||
|
|
||||||
|
/// Save the current n nodes to the ID to be loaded later
|
||||||
|
fn save(&mut self, id: &'static str, num: u32);
|
||||||
|
/// Loads a set of saved nodes from the ID into a scratch space
|
||||||
|
fn load(&mut self, id: &'static str, index: u32);
|
||||||
|
/// Assign the element on the stack's descendent the given ID
|
||||||
|
fn assign_id(&mut self, descendent: &'static [u8], id: ElementId);
|
||||||
|
/// Replace the given element of the topmost element with the next m elements on the stack
|
||||||
|
/// Is essentially a combination of assign_id and replace_with
|
||||||
|
fn replace_descendant(&mut self, descendent: &'static [u8], m: u32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
div {
|
||||||
|
div {
|
||||||
|
div {
|
||||||
|
div {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
push_child(0)
|
||||||
|
push_child(1)
|
||||||
|
push_child(3)
|
||||||
|
push_child(4)
|
||||||
|
pop
|
||||||
|
pop
|
||||||
|
|
||||||
|
clone_node(0)
|
||||||
|
set_node(el, [1,2,3,4])
|
||||||
|
set_attribute("class", "foo")
|
||||||
|
append_child(1)
|
||||||
|
*/
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
use std::{
|
use std::{
|
||||||
any::Any,
|
any::Any,
|
||||||
fmt::{Arguments, Display, Formatter},
|
fmt::{Arguments, Formatter},
|
||||||
};
|
};
|
||||||
|
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
@@ -8,41 +8,40 @@ use bumpalo::Bump;
|
|||||||
/// Possible values for an attribute
|
/// Possible values for an attribute
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum AttributeValue<'a> {
|
pub enum AttributeValue<'a> {
|
||||||
|
/// Reference strs, most common
|
||||||
Text(&'a str),
|
Text(&'a str),
|
||||||
Float32(f32),
|
/// Basic float values
|
||||||
|
Float(f32),
|
||||||
|
/// Basic Int values
|
||||||
|
Int(i32),
|
||||||
|
/// Basic bool values
|
||||||
Bool(bool),
|
Bool(bool),
|
||||||
|
/// Everything else
|
||||||
Any(&'a dyn AnyAttributeValue),
|
Any(&'a dyn AnyAttributeValue),
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[cfg(feature = "serialize")]
|
|
||||||
|
|
||||||
impl<'a> PartialEq for AttributeValue<'a> {
|
impl<'a> PartialEq for AttributeValue<'a> {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(Self::Text(l0), Self::Text(r0)) => l0 == r0,
|
(Self::Text(l0), Self::Text(r0)) => l0 == r0,
|
||||||
(Self::Float32(l0), Self::Float32(r0)) => l0 == r0,
|
(Self::Float(l0), Self::Float(r0)) => l0 == r0,
|
||||||
|
(Self::Int(l0), Self::Int(r0)) => l0 == r0,
|
||||||
(Self::Bool(l0), Self::Bool(r0)) => l0 == r0,
|
(Self::Bool(l0), Self::Bool(r0)) => l0 == r0,
|
||||||
// (Self::Any(l0), Self::Any(r0)) => l0.cmp(r0),
|
(Self::Any(l0), Self::Any(r0)) => (*l0).cmp_any(*r0),
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Display for AttributeValue<'a> {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Debug for AttributeValue<'_> {
|
impl std::fmt::Debug for AttributeValue<'_> {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
todo!()
|
match self {
|
||||||
// match self {
|
AttributeValue::Text(s) => write!(f, "AttributeValue::Text({:?})", s),
|
||||||
// AttributeValue::Text(s) => write!(f, "AttributeValue::Text({:?})", s),
|
AttributeValue::Float(v) => write!(f, "AttributeValue::Float({:?})", v),
|
||||||
// AttributeValue::Float32(f) => write!(f, "AttributeValue::Float32({:?})", f),
|
AttributeValue::Int(v) => write!(f, "AttributeValue::Int({:?})", v),
|
||||||
// AttributeValue::Bool(b) => write!(f, "AttributeValue::Bool({:?})", b),
|
AttributeValue::Bool(b) => write!(f, "AttributeValue::Bool({:?})", b),
|
||||||
// AttributeValue::Any(a) => write!(f, "AttributeValue::Any({:?})", a),
|
AttributeValue::Any(_) => write!(f, "AttributeValue::Any()"),
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,24 +50,27 @@ pub trait IntoAttributeValue<'a> {
|
|||||||
/// Convert into an attribute value
|
/// Convert into an attribute value
|
||||||
fn into_value(self, bump: &'a Bump) -> AttributeValue<'a>;
|
fn into_value(self, bump: &'a Bump) -> AttributeValue<'a>;
|
||||||
}
|
}
|
||||||
impl<'a> IntoAttributeValue<'a> for f32 {
|
|
||||||
fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
|
|
||||||
AttributeValue::Float32(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> IntoAttributeValue<'a> for bool {
|
|
||||||
fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
|
|
||||||
AttributeValue::Bool(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> IntoAttributeValue<'a> for &'a str {
|
impl<'a> IntoAttributeValue<'a> for &'a str {
|
||||||
fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
|
fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
|
||||||
AttributeValue::Text(self)
|
AttributeValue::Text(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl<'a> IntoAttributeValue<'a> for f32 {
|
||||||
|
fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
|
||||||
|
AttributeValue::Float(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a> IntoAttributeValue<'a> for i32 {
|
||||||
|
fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
|
||||||
|
AttributeValue::Int(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a> IntoAttributeValue<'a> for bool {
|
||||||
|
fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
|
||||||
|
AttributeValue::Bool(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
impl<'a> IntoAttributeValue<'a> for Arguments<'_> {
|
impl<'a> IntoAttributeValue<'a> for Arguments<'_> {
|
||||||
fn into_value(self, bump: &'a Bump) -> AttributeValue<'a> {
|
fn into_value(self, bump: &'a Bump) -> AttributeValue<'a> {
|
||||||
use bumpalo::core_alloc::fmt::Write;
|
use bumpalo::core_alloc::fmt::Write;
|
||||||
@@ -78,29 +80,6 @@ impl<'a> IntoAttributeValue<'a> for Arguments<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> IntoAttributeValue<'a> for &'a T
|
|
||||||
where
|
|
||||||
T: PartialEq,
|
|
||||||
{
|
|
||||||
fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
|
|
||||||
todo!()
|
|
||||||
// AttributeValue::Any(ArbitraryAttributeValue {
|
|
||||||
// value: self,
|
|
||||||
// cmp: |a, b| {
|
|
||||||
// if let Some(a) = a.as_any().downcast_ref::<T>() {
|
|
||||||
// if let Some(b) = b.as_any().downcast_ref::<T>() {
|
|
||||||
// a == b
|
|
||||||
// } else {
|
|
||||||
// false
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// false
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// todo
|
// todo
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
impl<'a> AttributeValue<'a> {
|
impl<'a> AttributeValue<'a> {
|
||||||
@@ -130,16 +109,55 @@ impl<'a> AttributeValue<'a> {
|
|||||||
/// If you want to override the default behavior, you should implement PartialEq through a wrapper type
|
/// If you want to override the default behavior, you should implement PartialEq through a wrapper type
|
||||||
pub trait AnyAttributeValue: Any {
|
pub trait AnyAttributeValue: Any {
|
||||||
/// Perform a comparison between two values
|
/// Perform a comparison between two values
|
||||||
fn cmp_any(&self, _other: &dyn Any) -> bool {
|
fn cmp_any<'a>(&'a self, _other: &'a dyn AnyAttributeValue) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Any + PartialEq> AnyAttributeValue for T {
|
impl<T: Any + PartialEq> AnyAttributeValue for T {
|
||||||
fn cmp_any(&self, other: &dyn Any) -> bool {
|
fn cmp_any(&self, other: &dyn AnyAttributeValue) -> bool {
|
||||||
match other.downcast_ref::<T>() {
|
// we can't, for whatever reason use other as &dyn Any
|
||||||
Some(t) => self == t,
|
let right: &dyn Any = unsafe { std::mem::transmute(other) };
|
||||||
|
|
||||||
|
match right.downcast_ref::<T>() {
|
||||||
|
Some(right) => self == right,
|
||||||
None => false,
|
None => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cmp_any_works_even_though_it_transmutes() {
|
||||||
|
// same type, same value
|
||||||
|
let a = 2;
|
||||||
|
let b = 2;
|
||||||
|
assert!(a.cmp_any(&b as &dyn AnyAttributeValue));
|
||||||
|
|
||||||
|
// same type, different value
|
||||||
|
let a = "asds";
|
||||||
|
let b = "asdsasd";
|
||||||
|
assert!(!a.cmp_any(&b as &dyn AnyAttributeValue));
|
||||||
|
|
||||||
|
// different type, different values
|
||||||
|
let a = 123;
|
||||||
|
let b = "asdsasd";
|
||||||
|
assert!(!a.cmp_any(&b as &dyn AnyAttributeValue));
|
||||||
|
|
||||||
|
// Custom structs
|
||||||
|
#[derive(PartialEq)]
|
||||||
|
struct CustomStruct {
|
||||||
|
a: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
let a = CustomStruct { a: 1 };
|
||||||
|
let b = CustomStruct { a: 1 };
|
||||||
|
assert!(a.cmp_any(&b as &dyn AnyAttributeValue));
|
||||||
|
|
||||||
|
let a = CustomStruct { a: 1 };
|
||||||
|
let b = CustomStruct { a: 123 };
|
||||||
|
assert!(!a.cmp_any(&b as &dyn AnyAttributeValue));
|
||||||
|
|
||||||
|
let a = CustomStruct { a: 1 };
|
||||||
|
let b = "asdasd";
|
||||||
|
assert!(!a.cmp_any(&b as &dyn AnyAttributeValue));
|
||||||
|
}
|
||||||
@@ -70,10 +70,6 @@ pub struct Attribute<'a> {
|
|||||||
/// Used in controlled components to ensure changes are propagated.
|
/// Used in controlled components to ensure changes are propagated.
|
||||||
pub volatile: bool,
|
pub volatile: bool,
|
||||||
|
|
||||||
/// A reverse lookup for tracking down attributes for templates
|
|
||||||
/// Not used for anything else
|
|
||||||
pub mounted_node: Cell<Option<ElementId>>,
|
|
||||||
|
|
||||||
/// The value of the attribute.
|
/// The value of the attribute.
|
||||||
pub value: AttributeValue<'a>,
|
pub value: AttributeValue<'a>,
|
||||||
}
|
}
|
||||||
@@ -83,7 +79,7 @@ pub struct Attribute<'a> {
|
|||||||
pub struct Listener<'bump> {
|
pub struct Listener<'bump> {
|
||||||
/// The ID of the node that this listener is mounted to
|
/// The ID of the node that this listener is mounted to
|
||||||
/// Used to generate the event listener's ID on the DOM
|
/// Used to generate the event listener's ID on the DOM
|
||||||
pub mounted_node: Cell<Option<ElementId>>,
|
pub mounted_node: Cell<ElementId>,
|
||||||
|
|
||||||
/// The type of event to listen for.
|
/// The type of event to listen for.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -108,7 +108,6 @@ impl<'a> NodeFactory<'a> {
|
|||||||
name,
|
name,
|
||||||
namespace,
|
namespace,
|
||||||
volatile: is_volatile,
|
volatile: is_volatile,
|
||||||
mounted_node: Default::default(),
|
|
||||||
value: val.into_value(self.bump),
|
value: val.into_value(self.bump),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -125,7 +124,6 @@ impl<'a> NodeFactory<'a> {
|
|||||||
name,
|
name,
|
||||||
namespace,
|
namespace,
|
||||||
volatile: is_volatile,
|
volatile: is_volatile,
|
||||||
mounted_node: Default::default(),
|
|
||||||
value,
|
value,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -172,7 +170,7 @@ impl<'a> NodeFactory<'a> {
|
|||||||
pub fn listener(self, event: &'static str, callback: InternalHandler<'a>) -> Listener<'a> {
|
pub fn listener(self, event: &'static str, callback: InternalHandler<'a>) -> Listener<'a> {
|
||||||
Listener {
|
Listener {
|
||||||
event,
|
event,
|
||||||
mounted_node: Cell::new(None),
|
mounted_node: Cell::new(ElementId(0)),
|
||||||
callback,
|
callback,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -234,27 +232,20 @@ impl<'a> NodeFactory<'a> {
|
|||||||
/// Create a refrence to a template
|
/// Create a refrence to a template
|
||||||
pub fn template_ref(
|
pub fn template_ref(
|
||||||
&self,
|
&self,
|
||||||
template: fn() -> Template<'static>,
|
template: Template<'static>,
|
||||||
nodes: &'a [VNode<'a>],
|
nodes: &'a [VNode<'a>],
|
||||||
attributes: &'a [Attribute<'a>],
|
attributes: &'a [Attribute<'a>],
|
||||||
listeners: &'a [Listener<'a>],
|
listeners: &'a [Listener<'a>],
|
||||||
key: Option<Arguments>,
|
key: Option<Arguments>,
|
||||||
) -> VNode<'a> {
|
) -> VNode<'a> {
|
||||||
// let borrow_ref = self.scope.templates.borrow();
|
VNode::Template(self.bump.alloc(VTemplate {
|
||||||
// // We only create the template if it doesn't already exist to allow for hot reloading
|
key: None,
|
||||||
// if !borrow_ref.contains_key(&id) {
|
node_id: Cell::new(ElementId(0)),
|
||||||
// drop(borrow_ref);
|
template,
|
||||||
// let mut borrow_mut = self.scope.templates.borrow_mut();
|
dynamic_nodes: self.bump.alloc([]),
|
||||||
// borrow_mut.insert(id.clone(), Rc::new(RefCell::new(template)));
|
dynamic_attrs: self.bump.alloc([]),
|
||||||
// }
|
listeners,
|
||||||
todo!()
|
}))
|
||||||
// VNode::TemplateRef(self.bump.alloc(VTemplate {
|
|
||||||
// dynamic_context,
|
|
||||||
// template_id: id,
|
|
||||||
// node_ids: RefCell::new(Vec::new()),
|
|
||||||
// parent: Cell::new(None),
|
|
||||||
// template_ref_id: Cell::new(None),
|
|
||||||
// }))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ pub struct VFragment<'src> {
|
|||||||
/// The key of the fragment to be used during keyed diffing.
|
/// The key of the fragment to be used during keyed diffing.
|
||||||
pub key: Option<&'src str>,
|
pub key: Option<&'src str>,
|
||||||
|
|
||||||
/// The [`ElementId`] of the placeholder.
|
/// The [`ElementId`] of the placeholder if it exists
|
||||||
pub placeholder: Cell<Option<ElementId>>,
|
pub placeholder: Cell<Option<ElementId>>,
|
||||||
|
|
||||||
/// Fragments can never have zero children. Enforced by NodeFactory.
|
/// Fragments can never have zero children. Enforced by NodeFactory.
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::{Debug, Formatter};
|
||||||
|
|
||||||
mod Placeholder;
|
|
||||||
mod arbitrary_value;
|
mod arbitrary_value;
|
||||||
mod component;
|
mod component;
|
||||||
mod element;
|
mod element;
|
||||||
@@ -25,7 +24,7 @@ pub use suspense::*;
|
|||||||
pub use template::*;
|
pub use template::*;
|
||||||
pub use text::*;
|
pub use text::*;
|
||||||
|
|
||||||
use self::Placeholder::VPlaceholder;
|
use self::placeholder::VPlaceholder;
|
||||||
|
|
||||||
/// A composable "VirtualNode" to declare a User Interface in the Dioxus VirtualDOM.
|
/// A composable "VirtualNode" to declare a User Interface in the Dioxus VirtualDOM.
|
||||||
///
|
///
|
||||||
@@ -117,9 +116,6 @@ pub enum VNode<'src> {
|
|||||||
///
|
///
|
||||||
///
|
///
|
||||||
Template(&'src VTemplate<'src>),
|
Template(&'src VTemplate<'src>),
|
||||||
|
|
||||||
///
|
|
||||||
Placeholder(&'src VPlaceholder),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An Element's unique identifier.
|
/// An Element's unique identifier.
|
||||||
@@ -140,7 +136,6 @@ impl<'src> VNode<'src> {
|
|||||||
VNode::Fragment(f) => f.key,
|
VNode::Fragment(f) => f.key,
|
||||||
VNode::Template(t) => t.key,
|
VNode::Template(t) => t.key,
|
||||||
VNode::Text(_t) => None,
|
VNode::Text(_t) => None,
|
||||||
VNode::Placeholder(_p) => None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,7 +156,6 @@ impl<'src> VNode<'src> {
|
|||||||
VNode::Fragment(_) => None,
|
VNode::Fragment(_) => None,
|
||||||
VNode::Component(_) => None,
|
VNode::Component(_) => None,
|
||||||
VNode::Template(_) => None,
|
VNode::Template(_) => None,
|
||||||
VNode::Placeholder(el) => el.id.get(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,7 +167,6 @@ impl<'src> VNode<'src> {
|
|||||||
VNode::Component(c) => VNode::Component(c),
|
VNode::Component(c) => VNode::Component(c),
|
||||||
VNode::Fragment(f) => VNode::Fragment(f),
|
VNode::Fragment(f) => VNode::Fragment(f),
|
||||||
VNode::Template(t) => VNode::Template(t),
|
VNode::Template(t) => VNode::Template(t),
|
||||||
VNode::Placeholder(p) => VNode::Placeholder(p),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -209,10 +202,6 @@ impl Debug for VNode<'_> {
|
|||||||
.debug_struct("VNode::Templates")
|
.debug_struct("VNode::Templates")
|
||||||
.field("template_id", &temp.template.id)
|
.field("template_id", &temp.template.id)
|
||||||
.finish(),
|
.finish(),
|
||||||
VNode::Placeholder(place) => s
|
|
||||||
.debug_struct("VNode::Placeholder")
|
|
||||||
.field("id", &place.id)
|
|
||||||
.finish(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
|
use crate::ElementId;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
|
||||||
use crate::ElementId;
|
/// A placeholder node
|
||||||
|
|
||||||
pub struct VPlaceholder {
|
pub struct VPlaceholder {
|
||||||
pub id: Cell<Option<ElementId>>,
|
pub id: Cell<Option<ElementId>>,
|
||||||
pub dynamic_index: Option<usize>,
|
pub dynamic_index: Option<usize>,
|
||||||
|
|||||||
@@ -1,16 +1,25 @@
|
|||||||
use std::hash::Hash;
|
use std::{cell::Cell, hash::Hash};
|
||||||
|
|
||||||
use crate::{Attribute, Listener, VNode};
|
use crate::{Attribute, ElementId, Listener, VNode};
|
||||||
|
|
||||||
/// A reference to a template along with any context needed to hydrate it
|
/// A reference to a template along with any context needed to hydrate it
|
||||||
pub struct VTemplate<'a> {
|
pub struct VTemplate<'a> {
|
||||||
pub key: Option<&'a str>,
|
pub key: Option<&'a str>,
|
||||||
|
|
||||||
|
// The ID assigned for all nodes in this template
|
||||||
|
pub node_id: Cell<ElementId>,
|
||||||
|
|
||||||
|
// Position this template for fragments and stuff
|
||||||
|
pub head_id: Cell<ElementId>,
|
||||||
|
|
||||||
|
pub tail_id: Cell<ElementId>,
|
||||||
|
|
||||||
pub template: Template<'static>,
|
pub template: Template<'static>,
|
||||||
|
|
||||||
pub dynamic_nodes: &'a [VNode<'a>],
|
/// All the non-root dynamic nodes
|
||||||
|
pub dynamic_nodes: &'a [NodeLocation<'a>],
|
||||||
|
|
||||||
pub dynamic_attrs: &'a [Attribute<'a>],
|
pub dynamic_attrs: &'a [AttributeLocation<'a>],
|
||||||
|
|
||||||
pub listeners: &'a [Listener<'a>],
|
pub listeners: &'a [Listener<'a>],
|
||||||
}
|
}
|
||||||
@@ -26,13 +35,11 @@ pub struct Template<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Eq for Template<'a> {}
|
impl<'a> Eq for Template<'a> {}
|
||||||
|
|
||||||
impl<'a> PartialEq for Template<'a> {
|
impl<'a> PartialEq for Template<'a> {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.id == other.id
|
self.id == other.id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Hash for Template<'a> {
|
impl<'a> Hash for Template<'a> {
|
||||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
self.id.hash(state);
|
self.id.hash(state);
|
||||||
@@ -41,8 +48,10 @@ impl<'a> Hash for Template<'a> {
|
|||||||
|
|
||||||
/// A weird-ish variant of VNodes with way more limited types
|
/// A weird-ish variant of VNodes with way more limited types
|
||||||
pub enum TemplateNode<'a> {
|
pub enum TemplateNode<'a> {
|
||||||
|
/// A simple element
|
||||||
Element {
|
Element {
|
||||||
tag: &'static str,
|
tag: &'static str,
|
||||||
|
namespace: Option<&'static str>,
|
||||||
attrs: &'a [TemplateAttribute<'a>],
|
attrs: &'a [TemplateAttribute<'a>],
|
||||||
children: &'a [TemplateNode<'a>],
|
children: &'a [TemplateNode<'a>],
|
||||||
},
|
},
|
||||||
@@ -50,8 +59,21 @@ pub enum TemplateNode<'a> {
|
|||||||
Dynamic(usize),
|
Dynamic(usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum TemplateAttribute<'a> {
|
pub struct TemplateAttribute<'a> {
|
||||||
// todo: more values
|
pub name: &'static str,
|
||||||
Static { name: &'static str, value: &'a str },
|
pub value: &'a str,
|
||||||
Dynamic(usize),
|
pub namespace: Option<&'static str>,
|
||||||
|
pub volatile: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AttributeLocation<'a> {
|
||||||
|
pub pathway: &'static [u8],
|
||||||
|
pub mounted_element: Cell<ElementId>,
|
||||||
|
pub attrs: &'a [Attribute<'a>],
|
||||||
|
pub listeners: &'a [Listener<'a>],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct NodeLocation<'a> {
|
||||||
|
pub pathway: &'static [u8],
|
||||||
|
pub node: VNode<'a>,
|
||||||
}
|
}
|
||||||
@@ -1,15 +1,5 @@
|
|||||||
use crate::{
|
use crate::ElementId;
|
||||||
innerlude::{
|
use std::cell::Cell;
|
||||||
AttributeValue, ComponentPtr, Element, IntoAttributeValue, Properties, Scope, ScopeId,
|
|
||||||
ScopeState, Template,
|
|
||||||
},
|
|
||||||
AnyEvent, Component, ElementId,
|
|
||||||
};
|
|
||||||
use bumpalo::{boxed::Box as BumpBox, Bump};
|
|
||||||
use std::{
|
|
||||||
cell::{Cell, RefCell},
|
|
||||||
fmt::{Arguments, Debug, Formatter},
|
|
||||||
};
|
|
||||||
|
|
||||||
/// A bump-allocated string slice and metadata.
|
/// A bump-allocated string slice and metadata.
|
||||||
pub struct VText<'src> {
|
pub struct VText<'src> {
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ use std::{collections::VecDeque, iter::FromIterator, task::Poll};
|
|||||||
|
|
||||||
/// A virtual node system that progresses user events and diffs UI trees.
|
/// A virtual node system that progresses user events and diffs UI trees.
|
||||||
///
|
///
|
||||||
///
|
|
||||||
/// ## Guide
|
/// ## Guide
|
||||||
///
|
///
|
||||||
/// Components are defined as simple functions that take [`Scope`] and return an [`Element`].
|
/// Components are defined as simple functions that take [`Scope`] and return an [`Element`].
|
||||||
@@ -505,6 +504,13 @@ impl VirtualDom {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Run the virtualdom, waiting for all async components to finish rendering
|
||||||
|
///
|
||||||
|
/// As they finish rendering, the virtualdom will apply the mutations to the renderer.
|
||||||
|
pub async fn render(&mut self, renderer: &mut impl Renderer<'_>) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
/// Performs a *full* rebuild of the virtual dom, returning every edit required to generate the actual dom from scratch.
|
/// Performs a *full* rebuild of the virtual dom, returning every edit required to generate the actual dom from scratch.
|
||||||
///
|
///
|
||||||
/// The diff machine expects the RealDom's stack to be the root of the application.
|
/// The diff machine expects the RealDom's stack to be the root of the application.
|
||||||
|
|||||||
@@ -1,87 +1,44 @@
|
|||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
use dioxus_core::{Attribute, TemplateAttribute};
|
use dioxus_core::{Attribute, TemplateAttribute};
|
||||||
|
use dioxus_edit_stream::*;
|
||||||
|
|
||||||
fn basic_syntax_is_a_template(cx: Scope) -> Element {
|
fn basic_syntax_is_a_template(cx: Scope) -> Element {
|
||||||
let asd = 123;
|
let asd = 123;
|
||||||
|
let var = 123;
|
||||||
|
|
||||||
let g = rsx! {
|
cx.render(rsx! {
|
||||||
div {
|
div { class: "asd", class: "{asd}",
|
||||||
class: "asd",
|
onclick: move |_| {},
|
||||||
// class: "{asd}",
|
div { "{var}" }
|
||||||
// onclick: move |_| {},
|
div {
|
||||||
// div { "{var}" }
|
h1 { "var" }
|
||||||
|
p { "you're great!" }
|
||||||
|
div {
|
||||||
|
background_color: "red",
|
||||||
|
h1 { "var" }
|
||||||
|
div {
|
||||||
|
b { "asd" }
|
||||||
|
"not great"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p { "you're great!" }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
})
|
||||||
|
}
|
||||||
|
|
||||||
let __cx = NodeFactory::new(&cx);
|
fn basic_template(cx: Scope) -> Element {
|
||||||
|
cx.render(rsx! {
|
||||||
|
div {"hi!"}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
static attrs: &'static [TemplateAttribute<'static>] =
|
#[test]
|
||||||
&[::dioxus::core::TemplateAttribute::Static(
|
fn basic_prints() {
|
||||||
::dioxus::core::Attribute {
|
let dom = VirtualDom::new(basic_template);
|
||||||
name: "class",
|
|
||||||
namespace: None,
|
|
||||||
volatile: false,
|
|
||||||
mounted_node: Default::default(),
|
|
||||||
value: ::dioxus::core::AttributeValue::Text("asd"),
|
|
||||||
},
|
|
||||||
)];
|
|
||||||
|
|
||||||
__cx . template_ref (
|
let renderer = dioxus_edit_stream::Mutations::default();
|
||||||
|| :: dioxus :: core :: Template {
|
dom.rebuild(&mut renderer);
|
||||||
id : "packages/dioxus/tests/rsx_syntax.rs:7:13:/Users/jonkelley/Development/dioxus/packages/dioxus" ,
|
|
||||||
roots : &[
|
|
||||||
:: dioxus :: core :: TemplateNode :: Element {
|
|
||||||
tag : dioxus_elements :: div :: TAG_NAME ,
|
|
||||||
attrs : attrs,
|
|
||||||
children : & [] ,
|
|
||||||
}] ,
|
|
||||||
} ,
|
|
||||||
__cx . bump () . alloc ([]) , __cx . bump () . alloc ([]) , __cx . bump () . alloc ([]) ,
|
|
||||||
None
|
|
||||||
);
|
|
||||||
|
|
||||||
// let static_attr = ::dioxus::core::TemplateAttribute::Static(::dioxus::core::Attribute {
|
dbg!(renderer.edits);
|
||||||
// name: "class",
|
|
||||||
// namespace: None,
|
|
||||||
// volatile: false,
|
|
||||||
// mounted_node: Default::default(),
|
|
||||||
// value: ::dioxus::core::AttributeValue::Text("asd"),
|
|
||||||
// });
|
|
||||||
|
|
||||||
// __cx . template_ref (|| :: dioxus :: core :: Template { id : "packages/dioxus/tests/rsx_syntax.rs:7:13:/Users/jonkelley/Development/dioxus/packages/dioxus" , roots : & [:: dioxus :: core :: TemplateNode :: Element { tag : dioxus_elements :: div :: TAG_NAME , attrs : & [static_attr , :: dioxus :: core :: TemplateAttribute :: Dynamic (0usize)] , children : & [] , }] , } , __cx . bump () . alloc ([]) , __cx . bump () . alloc ([__cx . attr (dioxus_elements :: div :: class . 0 , :: core :: fmt :: Arguments :: new_v1 (& [""] , & [:: core :: fmt :: ArgumentV1 :: new_display (& asd)]) , None , false)]) , __cx . bump () . alloc ([]) , None);
|
|
||||||
|
|
||||||
cx.render(g)
|
|
||||||
|
|
||||||
// let __cx = NodeFactory::new(&cx);
|
|
||||||
|
|
||||||
// let t = __cx.template_ref (
|
|
||||||
// || :: dioxus :: core :: Template {
|
|
||||||
// id : "packages/dioxus/tests/rsx_syntax.rs:8:13:/Users/jonkelley/Development/dioxus/packages/dioxus" ,
|
|
||||||
// roots : & [
|
|
||||||
// :: dioxus :: core :: TemplateNode :: Element {
|
|
||||||
// tag : dioxus_elements :: div :: TAG_NAME ,
|
|
||||||
// attrs : & [:: dioxus :: core :: TemplateAttribute :: Dynamic (0usize)] ,
|
|
||||||
// children : & [] ,
|
|
||||||
// }
|
|
||||||
// ],
|
|
||||||
// },
|
|
||||||
// &[] ,
|
|
||||||
// {
|
|
||||||
// let mut arr = dioxus_core::exports::bumpalo::vec![in __cx.bump()];
|
|
||||||
// arr.push(Attribute {
|
|
||||||
// name: "asd",
|
|
||||||
// namespace: None,
|
|
||||||
// volatile: false,
|
|
||||||
// mounted_node: Default::default(),
|
|
||||||
// value: dioxus_core::AttributeValue::Text(
|
|
||||||
// __cx.raw_text(format_args!("{asd}")).0
|
|
||||||
// ),
|
|
||||||
// });
|
|
||||||
// arr.into_bump_slice() as &[::dioxus::core::Attribute]
|
|
||||||
// },
|
|
||||||
// & [] ,
|
|
||||||
// None
|
|
||||||
// );
|
|
||||||
|
|
||||||
// Some(t)
|
|
||||||
}
|
}
|
||||||
+356
-376
@@ -1,378 +1,358 @@
|
|||||||
use dioxus_core::*;
|
use dioxus_core::*;
|
||||||
|
|
||||||
// /// ## Mutations
|
/// ## Mutations
|
||||||
// ///
|
///
|
||||||
// /// This method returns "mutations" - IE the necessary changes to get the RealDOM to match the VirtualDOM. It also
|
/// 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
|
/// includes a list of NodeRefs that need to be applied and effects that need to be triggered after the RealDOM has
|
||||||
// /// applied the edits.
|
/// applied the edits.
|
||||||
// ///
|
///
|
||||||
// /// Mutations are the only link between the RealDOM and the VirtualDOM.
|
/// Mutations are the only link between the RealDOM and the VirtualDOM.
|
||||||
// pub struct Mutations<'a> {
|
#[derive(Default)]
|
||||||
// /// The list of edits that need to be applied for the RealDOM to match the VirtualDOM.
|
pub struct Mutations<'a> {
|
||||||
// pub edits: Vec<DomEdit<'a>>,
|
/// The list of edits that need to be applied for the RealDOM to match the VirtualDOM.
|
||||||
|
pub edits: Vec<DomEdit<'a>>,
|
||||||
// /// The list of Scopes that were diffed, created, and removed during the Diff process.
|
|
||||||
// pub dirty_scopes: FxHashSet<ScopeId>,
|
/// The list of Scopes that were diffed, created, and removed during the Diff process.
|
||||||
|
pub dirty_scopes: Vec<ScopeId>,
|
||||||
// /// The list of nodes to connect to the RealDOM.
|
}
|
||||||
// pub refs: Vec<NodeRefMutation<'a>>,
|
|
||||||
// }
|
/// A `DomEdit` represents a serialized form of the VirtualDom's trait-based API. This allows streaming edits across the
|
||||||
|
/// network or through FFI boundaries.
|
||||||
// impl Debug for Mutations<'_> {
|
#[derive(Debug, PartialEq)]
|
||||||
// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
#[cfg_attr(
|
||||||
// f.debug_struct("Mutations")
|
feature = "serialize",
|
||||||
// .field("edits", &self.edits)
|
derive(serde::Serialize, serde::Deserialize),
|
||||||
// .field("noderefs", &self.refs)
|
serde(tag = "type")
|
||||||
// .finish()
|
)]
|
||||||
// }
|
pub enum DomEdit<'bump> {
|
||||||
// }
|
/// Push the given root node onto our stack.
|
||||||
|
PushRoot {
|
||||||
// /// A `DomEdit` represents a serialized form of the VirtualDom's trait-based API. This allows streaming edits across the
|
/// The ID of the root node to push.
|
||||||
// /// network or through FFI boundaries.
|
root: ElementId,
|
||||||
// #[derive(Debug, PartialEq)]
|
},
|
||||||
// #[cfg_attr(
|
|
||||||
// feature = "serialize",
|
/// Pop the topmost node from our stack and append them to the node
|
||||||
// derive(serde::Serialize, serde::Deserialize),
|
/// at the top of the stack.
|
||||||
// serde(tag = "type")
|
AppendChildren {
|
||||||
// )]
|
/// How many nodes should be popped from the stack.
|
||||||
// pub enum DomEdit<'bump> {
|
/// The node remaining on the stack will be the target for the append.
|
||||||
// /// Push the given root node onto our stack.
|
many: u32,
|
||||||
// PushRoot {
|
},
|
||||||
// /// The ID of the root node to push.
|
|
||||||
// root: ElementId,
|
/// Replace a given (single) node with a handful of nodes currently on the stack.
|
||||||
// },
|
ReplaceWith {
|
||||||
|
/// The ID of the node to be replaced.
|
||||||
// /// Pop the topmost node from our stack and append them to the node
|
root: ElementId,
|
||||||
// /// at the top of the stack.
|
|
||||||
// AppendChildren {
|
/// How many nodes should be popped from the stack to replace the target node.
|
||||||
// /// How many nodes should be popped from the stack.
|
m: u32,
|
||||||
// /// The node remaining on the stack will be the target for the append.
|
},
|
||||||
// many: u32,
|
|
||||||
// },
|
/// Insert a number of nodes after a given node.
|
||||||
|
InsertAfter {
|
||||||
// /// Replace a given (single) node with a handful of nodes currently on the stack.
|
/// The ID of the node to insert after.
|
||||||
// ReplaceWith {
|
root: ElementId,
|
||||||
// /// The ID of the node to be replaced.
|
|
||||||
// root: ElementId,
|
/// How many nodes should be popped from the stack to insert after the target node.
|
||||||
|
n: u32,
|
||||||
// /// How many nodes should be popped from the stack to replace the target node.
|
},
|
||||||
// m: u32,
|
|
||||||
// },
|
/// Insert a number of nodes before a given node.
|
||||||
|
InsertBefore {
|
||||||
// /// Insert a number of nodes after a given node.
|
/// The ID of the node to insert before.
|
||||||
// InsertAfter {
|
root: ElementId,
|
||||||
// /// The ID of the node to insert after.
|
|
||||||
// root: ElementId,
|
/// How many nodes should be popped from the stack to insert before the target node.
|
||||||
|
n: u32,
|
||||||
// /// How many nodes should be popped from the stack to insert after the target node.
|
},
|
||||||
// n: u32,
|
|
||||||
// },
|
/// Remove a particular node from the DOM
|
||||||
|
Remove {
|
||||||
// /// Insert a number of nodes before a given node.
|
/// The ID of the node to remove.
|
||||||
// InsertBefore {
|
root: ElementId,
|
||||||
// /// The ID of the node to insert before.
|
},
|
||||||
// root: ElementId,
|
|
||||||
|
/// Create a new purely-text node
|
||||||
// /// How many nodes should be popped from the stack to insert before the target node.
|
CreateTextNode {
|
||||||
// n: u32,
|
/// The ID the new node should have.
|
||||||
// },
|
root: ElementId,
|
||||||
|
|
||||||
// /// Remove a particular node from the DOM
|
/// The textcontent of the node
|
||||||
// Remove {
|
text: &'bump str,
|
||||||
// /// The ID of the node to remove.
|
},
|
||||||
// root: ElementId,
|
|
||||||
// },
|
/// Create a new purely-element node
|
||||||
|
CreateElement {
|
||||||
// /// Create a new purely-text node
|
/// The ID the new node should have.
|
||||||
// CreateTextNode {
|
root: ElementId,
|
||||||
// /// The ID the new node should have.
|
|
||||||
// root: ElementId,
|
/// The tagname of the node
|
||||||
|
tag: &'bump str,
|
||||||
// /// The textcontent of the node
|
},
|
||||||
// text: &'bump str,
|
|
||||||
// },
|
/// Create a new purely-comment node with a given namespace
|
||||||
|
CreateElementNs {
|
||||||
// /// Create a new purely-element node
|
/// The ID the new node should have.
|
||||||
// CreateElement {
|
root: ElementId,
|
||||||
// /// The ID the new node should have.
|
|
||||||
// root: ElementId,
|
/// The namespace of the node
|
||||||
|
tag: &'bump str,
|
||||||
// /// The tagname of the node
|
|
||||||
// tag: &'bump str,
|
/// The namespace of the node (like `SVG`)
|
||||||
// },
|
ns: &'static str,
|
||||||
|
},
|
||||||
// /// Create a new purely-comment node with a given namespace
|
|
||||||
// CreateElementNs {
|
/// Create a new placeholder node.
|
||||||
// /// The ID the new node should have.
|
/// In most implementations, this will either be a hidden div or a comment node.
|
||||||
// root: ElementId,
|
CreatePlaceholder {
|
||||||
|
/// The ID the new node should have.
|
||||||
// /// The namespace of the node
|
root: ElementId,
|
||||||
// tag: &'bump str,
|
},
|
||||||
|
|
||||||
// /// The namespace of the node (like `SVG`)
|
/// Create a new Event Listener.
|
||||||
// ns: &'static str,
|
NewEventListener {
|
||||||
// },
|
/// The name of the event to listen for.
|
||||||
|
event_name: &'static str,
|
||||||
// /// Create a new placeholder node.
|
|
||||||
// /// In most implementations, this will either be a hidden div or a comment node.
|
/// The ID of the node to attach the listener to.
|
||||||
// CreatePlaceholder {
|
scope: ScopeId,
|
||||||
// /// The ID the new node should have.
|
|
||||||
// root: ElementId,
|
/// The ID of the node to attach the listener to.
|
||||||
// },
|
root: ElementId,
|
||||||
|
},
|
||||||
// /// Create a new Event Listener.
|
|
||||||
// NewEventListener {
|
/// Remove an existing Event Listener.
|
||||||
// /// The name of the event to listen for.
|
RemoveEventListener {
|
||||||
// event_name: &'static str,
|
/// The ID of the node to remove.
|
||||||
|
root: ElementId,
|
||||||
// /// The ID of the node to attach the listener to.
|
|
||||||
// scope: ScopeId,
|
/// The name of the event to remove.
|
||||||
|
event: &'static str,
|
||||||
// /// The ID of the node to attach the listener to.
|
},
|
||||||
// root: ElementId,
|
|
||||||
// },
|
/// Set the textcontent of a node.
|
||||||
|
SetText {
|
||||||
// /// Remove an existing Event Listener.
|
/// The ID of the node to set the textcontent of.
|
||||||
// RemoveEventListener {
|
root: ElementId,
|
||||||
// /// The ID of the node to remove.
|
|
||||||
// root: ElementId,
|
/// The textcontent of the node
|
||||||
|
text: &'bump str,
|
||||||
// /// The name of the event to remove.
|
},
|
||||||
// event: &'static str,
|
|
||||||
// },
|
/// Set the value of a node's attribute.
|
||||||
|
SetAttribute {
|
||||||
// /// Set the textcontent of a node.
|
/// The ID of the node to set the attribute of.
|
||||||
// SetText {
|
root: ElementId,
|
||||||
// /// The ID of the node to set the textcontent of.
|
|
||||||
// root: ElementId,
|
/// The name of the attribute to set.
|
||||||
|
field: &'static str,
|
||||||
// /// The textcontent of the node
|
|
||||||
// text: &'bump str,
|
/// The value of the attribute.
|
||||||
// },
|
value: AttributeValue<'bump>,
|
||||||
|
|
||||||
// /// Set the value of a node's attribute.
|
// value: &'bump str,
|
||||||
// SetAttribute {
|
/// The (optional) namespace of the attribute.
|
||||||
// /// The ID of the node to set the attribute of.
|
/// For instance, "style" is in the "style" namespace.
|
||||||
// root: ElementId,
|
ns: Option<&'bump str>,
|
||||||
|
},
|
||||||
// /// The name of the attribute to set.
|
|
||||||
// field: &'static str,
|
/// Remove an attribute from a node.
|
||||||
|
RemoveAttribute {
|
||||||
// /// The value of the attribute.
|
/// The ID of the node to remove.
|
||||||
// value: AttributeValue<'bump>,
|
root: ElementId,
|
||||||
|
|
||||||
// // value: &'bump str,
|
/// The name of the attribute to remove.
|
||||||
// /// The (optional) namespace of the attribute.
|
name: &'static str,
|
||||||
// /// For instance, "style" is in the "style" namespace.
|
|
||||||
// ns: Option<&'bump str>,
|
/// The namespace of the attribute.
|
||||||
// },
|
ns: Option<&'bump str>,
|
||||||
|
},
|
||||||
// /// Remove an attribute from a node.
|
|
||||||
// RemoveAttribute {
|
/// Manually pop a root node from the stack.
|
||||||
// /// The ID of the node to remove.
|
PopRoot {
|
||||||
// root: ElementId,
|
/// The amount of nodes to pop
|
||||||
|
count: u32,
|
||||||
// /// The name of the attribute to remove.
|
},
|
||||||
// name: &'static str,
|
|
||||||
|
/// Remove all the children of an element
|
||||||
// /// The namespace of the attribute.
|
RemoveChildren {
|
||||||
// ns: Option<&'bump str>,
|
/// The root
|
||||||
// },
|
root: ElementId,
|
||||||
|
},
|
||||||
// /// Manually pop a root node from the stack.
|
|
||||||
// PopRoot {
|
/*
|
||||||
// /// The amount of nodes to pop
|
|
||||||
// count: u32,
|
Template stuff
|
||||||
// },
|
|
||||||
|
- load into scratch space
|
||||||
// /// Remove all the children of an element
|
- dump nodes into stack
|
||||||
// RemoveChildren {
|
- assign ids of nodes in template
|
||||||
// /// The root
|
|
||||||
// root: ElementId,
|
*/
|
||||||
// },
|
/// Create a template using the nodes on the stack
|
||||||
|
Save {
|
||||||
// /// Create a template using the nodes on the stack
|
/// The ID of the template
|
||||||
// StoreTemplate {
|
name: &'static str,
|
||||||
// /// The ID of the template
|
|
||||||
// name: &'static str,
|
/// The amount of nodes to pop from the stack into the template
|
||||||
|
num_children: u32,
|
||||||
// /// The amount of nodes to pop from the stack into the template
|
},
|
||||||
// num_children: u32,
|
|
||||||
|
/// Load the template into a scratch space on the stack
|
||||||
// /// Indicies for the nodes to pop from the stack into the template
|
///
|
||||||
// dynamic_nodes: &'static [&'static [u32]],
|
/// The template body now lives on the stack, but needs to be finished before its nodes can be appended to the DOM.
|
||||||
// },
|
Load {
|
||||||
|
/// The ID of the template
|
||||||
// /// Load the template onto the stack
|
name: &'static str,
|
||||||
// LoadTemplate {
|
|
||||||
// /// The ID of the template
|
id: u32,
|
||||||
// name: &'static str,
|
},
|
||||||
|
|
||||||
// /// The index of the template body
|
AssignId {
|
||||||
// index: u32,
|
index: &'static str,
|
||||||
|
id: ElementId,
|
||||||
// /// Give the node a new ID to remove it later
|
},
|
||||||
// root: ElementId,
|
|
||||||
// },
|
ReplaceDescendant {
|
||||||
|
index: &'static str,
|
||||||
// /// Load n nodes into the kth dynamic node of the template
|
m: u32,
|
||||||
// ///
|
},
|
||||||
// /// Assumes that the template is already on the stack
|
}
|
||||||
// MergeTemplate {
|
|
||||||
// /// The index of the dynamic node to merge into
|
use DomEdit::*;
|
||||||
// index: u32,
|
|
||||||
|
impl<'a> dioxus_core::Renderer<'a> for Mutations<'a> {
|
||||||
// /// The amount of nodes to pop from the stack into the template
|
// Navigation
|
||||||
// num_children: u32,
|
fn push_root(&mut self, root: ElementId) {
|
||||||
// },
|
self.edits.push(PushRoot { root });
|
||||||
// }
|
}
|
||||||
|
|
||||||
// use DomEdit::*;
|
// Navigation
|
||||||
|
fn pop_root(&mut self) {
|
||||||
// impl<'a> Mutations<'a> {
|
self.edits.push(PopRoot { count: 1 });
|
||||||
// pub(crate) fn new() -> Self {
|
}
|
||||||
// Self {
|
|
||||||
// edits: Vec::new(),
|
fn replace_with(&mut self, root: ElementId, m: u32) {
|
||||||
// refs: Vec::new(),
|
self.edits.push(ReplaceWith { m, root });
|
||||||
// dirty_scopes: Default::default(),
|
}
|
||||||
// }
|
|
||||||
// }
|
fn replace_descendant(&mut self, descendent: &'static [u8], m: u32) {
|
||||||
|
self.edits.push(ReplaceDescendant {
|
||||||
// // Navigation
|
// serializing is just hijacking ascii
|
||||||
// pub(crate) fn push_root(&mut self, root: ElementId) {
|
index: unsafe { std::str::from_utf8_unchecked(descendent) },
|
||||||
// self.edits.push(PushRoot { root });
|
m,
|
||||||
// }
|
});
|
||||||
|
}
|
||||||
// // Navigation
|
|
||||||
// pub(crate) fn pop_root(&mut self) {
|
fn insert_after(&mut self, root: ElementId, n: u32) {
|
||||||
// self.edits.push(PopRoot { count: 1 });
|
self.edits.push(InsertAfter { n, root });
|
||||||
// }
|
}
|
||||||
|
|
||||||
// pub(crate) fn replace_with(&mut self, root: ElementId, m: u32) {
|
fn insert_before(&mut self, root: ElementId, n: u32) {
|
||||||
// self.edits.push(ReplaceWith { m, root });
|
self.edits.push(InsertBefore { n, root });
|
||||||
// }
|
}
|
||||||
|
|
||||||
// pub(crate) fn insert_after(&mut self, root: ElementId, n: u32) {
|
fn append_children(&mut self, n: u32) {
|
||||||
// self.edits.push(InsertAfter { n, root });
|
self.edits.push(AppendChildren { many: n });
|
||||||
// }
|
}
|
||||||
|
|
||||||
// pub(crate) fn insert_before(&mut self, root: ElementId, n: u32) {
|
// Create
|
||||||
// self.edits.push(InsertBefore { n, root });
|
fn create_text_node(&mut self, text: &'a str, root: ElementId) {
|
||||||
// }
|
self.edits.push(CreateTextNode { text, root });
|
||||||
|
}
|
||||||
// pub(crate) fn append_children(&mut self, n: u32) {
|
|
||||||
// self.edits.push(AppendChildren { many: n });
|
fn create_element(&mut self, tag: &'static str, ns: Option<&'static str>, id: ElementId) {
|
||||||
// }
|
match ns {
|
||||||
|
Some(ns) => self.edits.push(CreateElementNs { root: id, ns, tag }),
|
||||||
// // Remove Nodes from the dom
|
None => self.edits.push(CreateElement { root: id, tag }),
|
||||||
// pub(crate) fn remove(&mut self, root: ElementId) {
|
}
|
||||||
// self.edits.push(Remove { root });
|
}
|
||||||
// }
|
|
||||||
|
// placeholders are nodes that don't get rendered but still exist as an "anchor" in the real dom
|
||||||
// // Create
|
fn create_placeholder(&mut self, id: ElementId) {
|
||||||
// pub(crate) fn create_text_node(&mut self, text: &'a str, root: ElementId) {
|
self.edits.push(CreatePlaceholder { root: id });
|
||||||
// self.edits.push(CreateTextNode { text, root });
|
}
|
||||||
// }
|
|
||||||
|
fn assign_id(&mut self, descendent: &'static [u8], id: ElementId) {
|
||||||
// pub(crate) fn create_element(
|
self.edits.push(AssignId {
|
||||||
// &mut self,
|
index: unsafe { std::str::from_utf8_unchecked(descendent) },
|
||||||
// tag: &'static str,
|
id,
|
||||||
// ns: Option<&'static str>,
|
});
|
||||||
// id: ElementId,
|
}
|
||||||
// ) {
|
|
||||||
// match ns {
|
// Remove Nodes from the dom
|
||||||
// Some(ns) => self.edits.push(CreateElementNs { root: id, ns, tag }),
|
fn remove(&mut self, root: ElementId) {
|
||||||
// None => self.edits.push(CreateElement { root: id, tag }),
|
self.edits.push(Remove { root });
|
||||||
// }
|
}
|
||||||
// }
|
|
||||||
// // placeholders are nodes that don't get rendered but still exist as an "anchor" in the real dom
|
fn remove_attribute(&mut self, attribute: &Attribute, root: ElementId) {
|
||||||
// pub(crate) fn create_placeholder(&mut self, id: ElementId) {
|
self.edits.push(RemoveAttribute {
|
||||||
// self.edits.push(CreatePlaceholder { root: id });
|
name: attribute.name,
|
||||||
// }
|
ns: attribute.namespace,
|
||||||
|
root,
|
||||||
// // events
|
});
|
||||||
// pub(crate) fn new_event_listener(&mut self, listener: &Listener, scope: ScopeId) {
|
}
|
||||||
// let Listener {
|
|
||||||
// event,
|
// events
|
||||||
// mounted_node,
|
fn new_event_listener(&mut self, listener: &Listener, scope: ScopeId) {
|
||||||
// ..
|
let Listener {
|
||||||
// } = listener;
|
event,
|
||||||
|
mounted_node,
|
||||||
// let element_id = mounted_node.get().unwrap();
|
..
|
||||||
|
} = listener;
|
||||||
// self.edits.push(NewEventListener {
|
|
||||||
// scope,
|
let element_id = mounted_node.get();
|
||||||
// event_name: event,
|
|
||||||
// root: element_id,
|
self.edits.push(NewEventListener {
|
||||||
// });
|
scope,
|
||||||
// }
|
event_name: event,
|
||||||
// pub(crate) fn remove_event_listener(&mut self, event: &'static str, root: ElementId) {
|
root: element_id,
|
||||||
// self.edits.push(RemoveEventListener { event, root });
|
});
|
||||||
// }
|
}
|
||||||
|
|
||||||
// // modify
|
fn remove_event_listener(&mut self, event: &'static str, root: ElementId) {
|
||||||
// pub(crate) fn set_text(&mut self, text: &'a str, root: ElementId) {
|
self.edits.push(RemoveEventListener { event, root });
|
||||||
// self.edits.push(SetText { text, root });
|
}
|
||||||
// }
|
|
||||||
|
// modify
|
||||||
// pub(crate) fn set_attribute(&mut self, attribute: &'a Attribute<'a>, root: ElementId) {
|
fn set_text(&mut self, text: &'a str, root: ElementId) {
|
||||||
// let Attribute {
|
self.edits.push(SetText { text, root });
|
||||||
// name,
|
}
|
||||||
// value,
|
|
||||||
// namespace,
|
fn save(&mut self, id: &'static str, num: u32) {
|
||||||
// ..
|
self.edits.push(Save {
|
||||||
// } = attribute;
|
name: id,
|
||||||
|
num_children: num,
|
||||||
// self.edits.push(SetAttribute {
|
});
|
||||||
// field: name,
|
}
|
||||||
// value: value.clone(),
|
|
||||||
// ns: *namespace,
|
fn load(&mut self, id: &'static str, index: u32) {
|
||||||
// root,
|
self.edits.push(Load {
|
||||||
// });
|
name: id,
|
||||||
// }
|
id: index,
|
||||||
|
});
|
||||||
// pub(crate) fn remove_attribute(&mut self, attribute: &Attribute, root: ElementId) {
|
}
|
||||||
// let Attribute {
|
|
||||||
// name, namespace, ..
|
fn mark_dirty_scope(&mut self, scope: ScopeId) {
|
||||||
// } = attribute;
|
self.dirty_scopes.push(scope);
|
||||||
|
}
|
||||||
// self.edits.push(RemoveAttribute {
|
|
||||||
// name,
|
fn set_attribute(
|
||||||
// ns: *namespace,
|
&mut self,
|
||||||
// root,
|
name: &'static str,
|
||||||
// });
|
value: AttributeValue<'a>,
|
||||||
// }
|
namespace: Option<&'a str>,
|
||||||
|
root: ElementId,
|
||||||
// pub(crate) fn mark_dirty_scope(&mut self, scope: ScopeId) {
|
) {
|
||||||
// self.dirty_scopes.insert(scope);
|
self.edits.push(SetAttribute {
|
||||||
// }
|
field: name,
|
||||||
// }
|
value: value.clone(),
|
||||||
|
ns: namespace,
|
||||||
// // refs are only assigned once
|
root,
|
||||||
// pub struct NodeRefMutation<'a> {
|
});
|
||||||
// pub element: &'a mut Option<once_cell::sync::OnceCell<Box<dyn Any>>>,
|
}
|
||||||
// pub element_id: ElementId,
|
|
||||||
// }
|
fn remove_children(&mut self, element: ElementId) {
|
||||||
|
todo!()
|
||||||
// impl<'a> std::fmt::Debug for NodeRefMutation<'a> {
|
}
|
||||||
// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
}
|
||||||
// f.debug_struct("NodeRefMutation")
|
|
||||||
// .field("element_id", &self.element_id)
|
|
||||||
// .finish()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 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>())
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
@@ -10,6 +10,7 @@ macro_rules! no_namespace_trait_methods {
|
|||||||
)*
|
)*
|
||||||
) => {
|
) => {
|
||||||
$(
|
$(
|
||||||
|
$(#[$attr])*
|
||||||
const $name: AttributeDiscription = (
|
const $name: AttributeDiscription = (
|
||||||
stringify!($name),
|
stringify!($name),
|
||||||
None,
|
None,
|
||||||
@@ -26,6 +27,7 @@ macro_rules! style_trait_methods {
|
|||||||
)*
|
)*
|
||||||
) => {
|
) => {
|
||||||
$(
|
$(
|
||||||
|
$(#[$attr])*
|
||||||
const $name: AttributeDiscription = (
|
const $name: AttributeDiscription = (
|
||||||
$lit,
|
$lit,
|
||||||
Some("style"),
|
Some("style"),
|
||||||
@@ -42,6 +44,7 @@ macro_rules! aria_trait_methods {
|
|||||||
)*
|
)*
|
||||||
) => {
|
) => {
|
||||||
$(
|
$(
|
||||||
|
$(#[$attr])*
|
||||||
const $name: AttributeDiscription = (
|
const $name: AttributeDiscription = (
|
||||||
$lit,
|
$lit,
|
||||||
None,
|
None,
|
||||||
|
|||||||
+29
-27
@@ -83,41 +83,39 @@ impl ToTokens for CallBody {
|
|||||||
fn render_static_node<'a>(root: &'a BodyNode, cx: &mut DynamicContext<'a>) -> TokenStream2 {
|
fn render_static_node<'a>(root: &'a BodyNode, cx: &mut DynamicContext<'a>) -> TokenStream2 {
|
||||||
match root {
|
match root {
|
||||||
BodyNode::Element(el) => {
|
BodyNode::Element(el) => {
|
||||||
let name = &el.name;
|
let el_name = &el.name;
|
||||||
|
|
||||||
let children = {
|
let children = {
|
||||||
let children = el.children.iter().map(|root| render_static_node(root, cx));
|
let children = el.children.iter().map(|root| render_static_node(root, cx));
|
||||||
quote! { #(#children),* }
|
quote! { #(#children),* }
|
||||||
};
|
};
|
||||||
|
|
||||||
let attrs = el.attributes.iter().map(|attr| {
|
let attrs = el.attributes.iter().filter_map(|attr| {
|
||||||
//
|
//
|
||||||
match &attr.attr {
|
match &attr.attr {
|
||||||
ElementAttr::AttrText { name, value } if value.is_static() => {
|
ElementAttr::AttrText { name, value } if value.is_static() => {
|
||||||
let value = value.source.as_ref().unwrap();
|
let value = value.source.as_ref().unwrap();
|
||||||
quote! {
|
Some(quote! {
|
||||||
::dioxus::core::TemplateAttribute::Static(::dioxus::core::Attribute {
|
::dioxus::core::TemplateAttribute {
|
||||||
name: stringify!(#name),
|
name: dioxus_elements::#el_name::#name.0,
|
||||||
namespace: None,
|
namespace: dioxus_elements::#el_name::#name.1,
|
||||||
volatile: false,
|
volatile: dioxus_elements::#el_name::#name.2,
|
||||||
mounted_node: Default::default(),
|
value: #value,
|
||||||
value: ::dioxus::core::AttributeValue::Text(#value),
|
}
|
||||||
})
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ElementAttr::CustomAttrText { name, value } if value.is_static() => {
|
ElementAttr::CustomAttrText { name, value } if value.is_static() => {
|
||||||
let value = value.source.as_ref().unwrap();
|
let value = value.source.as_ref().unwrap();
|
||||||
quote! {
|
Some(quote! {
|
||||||
::dioxus::core::TemplateAttribute::Static(::dioxus::core::Attribute {
|
::dioxus::core::TemplateAttribute {
|
||||||
name: stringify!(#name),
|
name: dioxus_elements::#el_name::#name.0,
|
||||||
namespace: None,
|
namespace: dioxus_elements::#el_name::#name.1,
|
||||||
volatile: false,
|
volatile: dioxus_elements::#el_name::#name.2,
|
||||||
mounted_node: Default::default(),
|
value: #value,
|
||||||
value: ::dioxus::core::AttributeValue::Text(#value),
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
|
||||||
ElementAttr::AttrExpression { .. }
|
ElementAttr::AttrExpression { .. }
|
||||||
| ElementAttr::AttrText { .. }
|
| ElementAttr::AttrText { .. }
|
||||||
@@ -125,20 +123,24 @@ impl ToTokens for CallBody {
|
|||||||
| ElementAttr::CustomAttrExpression { .. } => {
|
| ElementAttr::CustomAttrExpression { .. } => {
|
||||||
let ct = cx.dynamic_attributes.len();
|
let ct = cx.dynamic_attributes.len();
|
||||||
cx.dynamic_attributes.push(attr);
|
cx.dynamic_attributes.push(attr);
|
||||||
quote! { ::dioxus::core::TemplateAttribute::Dynamic(#ct) }
|
// quote! {}
|
||||||
|
None
|
||||||
|
// quote! { ::dioxus::core::TemplateAttribute::Dynamic(#ct) }
|
||||||
}
|
}
|
||||||
|
|
||||||
ElementAttr::EventTokens { .. } => {
|
ElementAttr::EventTokens { .. } => {
|
||||||
let ct = cx.dynamic_listeners.len();
|
let ct = cx.dynamic_listeners.len();
|
||||||
cx.dynamic_listeners.push(attr);
|
cx.dynamic_listeners.push(attr);
|
||||||
quote! { ::dioxus::core::TemplateAttribute::Dynamic(#ct) }
|
// quote! {}
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
::dioxus::core::TemplateNode::Element {
|
::dioxus::core::TemplateNode::Element {
|
||||||
tag: dioxus_elements::#name::TAG_NAME,
|
tag: dioxus_elements::#el_name::TAG_NAME,
|
||||||
|
namespace: dioxus_elements::#el_name::NAME_SPACE,
|
||||||
attrs: &[ #(#attrs),* ],
|
attrs: &[ #(#attrs),* ],
|
||||||
children: &[ #children ],
|
children: &[ #children ],
|
||||||
}
|
}
|
||||||
@@ -166,19 +168,19 @@ impl ToTokens for CallBody {
|
|||||||
// Render and release the mutable borrow on context
|
// Render and release the mutable borrow on context
|
||||||
let roots = quote! { #( #root_printer ),* };
|
let roots = quote! { #( #root_printer ),* };
|
||||||
|
|
||||||
let dyn_printer = &context.dynamic_nodes;
|
let node_printer = &context.dynamic_nodes;
|
||||||
let attr_printer = context.dynamic_attributes.iter();
|
let attr_printer = context.dynamic_attributes.iter();
|
||||||
let listener_printer = context.dynamic_listeners.iter();
|
let listener_printer = context.dynamic_listeners.iter();
|
||||||
|
|
||||||
out_tokens.append_all(quote! {
|
out_tokens.append_all(quote! {
|
||||||
LazyNodes::new(move | __cx: ::dioxus::core::NodeFactory| -> ::dioxus::core::VNode {
|
LazyNodes::new(move | __cx: ::dioxus::core::NodeFactory| -> ::dioxus::core::VNode {
|
||||||
__cx.template_ref(
|
__cx.template_ref(
|
||||||
|| ::dioxus::core::Template {
|
::dioxus::core::Template {
|
||||||
id: ::dioxus::core::get_line_num!(),
|
id: ::dioxus::core::get_line_num!(),
|
||||||
roots: &[ #roots ]
|
roots: &[ #roots ]
|
||||||
},
|
},
|
||||||
__cx.bump().alloc([
|
__cx.bump().alloc([
|
||||||
#( #dyn_printer ),*
|
#( #node_printer ),*
|
||||||
]),
|
]),
|
||||||
__cx.bump().alloc([
|
__cx.bump().alloc([
|
||||||
#( #attr_printer ),*
|
#( #attr_printer ),*
|
||||||
|
|||||||
+30
-30
@@ -410,36 +410,36 @@ fn render_attributes<'a, 'b: 'a>(
|
|||||||
let mut inner_html = None;
|
let mut inner_html = None;
|
||||||
let mut attr_iter = attrs.peekable();
|
let mut attr_iter = attrs.peekable();
|
||||||
|
|
||||||
while let Some(attr) = attr_iter.next() {
|
// while let Some(attr) = attr_iter.next() {
|
||||||
match attr.namespace {
|
// match attr.namespace {
|
||||||
None => {
|
// None => {
|
||||||
if attr.name == "dangerous_inner_html" {
|
// if attr.name == "dangerous_inner_html" {
|
||||||
inner_html = Some(attr.value.as_text().unwrap())
|
// inner_html = Some(attr.value.as_text().unwrap())
|
||||||
} else {
|
// } else {
|
||||||
if is_boolean_attribute(attr.name) && !attr.value.is_truthy() {
|
// if is_boolean_attribute(attr.name) && !attr.value.is_truthy() {
|
||||||
continue;
|
// continue;
|
||||||
}
|
// }
|
||||||
write!(f, " {}=\"{}\"", attr.name, attr.value)?
|
// write!(f, " {}=\"{}\"", attr.name, attr.value)?
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
Some(ns) => {
|
// Some(ns) => {
|
||||||
// write the opening tag
|
// // write the opening tag
|
||||||
write!(f, " {}=\"", ns)?;
|
// write!(f, " {}=\"", ns)?;
|
||||||
let mut cur_ns_el = attr;
|
// let mut cur_ns_el = attr;
|
||||||
loop {
|
// loop {
|
||||||
write!(f, "{}:{};", cur_ns_el.name, cur_ns_el.value)?;
|
// write!(f, "{}:{};", cur_ns_el.name, cur_ns_el.value)?;
|
||||||
match attr_iter.peek() {
|
// match attr_iter.peek() {
|
||||||
Some(next_attr) if next_attr.namespace == Some(ns) => {
|
// Some(next_attr) if next_attr.namespace == Some(ns) => {
|
||||||
cur_ns_el = attr_iter.next().unwrap();
|
// cur_ns_el = attr_iter.next().unwrap();
|
||||||
}
|
// }
|
||||||
_ => break,
|
// _ => break,
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
// write the closing tag
|
// // write the closing tag
|
||||||
write!(f, "\"")?;
|
// write!(f, "\"")?;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
Ok(inner_html)
|
Ok(inner_html)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user