Feat: implememt nodes better

This commit is contained in:
Jonathan Kelley committed 2021-02-07 19:14:04 -05:00
1 parent c9d95dd1dc
commit edbb33b2ee
9 files changed
+317 -387

No files matched your search

+50 -136
View File
@@ -22,7 +22,7 @@ mod vnode {
pub enum VNode<'src> {
/// An element node (node type `ELEMENT_NODE`).
Element(VElement<'src>),
Element(&'src VElement<'src>),
/// A text node (node type `TEXT_NODE`).
///
@@ -40,147 +40,54 @@ mod vnode {
Component(VComponent),
}
impl<'src> VNode<'src> {
/// Create a new virtual element node with a given tag.
impl<'a> VNode<'a> {
/// Low-level constructor for making a new `Node` of type element with given
/// parts.
///
/// These get patched into the DOM using `document.createElement`
///
/// ```ignore
/// let div = VNode::element("div");
/// ```
pub fn element(tag: &'static str) -> Self {
VNode::Element(VElement::new(tag))
/// This is primarily intended for JSX and templating proc-macros to compile
/// down into. If you are building nodes by-hand, prefer using the
/// `dodrio::builder::*` APIs.
#[inline]
pub fn element(
bump: &'a Bump,
key: NodeKey,
tag_name: &'a str,
listeners: &'a [Listener<'a>],
attributes: &'a [Attribute<'a>],
children: &'a [VNode<'a>],
namespace: Option<&'a str>,
) -> VNode<'a> {
let element = bump.alloc_with(|| VElement {
key,
tag_name,
listeners,
attributes,
children,
namespace,
});
VNode::Element(element)
}
/// Construct a new text node with the given text.
#[inline]
pub(crate) fn text(text: &'src str) -> VNode<'src> {
pub fn text(text: &'a str) -> VNode<'a> {
VNode::Text(VText { text })
}
// /// Create a new virtual text node with the given text.
// ///
// /// These get patched into the DOM using `document.createTextNode`
// ///
// /// ```ignore
// /// let div = VNode::text("div");
// /// ```
// pub fn text<S>(text: S) -> Self
// where
// S: Into<String>,
// {
// /*
// TODO
// This is an opportunity to be extremely efficient when allocating/creating strings
// To assemble a formatted string, we can, using the macro, borrow all the contents without allocating.
// String contents are therefore bump allocated automatically
// html!{
// <>"Hello {world}"</>
// }
// Should be
// ```
// let mut root = VNode::text(["Hello", world]);
// ```
// */
// VNode::Text(VText::new(text.into()))
// }
// /// Return a [`VElement`] reference, if this is an [`Element`] variant.
// ///
// /// [`VElement`]: struct.VElement.html
// /// [`Element`]: enum.VNode.html#variant.Element
// pub fn as_velement_ref(&self) -> Option<&VElement> {
// match self {
// VNode::Element(ref element_node) => Some(element_node),
// _ => None,
// }
// }
// /// Return a mutable [`VElement`] reference, if this is an [`Element`] variant.
// ///
// /// [`VElement`]: struct.VElement.html
// /// [`Element`]: enum.VNode.html#variant.Element
// pub fn as_velement_mut(&mut self) -> Option<&mut VElement> {
// match self {
// VNode::Element(ref mut element_node) => Some(element_node),
// _ => None,
// }
// }
// /// Return a [`VText`] reference, if this is an [`Text`] variant.
// ///
// /// [`VText`]: struct.VText.html
// /// [`Text`]: enum.VNode.html#variant.Text
// pub fn as_vtext_ref(&self) -> Option<&VText> {
// match self {
// VNode::Text(ref text_node) => Some(text_node),
// _ => None,
// }
// }
// /// Return a mutable [`VText`] reference, if this is an [`Text`] variant.
// ///
// /// [`VText`]: struct.VText.html
// /// [`Text`]: enum.VNode.html#variant.Text
// pub fn as_vtext_mut(&mut self) -> Option<&mut VText> {
// match self {
// VNode::Text(ref mut text_node) => Some(text_node),
// _ => None,
// }
// }
// /// Used by html-macro to insert space before text that is inside of a block that came after
// /// an open tag.
// ///
// /// html! { <div> {world}</div> }
// ///
// /// So that we end up with <div> world</div> when we're finished parsing.
// pub fn insert_space_before_text(&mut self) {
// match self {
// VNode::Text(text_node) => {
// text_node.text = " ".to_string() + &text_node.text;
// }
// _ => {}
// }
// }
// /// Used by html-macro to insert space after braced text if we know that the next block is
// /// another block or a closing tag.
// ///
// /// html! { <div>{Hello} {world}</div> } -> <div>Hello world</div>
// /// html! { <div>{Hello} </div> } -> <div>Hello </div>
// ///
// /// So that we end up with <div>Hello world</div> when we're finished parsing.
// pub fn insert_space_after_text(&mut self) {
// match self {
// VNode::Text(text_node) => {
// text_node.text += " ";
// }
// _ => {}
// }
// }
#[inline]
pub(crate) fn key(&self) -> NodeKey {
match &self {
VNode::Text(_) => NodeKey::NONE,
VNode::Element(e) => e.key,
VNode::Suspended => {
todo!()
}
VNode::Component(_) => {
todo!()
}
}
}
}
// -----------------------------------------------
// Convert from DOM elements to the primary enum
// -----------------------------------------------
// impl From<VText> for VNode {
// fn from(other: VText) -> Self {
// VNode::Text(other)
// }
// }
// impl From<VElement> for VNode {
// fn from(other: VElement) -> Self {
// VNode::Element(other)
// }
// }
}
mod velement {
@@ -188,11 +95,18 @@ mod velement {
use std::collections::HashMap;
pub struct VElement<'a> {
/// The HTML tag, such as "div"
pub tag: &'a str,
/// Elements have a tag name, zero or more attributes, and zero or more
pub key: NodeKey,
pub tag_name: &'a str,
pub listeners: &'a [Listener<'a>],
pub attributes: &'a [Attribute<'a>],
pub children: &'a [VNode<'a>],
pub namespace: Option<&'a str>,
// The HTML tag, such as "div"
// pub tag: &'a str,
// pub tag_name: &'a str,
// pub attributes: &'a [Attribute<'a>],
// todo: hook up listeners
// pub listeners: &'a [Listener<'a>],
// / HTML attributes such as id, class, style, etc