2022-12-10 02:56:48 +00:00
|
|
|
use rustc_hash::FxHashSet;
|
2022-12-01 04:54:30 +00:00
|
|
|
|
2023-01-02 20:40:25 +00:00
|
|
|
use crate::{arena::ElementId, innerlude::BorrowedAttributeValue, ScopeId, Template};
|
2021-08-22 21:08:25 +00:00
|
|
|
|
2022-12-01 04:54:30 +00:00
|
|
|
/// A container for all the relevant steps to modify the Real DOM
|
|
|
|
///
|
2022-12-03 00:24:49 +00:00
|
|
|
/// This object provides a bunch of important information for a renderer to use patch the Real Dom with the state of the
|
|
|
|
/// VirtualDom. This includes the scopes that were modified, the templates that were discovered, and a list of changes
|
|
|
|
/// in the form of a [`Mutation`].
|
|
|
|
///
|
|
|
|
/// These changes are specific to one subtree, so to patch multiple subtrees, you'd need to handle each set separately.
|
|
|
|
///
|
|
|
|
/// Templates, however, apply to all subtrees, not just target subtree.
|
2022-12-01 04:54:30 +00:00
|
|
|
///
|
|
|
|
/// Mutations are the only link between the RealDOM and the VirtualDOM.
|
2022-12-06 00:08:41 +00:00
|
|
|
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
|
2022-11-29 21:46:25 +00:00
|
|
|
#[derive(Debug, Default)]
|
2022-11-29 21:31:04 +00:00
|
|
|
#[must_use = "not handling edits can lead to visual inconsistencies in UI"]
|
2022-11-09 18:58:11 +00:00
|
|
|
pub struct Mutations<'a> {
|
2022-12-01 04:54:30 +00:00
|
|
|
/// The ID of the subtree that these edits are targetting
|
2022-11-09 03:39:37 +00:00
|
|
|
pub subtree: usize,
|
2022-12-01 04:54:30 +00:00
|
|
|
|
|
|
|
/// The list of Scopes that were diffed, created, and removed during the Diff process.
|
|
|
|
pub dirty_scopes: FxHashSet<ScopeId>,
|
|
|
|
|
2022-12-01 05:46:15 +00:00
|
|
|
/// Any templates encountered while diffing the DOM.
|
|
|
|
///
|
|
|
|
/// These must be loaded into a cache before applying the edits
|
|
|
|
pub templates: Vec<Template<'a>>,
|
2022-12-01 04:54:30 +00:00
|
|
|
|
|
|
|
/// Any mutations required to patch the renderer to match the layout of the VirtualDom
|
2022-12-01 05:46:15 +00:00
|
|
|
pub edits: Vec<Mutation<'a>>,
|
2022-10-28 04:58:47 +00:00
|
|
|
}
|
2022-11-09 03:39:37 +00:00
|
|
|
|
2022-11-09 18:58:11 +00:00
|
|
|
impl<'a> Mutations<'a> {
|
2022-11-23 05:32:26 +00:00
|
|
|
/// Rewrites IDs to just be "template", so you can compare the mutations
|
2022-12-01 04:54:30 +00:00
|
|
|
///
|
|
|
|
/// Used really only for testing
|
2022-11-23 05:32:26 +00:00
|
|
|
pub fn santize(mut self) -> Self {
|
2022-12-03 00:24:49 +00:00
|
|
|
for edit in self.edits.iter_mut() {
|
|
|
|
if let Mutation::LoadTemplate { name, .. } = edit {
|
|
|
|
*name = "template"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
self
|
2022-11-23 05:32:26 +00:00
|
|
|
}
|
2022-11-09 03:39:37 +00:00
|
|
|
|
2022-12-01 04:54:30 +00:00
|
|
|
/// Push a new mutation into the dom_edits list
|
|
|
|
pub(crate) fn push(&mut self, mutation: Mutation<'static>) {
|
2023-01-03 03:26:12 +00:00
|
|
|
self.edits.push(mutation)
|
2022-11-09 03:39:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-03 00:24:49 +00:00
|
|
|
/// A `Mutation` represents a single instruction for the renderer to use to modify the UI tree to match the state
|
|
|
|
/// of the Dioxus VirtualDom.
|
|
|
|
///
|
|
|
|
/// These edits can be serialized and sent over the network or through any interface
|
2022-11-16 02:32:48 +00:00
|
|
|
#[cfg_attr(
|
|
|
|
feature = "serialize",
|
|
|
|
derive(serde::Serialize, serde::Deserialize),
|
|
|
|
serde(tag = "type")
|
|
|
|
)]
|
2022-12-09 22:18:37 +00:00
|
|
|
#[derive(Debug, PartialEq)]
|
2022-10-28 04:58:47 +00:00
|
|
|
pub enum Mutation<'a> {
|
2022-12-03 00:24:49 +00:00
|
|
|
/// Add these m children to the target element
|
|
|
|
AppendChildren {
|
|
|
|
/// The ID of the element being mounted to
|
|
|
|
id: ElementId,
|
|
|
|
|
2023-03-28 16:58:50 +00:00
|
|
|
/// The number of nodes on the stack to append to the target element
|
2022-12-03 00:24:49 +00:00
|
|
|
m: usize,
|
|
|
|
},
|
|
|
|
|
|
|
|
/// Assign the element at the given path the target ElementId.
|
|
|
|
///
|
|
|
|
/// The path is in the form of a list of indices based on children. Templates cannot have more than 255 children per
|
|
|
|
/// element, hence the use of a single byte.
|
|
|
|
///
|
|
|
|
///
|
2022-11-16 02:32:48 +00:00
|
|
|
AssignId {
|
2022-12-03 00:24:49 +00:00
|
|
|
/// The path of the child of the topmost node on the stack
|
|
|
|
///
|
|
|
|
/// A path of `[]` represents the topmost node. A path of `[0]` represents the first child.
|
|
|
|
/// `[0,1,2]` represents 1st child's 2nd child's 3rd child.
|
2022-11-16 02:32:48 +00:00
|
|
|
path: &'static [u8],
|
2022-12-03 00:24:49 +00:00
|
|
|
|
|
|
|
/// The ID we're assigning to this element/placeholder.
|
|
|
|
///
|
|
|
|
/// This will be used later to modify the element or replace it with another element.
|
2022-10-28 04:58:47 +00:00
|
|
|
id: ElementId,
|
|
|
|
},
|
2022-10-20 16:56:09 +00:00
|
|
|
|
2022-12-03 00:24:49 +00:00
|
|
|
/// Create an placeholder int he DOM that we will use later.
|
|
|
|
///
|
|
|
|
/// Dioxus currently requires the use of placeholders to maintain a re-entrance point for things like list diffing
|
2022-11-16 02:32:48 +00:00
|
|
|
CreatePlaceholder {
|
2022-12-03 00:24:49 +00:00
|
|
|
/// The ID we're assigning to this element/placeholder.
|
|
|
|
///
|
|
|
|
/// This will be used later to modify the element or replace it with another element.
|
2022-11-16 02:32:48 +00:00
|
|
|
id: ElementId,
|
2022-10-28 04:58:47 +00:00
|
|
|
},
|
2022-12-03 00:24:49 +00:00
|
|
|
|
|
|
|
/// Create a node specifically for text with the given value
|
2022-11-16 02:32:48 +00:00
|
|
|
CreateTextNode {
|
2022-12-03 00:24:49 +00:00
|
|
|
/// The text content of this text node
|
2022-11-16 02:32:48 +00:00
|
|
|
value: &'a str,
|
2022-12-03 00:24:49 +00:00
|
|
|
|
|
|
|
/// The ID we're assigning to this specific text nodes
|
|
|
|
///
|
|
|
|
/// This will be used later to modify the element or replace it with another element.
|
2022-11-16 09:13:39 +00:00
|
|
|
id: ElementId,
|
2022-11-02 01:42:29 +00:00
|
|
|
},
|
2022-12-03 00:24:49 +00:00
|
|
|
|
|
|
|
/// Hydrate an existing text node at the given path with the given text.
|
|
|
|
///
|
|
|
|
/// Assign this text node the given ID since we will likely need to modify this text at a later point
|
2022-10-28 04:58:47 +00:00
|
|
|
HydrateText {
|
2022-12-03 00:24:49 +00:00
|
|
|
/// The path of the child of the topmost node on the stack
|
|
|
|
///
|
|
|
|
/// A path of `[]` represents the topmost node. A path of `[0]` represents the first child.
|
|
|
|
/// `[0,1,2]` represents 1st child's 2nd child's 3rd child.
|
2022-10-28 04:58:47 +00:00
|
|
|
path: &'static [u8],
|
2022-12-03 00:24:49 +00:00
|
|
|
|
|
|
|
/// The value of the textnode that we want to set the placeholder with
|
2022-10-28 04:58:47 +00:00
|
|
|
value: &'a str,
|
2022-12-03 00:24:49 +00:00
|
|
|
|
|
|
|
/// The ID we're assigning to this specific text nodes
|
|
|
|
///
|
|
|
|
/// This will be used later to modify the element or replace it with another element.
|
2022-10-28 04:58:47 +00:00
|
|
|
id: ElementId,
|
|
|
|
},
|
2022-12-03 00:24:49 +00:00
|
|
|
|
|
|
|
/// Load and clone an existing node from a template saved under that specific name
|
|
|
|
///
|
|
|
|
/// Dioxus guarantees that the renderer will have already been provided the template.
|
|
|
|
/// When the template is picked up in the template list, it should be saved under its "name" - here, the name
|
2022-11-16 02:32:48 +00:00
|
|
|
LoadTemplate {
|
2022-12-03 00:24:49 +00:00
|
|
|
/// The "name" of the template. When paired with `rsx!`, this is autogenerated
|
2022-11-16 02:32:48 +00:00
|
|
|
name: &'static str,
|
2022-12-03 00:24:49 +00:00
|
|
|
|
|
|
|
/// Which root are we loading from the template?
|
|
|
|
///
|
|
|
|
/// The template is stored as a list of nodes. This index represents the position of that root
|
2022-11-16 02:32:48 +00:00
|
|
|
index: usize,
|
2022-12-03 00:24:49 +00:00
|
|
|
|
|
|
|
/// The ID we're assigning to this element being loaded from the template
|
|
|
|
///
|
|
|
|
/// This will be used later to move the element around in lists
|
2022-11-24 07:15:01 +00:00
|
|
|
id: ElementId,
|
2022-11-16 02:32:48 +00:00
|
|
|
},
|
2022-10-28 04:58:47 +00:00
|
|
|
|
2022-12-03 00:24:49 +00:00
|
|
|
/// Replace the target element (given by its ID) with the topmost m nodes on the stack
|
2022-11-16 02:32:48 +00:00
|
|
|
ReplaceWith {
|
2022-12-03 00:24:49 +00:00
|
|
|
/// The ID of the node we're going to replace with
|
2022-10-28 04:58:47 +00:00
|
|
|
id: ElementId,
|
2022-12-03 00:24:49 +00:00
|
|
|
|
2023-03-28 16:58:50 +00:00
|
|
|
/// The number of nodes on the stack to replace the target element with
|
2022-11-16 02:32:48 +00:00
|
|
|
m: usize,
|
2022-10-28 04:58:47 +00:00
|
|
|
},
|
|
|
|
|
2022-12-03 00:24:49 +00:00
|
|
|
/// Replace an existing element in the template at the given path with the m nodes on the stack
|
2022-10-28 04:58:47 +00:00
|
|
|
ReplacePlaceholder {
|
2022-12-03 00:24:49 +00:00
|
|
|
/// The path of the child of the topmost node on the stack
|
|
|
|
///
|
|
|
|
/// A path of `[]` represents the topmost node. A path of `[0]` represents the first child.
|
|
|
|
/// `[0,1,2]` represents 1st child's 2nd child's 3rd child.
|
2022-11-02 08:00:37 +00:00
|
|
|
path: &'static [u8],
|
2022-12-03 00:24:49 +00:00
|
|
|
|
2023-03-28 16:58:50 +00:00
|
|
|
/// The number of nodes on the stack to replace the target element with
|
2022-11-24 07:15:01 +00:00
|
|
|
m: usize,
|
2022-10-28 04:58:47 +00:00
|
|
|
},
|
|
|
|
|
2022-11-23 03:59:56 +00:00
|
|
|
/// Insert a number of nodes after a given node.
|
|
|
|
InsertAfter {
|
|
|
|
/// The ID of the node to insert after.
|
|
|
|
id: ElementId,
|
|
|
|
|
2023-03-28 16:58:50 +00:00
|
|
|
/// The number of nodes on the stack to insert after the target node.
|
2022-11-23 03:59:56 +00:00
|
|
|
m: usize,
|
|
|
|
},
|
|
|
|
|
|
|
|
/// Insert a number of nodes before a given node.
|
|
|
|
InsertBefore {
|
|
|
|
/// The ID of the node to insert before.
|
|
|
|
id: ElementId,
|
|
|
|
|
2023-03-28 16:58:50 +00:00
|
|
|
/// The number of nodes on the stack to insert before the target node.
|
2022-11-23 03:59:56 +00:00
|
|
|
m: usize,
|
|
|
|
},
|
|
|
|
|
2022-12-01 04:54:30 +00:00
|
|
|
/// Set the value of a node's attribute.
|
2022-11-16 02:32:48 +00:00
|
|
|
SetAttribute {
|
2022-12-01 04:54:30 +00:00
|
|
|
/// The name of the attribute to set.
|
2022-11-16 02:32:48 +00:00
|
|
|
name: &'a str,
|
2022-12-09 22:18:37 +00:00
|
|
|
|
2022-12-01 04:54:30 +00:00
|
|
|
/// The value of the attribute.
|
2023-01-02 20:40:25 +00:00
|
|
|
value: BorrowedAttributeValue<'a>,
|
2022-12-01 04:54:30 +00:00
|
|
|
|
|
|
|
/// The ID of the node to set the attribute of.
|
2022-10-28 04:58:47 +00:00
|
|
|
id: ElementId,
|
2022-11-16 07:31:23 +00:00
|
|
|
|
|
|
|
/// The (optional) namespace of the attribute.
|
|
|
|
/// For instance, "style" is in the "style" namespace.
|
|
|
|
ns: Option<&'a str>,
|
2022-10-28 04:58:47 +00:00
|
|
|
},
|
2022-11-02 01:42:29 +00:00
|
|
|
|
2022-12-01 04:54:30 +00:00
|
|
|
/// Set the textcontent of a node.
|
2022-11-16 02:32:48 +00:00
|
|
|
SetText {
|
2022-12-01 04:54:30 +00:00
|
|
|
/// The textcontent of the node
|
2022-11-02 01:42:29 +00:00
|
|
|
value: &'a str,
|
2022-12-01 04:54:30 +00:00
|
|
|
|
|
|
|
/// The ID of the node to set the textcontent of.
|
2022-11-16 02:32:48 +00:00
|
|
|
id: ElementId,
|
2022-11-02 01:42:29 +00:00
|
|
|
},
|
|
|
|
|
2022-11-16 02:32:48 +00:00
|
|
|
/// Create a new Event Listener.
|
|
|
|
NewEventListener {
|
|
|
|
/// The name of the event to listen for.
|
2022-11-30 22:21:10 +00:00
|
|
|
name: &'a str,
|
2022-11-16 02:32:48 +00:00
|
|
|
|
|
|
|
/// The ID of the node to attach the listener to.
|
2022-11-04 00:34:42 +00:00
|
|
|
id: ElementId,
|
|
|
|
},
|
2022-11-02 01:42:29 +00:00
|
|
|
|
2022-11-16 02:32:48 +00:00
|
|
|
/// Remove an existing Event Listener.
|
|
|
|
RemoveEventListener {
|
2022-11-30 22:21:10 +00:00
|
|
|
/// The name of the event to remove.
|
|
|
|
name: &'a str,
|
|
|
|
|
2022-11-16 02:32:48 +00:00
|
|
|
/// The ID of the node to remove.
|
|
|
|
id: ElementId,
|
2022-11-02 01:42:29 +00:00
|
|
|
},
|
2022-12-01 04:54:30 +00:00
|
|
|
|
|
|
|
/// Remove a particular node from the DOM
|
2022-11-24 07:15:01 +00:00
|
|
|
Remove {
|
2022-12-01 04:54:30 +00:00
|
|
|
/// The ID of the node to remove.
|
2022-11-24 07:15:01 +00:00
|
|
|
id: ElementId,
|
|
|
|
},
|
2022-11-27 07:06:04 +00:00
|
|
|
|
2022-12-01 04:54:30 +00:00
|
|
|
/// Push the given root node onto our stack.
|
2022-11-27 07:06:04 +00:00
|
|
|
PushRoot {
|
2022-12-01 04:54:30 +00:00
|
|
|
/// The ID of the root node to push.
|
2022-11-27 07:06:04 +00:00
|
|
|
id: ElementId,
|
|
|
|
},
|
2021-08-22 21:08:25 +00:00
|
|
|
}
|