wip: start to refactor out hot reloading from packages
Also implement alternative simpler template system
This commit is contained in:
1 parent
3b7b503333
commit
90982e0ccb
44 files changed
+3865
-5133
No files matched your search
@@ -0,0 +1,204 @@
|
||||
//! Virtual Node Support
|
||||
//!
|
||||
//! VNodes represent lazily-constructed VDom trees that support diffing and event handlers. These VNodes should be *very*
|
||||
//! cheap and *very* fast to construct - building a full tree should be quick.
|
||||
|
||||
use std::fmt::{Debug, Formatter};
|
||||
|
||||
mod arbitrary_value;
|
||||
mod component;
|
||||
mod element;
|
||||
mod factory;
|
||||
mod fragment;
|
||||
mod suspense;
|
||||
mod template;
|
||||
mod text;
|
||||
|
||||
pub use arbitrary_value::*;
|
||||
pub use component::*;
|
||||
pub use element::*;
|
||||
pub use factory::*;
|
||||
pub use fragment::*;
|
||||
pub use suspense::*;
|
||||
pub use template::*;
|
||||
pub use text::*;
|
||||
|
||||
/// A composable "VirtualNode" to declare a User Interface in the Dioxus VirtualDOM.
|
||||
///
|
||||
/// VNodes are designed to be lightweight and used with with a bump allocator. To create a VNode, you can use either of:
|
||||
///
|
||||
/// - the `rsx!` macro
|
||||
/// - the [`NodeFactory`] API
|
||||
pub enum VNode<'src> {
|
||||
/// Text VNodes are simply bump-allocated (or static) string slices
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust, ignore
|
||||
/// let mut vdom = VirtualDom::new();
|
||||
/// let node = vdom.render_vnode(rsx!( "hello" ));
|
||||
///
|
||||
/// if let VNode::Text(vtext) = node {
|
||||
/// assert_eq!(vtext.text, "hello");
|
||||
/// assert_eq!(vtext.dom_id.get(), None);
|
||||
/// assert_eq!(vtext.is_static, true);
|
||||
/// }
|
||||
/// ```
|
||||
Text(&'src VText<'src>),
|
||||
|
||||
/// Element VNodes are VNodes that may contain attributes, listeners, a key, a tag, and children.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust, ignore
|
||||
/// let mut vdom = VirtualDom::new();
|
||||
///
|
||||
/// let node = vdom.render_vnode(rsx!{
|
||||
/// div {
|
||||
/// key: "a",
|
||||
/// onclick: |e| log::info!("clicked"),
|
||||
/// hidden: "true",
|
||||
/// style: { background_color: "red" },
|
||||
/// "hello"
|
||||
/// }
|
||||
/// });
|
||||
///
|
||||
/// if let VNode::Element(velement) = node {
|
||||
/// assert_eq!(velement.tag_name, "div");
|
||||
/// assert_eq!(velement.namespace, None);
|
||||
/// assert_eq!(velement.key, Some("a"));
|
||||
/// }
|
||||
/// ```
|
||||
Element(&'src VElement<'src>),
|
||||
|
||||
/// Fragment nodes may contain many VNodes without a single root.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust, ignore
|
||||
/// rsx!{
|
||||
/// a {}
|
||||
/// link {}
|
||||
/// style {}
|
||||
/// "asd"
|
||||
/// Example {}
|
||||
/// }
|
||||
/// ```
|
||||
Fragment(&'src VFragment<'src>),
|
||||
|
||||
/// Component nodes represent a mounted component with props, children, and a key.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust, ignore
|
||||
/// fn Example(cx: Scope) -> Element {
|
||||
/// ...
|
||||
/// }
|
||||
///
|
||||
/// let mut vdom = VirtualDom::new();
|
||||
///
|
||||
/// let node = vdom.render_vnode(rsx!( Example {} ));
|
||||
///
|
||||
/// if let VNode::Component(vcomp) = node {
|
||||
/// assert_eq!(vcomp.user_fc, Example as *const ());
|
||||
/// }
|
||||
/// ```
|
||||
Component(&'src VComponent<'src>),
|
||||
|
||||
/// Templetes ase generated by the rsx macro to eleminate diffing static nodes.
|
||||
///
|
||||
///
|
||||
///
|
||||
///
|
||||
///
|
||||
///
|
||||
Template(&'src VTemplate<'src>),
|
||||
}
|
||||
|
||||
/// An Element's unique identifier.
|
||||
///
|
||||
/// `ElementId` is a `usize` that is unique across the entire VirtualDOM - but not unique across time. If a component is
|
||||
/// unmounted, then the `ElementId` will be reused for a new component.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[cfg_attr(feature = "serialize", serde(transparent))]
|
||||
pub struct ElementId(pub usize);
|
||||
|
||||
impl<'src> VNode<'src> {
|
||||
/// Get the VNode's "key" used in the keyed diffing algorithm.
|
||||
pub fn key(&self) -> Option<&'src str> {
|
||||
match &self {
|
||||
VNode::Element(el) => el.key,
|
||||
VNode::Component(c) => c.key,
|
||||
VNode::Fragment(f) => f.key,
|
||||
VNode::Text(_t) => None,
|
||||
VNode::Template(t) => t.key,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the ElementID of the mounted VNode.
|
||||
///
|
||||
/// Panics if the mounted ID is None or if the VNode is not represented by a single Element.
|
||||
pub fn mounted_id(&self) -> ElementId {
|
||||
self.try_mounted_id().unwrap()
|
||||
}
|
||||
|
||||
/// Try to get the ElementID of the mounted VNode.
|
||||
///
|
||||
/// Returns None if the VNode is not mounted, or if the VNode cannot be presented by a mounted ID (Fragment/Component)
|
||||
pub fn try_mounted_id(&self) -> Option<ElementId> {
|
||||
match &self {
|
||||
VNode::Text(el) => el.id.get(),
|
||||
VNode::Element(el) => el.id.get(),
|
||||
VNode::Fragment(_) => None,
|
||||
VNode::Component(_) => None,
|
||||
VNode::Template(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
// Create an "owned" version of the vnode.
|
||||
pub(crate) fn decouple(&self) -> VNode<'src> {
|
||||
match *self {
|
||||
VNode::Text(t) => VNode::Text(t),
|
||||
VNode::Element(e) => VNode::Element(e),
|
||||
VNode::Component(c) => VNode::Component(c),
|
||||
VNode::Fragment(f) => VNode::Fragment(f),
|
||||
VNode::Template(t) => VNode::Template(t),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for VNode<'_> {
|
||||
fn fmt(&self, s: &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
|
||||
match &self {
|
||||
VNode::Element(el) => s
|
||||
.debug_struct("VNode::Element")
|
||||
.field("name", &el.tag)
|
||||
.field("key", &el.key)
|
||||
.field("attrs", &el.attributes)
|
||||
.field("children", &el.children)
|
||||
.field("id", &el.id)
|
||||
.finish(),
|
||||
VNode::Text(t) => s
|
||||
.debug_struct("VNode::Text")
|
||||
.field("text", &t.text)
|
||||
.field("id", &t.id)
|
||||
.finish(),
|
||||
VNode::Fragment(frag) => s
|
||||
.debug_struct("VNode::Fragment")
|
||||
.field("children", &frag.children)
|
||||
.finish(),
|
||||
VNode::Component(comp) => s
|
||||
.debug_struct("VNode::Component")
|
||||
.field("name", &comp.fn_name)
|
||||
.field("fnptr", &comp.user_fc)
|
||||
.field("key", &comp.key)
|
||||
.field("scope", &comp.scope)
|
||||
.finish(),
|
||||
VNode::Template(temp) => s
|
||||
.debug_struct("VNode::Templates")
|
||||
.field("template_id", &temp.template.id)
|
||||
.finish(),
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user