Feat: some updates, pull in the vnode enums
This commit is contained in:
1 parent
ce34d0dfcd
commit
152bced9f3
5 files changed
+547
-31
No files matched your search
@@ -12,5 +12,6 @@ typed-arena = "2.0.1"
|
|||||||
virtual-dom-rs = { path = "../virtual-dom-rs" }
|
virtual-dom-rs = { path = "../virtual-dom-rs" }
|
||||||
virtual-node = { path = "../virtual-node" }
|
virtual-node = { path = "../virtual-node" }
|
||||||
html-macro = { path = "../html-macro" }
|
html-macro = { path = "../html-macro" }
|
||||||
|
once_cell = "1.5.2"
|
||||||
# web-sys = "0.3.46"
|
# web-sys = "0.3.46"
|
||||||
# js-sys = "0.3.46"
|
# js-sys = "0.3.46"
|
||||||
@@ -3,13 +3,17 @@ use std::future::Future;
|
|||||||
use dioxus_core::{component::AnyContext, prelude::*};
|
use dioxus_core::{component::AnyContext, prelude::*};
|
||||||
use virtual_dom_rs::Closure;
|
use virtual_dom_rs::Closure;
|
||||||
|
|
||||||
|
// Stop-gap while developing
|
||||||
|
// Need to update the macro
|
||||||
|
type VirtualNode = VNode;
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
let dom = VirtualDom::new(root);
|
let dom = VirtualDom::new(root);
|
||||||
let mut renderer = TextRenderer::new(dom);
|
let mut renderer = TextRenderer::new(dom);
|
||||||
let output = renderer.render();
|
let output = renderer.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn root(ctx: &mut AnyContext) -> VirtualNode {
|
fn root(ctx: &mut AnyContext) -> VNode {
|
||||||
// the regular html syntax
|
// the regular html syntax
|
||||||
|
|
||||||
// html! {
|
// html! {
|
||||||
@@ -22,10 +26,10 @@ fn root(ctx: &mut AnyContext) -> VirtualNode {
|
|||||||
|
|
||||||
// or a manually crated vnode
|
// or a manually crated vnode
|
||||||
{
|
{
|
||||||
let mut node_0 = VirtualNode::element("div");
|
let mut node_0 = VNode::element("div");
|
||||||
let mut node_1: IterableNodes = ("Hello world!").into();
|
let mut node_1: IterableNodes = ("Hello world!").into();
|
||||||
node_1.first().insert_space_before_text();
|
node_1.first().insert_space_before_text();
|
||||||
let mut node_2 = VirtualNode::element("button");
|
let mut node_2 = VNode::element("button");
|
||||||
{
|
{
|
||||||
// let closure = Closure::wrap(Box::new(|_| {}) as Box<FnMut(_)>);
|
// let closure = Closure::wrap(Box::new(|_| {}) as Box<FnMut(_)>);
|
||||||
// let closure_rc = std::rc::Rc::new(closure);
|
// let closure_rc = std::rc::Rc::new(closure);
|
||||||
@@ -44,13 +48,11 @@ fn root(ctx: &mut AnyContext) -> VirtualNode {
|
|||||||
element_node.children.extend(node_2.into_iter());
|
element_node.children.extend(node_2.into_iter());
|
||||||
}
|
}
|
||||||
|
|
||||||
VirtualNode
|
|
||||||
|
|
||||||
node_0
|
node_0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn Head(ctx: &mut AnyContext) -> VirtualNode {
|
fn Head(ctx: &mut AnyContext) -> VNode {
|
||||||
html! {
|
html! {
|
||||||
<head>
|
<head>
|
||||||
{"Head Section"}
|
{"Head Section"}
|
||||||
@@ -58,7 +60,7 @@ fn Head(ctx: &mut AnyContext) -> VirtualNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn Body(ctx: &mut AnyContext) -> VirtualNode {
|
fn Body(ctx: &mut AnyContext) -> VNode {
|
||||||
html! {
|
html! {
|
||||||
<body>
|
<body>
|
||||||
{"Footer Section"}
|
{"Footer Section"}
|
||||||
@@ -66,7 +68,7 @@ fn Body(ctx: &mut AnyContext) -> VirtualNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn Footer(ctx: &mut AnyContext) -> VirtualNode {
|
fn Footer(ctx: &mut AnyContext) -> VNode {
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
{"Footer Section"}
|
{"Footer Section"}
|
||||||
|
|||||||
+529
-11
@@ -1,19 +1,40 @@
|
|||||||
use html_macro::html;
|
//! Dioxus: a concurrent, functional, virtual dom for any renderer in Rust
|
||||||
use virtual_node::{IterableNodes, VElement, VirtualNode};
|
//!
|
||||||
|
//!
|
||||||
|
//!
|
||||||
|
//!
|
||||||
|
//!
|
||||||
|
//!
|
||||||
|
//!
|
||||||
|
//!
|
||||||
|
//!
|
||||||
|
//!
|
||||||
|
//!
|
||||||
|
//!
|
||||||
|
//!
|
||||||
|
//!
|
||||||
|
|
||||||
/// A re-export of everything to get macros working smoothly
|
/// Re-export common types for ease of development use.
|
||||||
|
/// Essential when working with the html! macro
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use crate::component::Context;
|
pub use crate::component::Context;
|
||||||
|
use crate::nodes;
|
||||||
pub use crate::renderer::TextRenderer;
|
pub use crate::renderer::TextRenderer;
|
||||||
pub use crate::types::FC;
|
pub use crate::types::FC;
|
||||||
pub use crate::virtual_dom::VirtualDom;
|
pub use crate::virtual_dom::VirtualDom;
|
||||||
|
pub use nodes::iterables::IterableNodes;
|
||||||
|
pub use nodes::*;
|
||||||
|
|
||||||
|
// Re-export from the macro crate
|
||||||
pub use html_macro::html;
|
pub use html_macro::html;
|
||||||
pub use virtual_node::{IterableNodes, VirtualNode};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The Dioxus Virtual Dom integrates an event system and virtual nodes to create reactive user interfaces.
|
||||||
pub mod virtual_dom {
|
pub mod virtual_dom {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
/// An integrated virtual node system that progresses events and diffs UI trees.
|
||||||
|
/// Differences are converted into patches which a renderer can use to draw the UI.
|
||||||
pub struct VirtualDom {}
|
pub struct VirtualDom {}
|
||||||
|
|
||||||
impl VirtualDom {
|
impl VirtualDom {
|
||||||
@@ -25,12 +46,472 @@ pub mod virtual_dom {
|
|||||||
|
|
||||||
/// Virtual Node Support
|
/// Virtual Node Support
|
||||||
pub mod nodes {
|
pub mod nodes {
|
||||||
pub type VNode = virtual_node::VirtualNode;
|
pub use vcomponent::VComponent;
|
||||||
// pub enum VNode {
|
pub use velement::VElement;
|
||||||
// VText,
|
pub use vnode::VNode;
|
||||||
// VElement,
|
pub use vtext::VText;
|
||||||
// VComponent,
|
|
||||||
// }
|
/// Tools for the base unit of the virtual dom - the VNode
|
||||||
|
/// VNodes are intended to be quickly-allocated, lightweight enum values.
|
||||||
|
///
|
||||||
|
/// Components will be generating a lot of these very quickly, so we want to
|
||||||
|
/// limit the amount of heap allocations / overly large enum sizes.
|
||||||
|
mod vnode {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(PartialEq)]
|
||||||
|
pub enum VNode {
|
||||||
|
/// An element node (node type `ELEMENT_NODE`).
|
||||||
|
Element(VElement),
|
||||||
|
/// A text node (node type `TEXT_NODE`).
|
||||||
|
///
|
||||||
|
/// Note: This wraps a `VText` instead of a plain `String` in
|
||||||
|
/// order to enable custom methods like `create_text_node()` on the
|
||||||
|
/// wrapped type.
|
||||||
|
Text(VText),
|
||||||
|
|
||||||
|
/// A User-defined componen node (node type COMPONENT_NODE)
|
||||||
|
Component(VComponent),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VNode {
|
||||||
|
/// Create a new virtual element node with a given tag.
|
||||||
|
///
|
||||||
|
/// These get patched into the DOM using `document.createElement`
|
||||||
|
///
|
||||||
|
/// ```ignore
|
||||||
|
/// let div = VNode::element("div");
|
||||||
|
/// ```
|
||||||
|
pub fn element<S>(tag: S) -> Self
|
||||||
|
where
|
||||||
|
S: Into<String>,
|
||||||
|
{
|
||||||
|
VNode::Element(VElement::new(tag))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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>,
|
||||||
|
{
|
||||||
|
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 += " ";
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for VNode {
|
||||||
|
fn from(other: &str) -> Self {
|
||||||
|
VNode::text(other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for VNode {
|
||||||
|
fn from(other: String) -> Self {
|
||||||
|
VNode::text(other.as_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------
|
||||||
|
// Allow VNodes to be iterated for map-based UI
|
||||||
|
// -----------------------------------------------
|
||||||
|
impl IntoIterator for VNode {
|
||||||
|
type Item = VNode;
|
||||||
|
// TODO: Is this possible with an array [VNode] instead of a vec?
|
||||||
|
type IntoIter = ::std::vec::IntoIter<VNode>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
vec![self].into_iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<::std::vec::IntoIter<VNode>> for VNode {
|
||||||
|
fn into(self) -> ::std::vec::IntoIter<VNode> {
|
||||||
|
self.into_iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------
|
||||||
|
// Allow debug/display adherent to the HTML spec
|
||||||
|
// -----------------------------------------------
|
||||||
|
use std::fmt;
|
||||||
|
impl fmt::Debug for VNode {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
VNode::Element(e) => write!(f, "Node::{:?}", e),
|
||||||
|
VNode::Text(t) => write!(f, "Node::{:?}", t),
|
||||||
|
VNode::Component(c) => write!(f, "Node::{:?}", c),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Turn a VNode into an HTML string (delegate impl to variants)
|
||||||
|
impl fmt::Display for VNode {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
VNode::Element(element) => write!(f, "{}", element),
|
||||||
|
VNode::Text(text) => write!(f, "{}", text),
|
||||||
|
VNode::Component(c) => write!(f, "{}", c),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod velement {
|
||||||
|
use super::*;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[derive(PartialEq)]
|
||||||
|
pub struct VElement {
|
||||||
|
/// The HTML tag, such as "div"
|
||||||
|
pub tag: String,
|
||||||
|
|
||||||
|
/// HTML attributes such as id, class, style, etc
|
||||||
|
pub attrs: HashMap<String, String>,
|
||||||
|
|
||||||
|
// TODO @Jon, re-enable "events"
|
||||||
|
//
|
||||||
|
// /// Events that will get added to your real DOM element via `.addEventListener`
|
||||||
|
// pub events: Events,
|
||||||
|
pub events: HashMap<String, ()>,
|
||||||
|
|
||||||
|
/// The children of this `VNode`. So a <div> <em></em> </div> structure would
|
||||||
|
/// have a parent div and one child, em.
|
||||||
|
pub children: Vec<VNode>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VElement {
|
||||||
|
pub fn new<S>(tag: S) -> Self
|
||||||
|
where
|
||||||
|
S: Into<String>,
|
||||||
|
{
|
||||||
|
VElement {
|
||||||
|
tag: tag.into(),
|
||||||
|
attrs: HashMap::new(),
|
||||||
|
events: HashMap::new(),
|
||||||
|
// events: Events(HashMap::new()),
|
||||||
|
children: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------
|
||||||
|
// Allow debug/display adherent to the HTML spec
|
||||||
|
// -----------------------------------------------
|
||||||
|
use std::fmt;
|
||||||
|
impl fmt::Debug for VElement {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"Element(<{}>, attrs: {:?}, children: {:?})",
|
||||||
|
self.tag, self.attrs, self.children,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for VElement {
|
||||||
|
// Turn a VElement and all of it's children (recursively) into an HTML string
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "<{}", self.tag).unwrap();
|
||||||
|
|
||||||
|
for (attr, value) in self.attrs.iter() {
|
||||||
|
write!(f, r#" {}="{}""#, attr, value)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(f, ">")?;
|
||||||
|
|
||||||
|
for child in self.children.iter() {
|
||||||
|
write!(f, "{}", child.to_string())?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !crate::validation::is_self_closing(&self.tag) {
|
||||||
|
write!(f, "</{}>", self.tag)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod vtext {
|
||||||
|
#[derive(PartialEq)]
|
||||||
|
pub struct VText {
|
||||||
|
pub text: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VText {
|
||||||
|
/// Create an new `VText` instance with the specified text.
|
||||||
|
pub fn new<S>(text: S) -> Self
|
||||||
|
where
|
||||||
|
S: Into<String>,
|
||||||
|
{
|
||||||
|
VText { text: text.into() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------
|
||||||
|
// Convert from primitives directly into VText
|
||||||
|
// -----------------------------------------------
|
||||||
|
impl From<&str> for VText {
|
||||||
|
fn from(text: &str) -> Self {
|
||||||
|
VText {
|
||||||
|
text: text.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for VText {
|
||||||
|
fn from(text: String) -> Self {
|
||||||
|
VText { text }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------
|
||||||
|
// Allow debug/display adherent to the HTML spec
|
||||||
|
// -----------------------------------------------
|
||||||
|
use std::fmt;
|
||||||
|
impl fmt::Debug for VText {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "Text({})", self.text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Turn a VText into an HTML string
|
||||||
|
impl fmt::Display for VText {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Virtual Components for custom user-defined components
|
||||||
|
/// Only supports the functional syntax
|
||||||
|
mod vcomponent {
|
||||||
|
#[derive(PartialEq)]
|
||||||
|
pub struct VComponent {}
|
||||||
|
|
||||||
|
// -----------------------------------------------
|
||||||
|
// Allow debug/display adherent to the HTML spec
|
||||||
|
// -----------------------------------------------
|
||||||
|
use std::fmt;
|
||||||
|
impl fmt::Debug for VComponent {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
// TODO: @JON Implement how components should be formatted when spit out to html
|
||||||
|
// It probably can't be as straightforward as renderinng their VNodes
|
||||||
|
// It _could_ be, but we can't really implement that directly
|
||||||
|
// Instead, we should drop a vnode labeled with the component id/key
|
||||||
|
|
||||||
|
// write!(
|
||||||
|
// f,
|
||||||
|
// "Element(<{}>, attrs: {:?}, children: {:?})",
|
||||||
|
// self.tag, self.attrs, self.children,
|
||||||
|
// )
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for VComponent {
|
||||||
|
// Turn a VElement and all of it's children (recursively) into an HTML string
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
// write!(f, "<{}", self.tag).unwrap();
|
||||||
|
|
||||||
|
// for (attr, value) in self.attrs.iter() {
|
||||||
|
// write!(f, r#" {}="{}""#, attr, value)?;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// write!(f, ">")?;
|
||||||
|
|
||||||
|
// for child in self.children.iter() {
|
||||||
|
// write!(f, "{}", child.to_string())?;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if !crate::validation::is_self_closing(&self.tag) {
|
||||||
|
// write!(f, "</{}>", self.tag)?;
|
||||||
|
// }
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod iterables {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
/// Used by the html! macro for all braced child nodes so that we can use any type
|
||||||
|
/// that implements Into<IterableNodes>
|
||||||
|
///
|
||||||
|
/// html! { <div> { nodes } </div> }
|
||||||
|
///
|
||||||
|
/// nodes can be a String .. VNode .. Vec<VNode> ... etc
|
||||||
|
pub struct IterableNodes(Vec<VNode>);
|
||||||
|
|
||||||
|
impl IterableNodes {
|
||||||
|
/// Retrieve the first node mutably
|
||||||
|
pub fn first(&mut self) -> &mut VNode {
|
||||||
|
self.0.first_mut().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieve the last node mutably
|
||||||
|
pub fn last(&mut self) -> &mut VNode {
|
||||||
|
self.0.last_mut().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoIterator for IterableNodes {
|
||||||
|
type Item = VNode;
|
||||||
|
// TODO: Is this possible with an array [VNode] instead of a vec?
|
||||||
|
type IntoIter = ::std::vec::IntoIter<VNode>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
self.0.into_iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<VNode> for IterableNodes {
|
||||||
|
fn from(other: VNode) -> Self {
|
||||||
|
IterableNodes(vec![other])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for IterableNodes {
|
||||||
|
fn from(other: &str) -> Self {
|
||||||
|
IterableNodes(vec![VNode::text(other)])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for IterableNodes {
|
||||||
|
fn from(other: String) -> Self {
|
||||||
|
IterableNodes(vec![VNode::text(other.as_str())])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Vec<VNode>> for IterableNodes {
|
||||||
|
fn from(other: Vec<VNode>) -> Self {
|
||||||
|
IterableNodes(other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO @Jon
|
||||||
|
// Set this up so instead of the view trait, we can just take functions
|
||||||
|
// Functions with no context should just be rendered
|
||||||
|
// But functions with a context should be treated as regular components
|
||||||
|
|
||||||
|
// impl<V: View> From<Vec<V>> for IterableNodes {
|
||||||
|
// fn from(other: Vec<V>) -> Self {
|
||||||
|
// IterableNodes(other.into_iter().map(|it| it.render()).collect())
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// impl<V: View> From<&Vec<V>> for IterableNodes {
|
||||||
|
// fn from(other: &Vec<V>) -> Self {
|
||||||
|
// IterableNodes(other.iter().map(|it| it.render()).collect())
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// impl<V: View> From<&[V]> for IterableNodes {
|
||||||
|
// fn from(other: &[V]) -> Self {
|
||||||
|
// IterableNodes(other.iter().map(|it| it.render()).collect())
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod diff {
|
||||||
|
pub enum Patch {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Example on how to craft a renderer that interacts with the VirtualDom
|
/// Example on how to craft a renderer that interacts with the VirtualDom
|
||||||
@@ -78,9 +559,46 @@ pub mod types {
|
|||||||
pub type FC = fn(&mut AnyContext) -> VNode;
|
pub type FC = fn(&mut AnyContext) -> VNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[cg(test)]
|
/// TODO @Jon
|
||||||
|
/// Figure out if validation should be its own crate, or embedded directly into dioxus
|
||||||
|
/// Should we even be bothered with validation?
|
||||||
|
mod validation {
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
// Used to uniquely identify elements that contain closures so that the DomUpdater can
|
||||||
|
// look them up by their unique id.
|
||||||
|
// When the DomUpdater sees that the element no longer exists it will drop all of it's
|
||||||
|
// Rc'd Closures for those events.
|
||||||
|
static SELF_CLOSING_TAGS: Lazy<HashSet<&'static str>> = Lazy::new(|| {
|
||||||
|
[
|
||||||
|
"area", "base", "br", "col", "hr", "img", "input", "link", "meta", "param", "command",
|
||||||
|
"keygen", "source",
|
||||||
|
]
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.collect()
|
||||||
|
});
|
||||||
|
|
||||||
|
/// Whether or not this tag is self closing
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use html_validation::is_self_closing;
|
||||||
|
///
|
||||||
|
/// assert_eq!(is_self_closing("br"), true);
|
||||||
|
///
|
||||||
|
/// assert_eq!(is_self_closing("div"), false);
|
||||||
|
/// ```
|
||||||
|
pub fn is_self_closing(tag: &str) -> bool {
|
||||||
|
SELF_CLOSING_TAGS.contains(tag)
|
||||||
|
// SELF_CLOSING_TAGS.contains(tag) || is_self_closing_svg_tag(tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
mod integration_tests {
|
mod integration_tests {
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
type VirtualNode = VNode;
|
||||||
|
|
||||||
/// Test a basic usage of a virtual dom + text renderer combo
|
/// Test a basic usage of a virtual dom + text renderer combo
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
Whitespace-only changes.
@@ -57,9 +57,8 @@ pub enum VirtualNode {
|
|||||||
/// order to enable custom methods like `create_text_node()` on the
|
/// order to enable custom methods like `create_text_node()` on the
|
||||||
/// wrapped type.
|
/// wrapped type.
|
||||||
Text(VText),
|
Text(VText),
|
||||||
|
// /// A User-defined componen node (node type COMPONENT_NODE)
|
||||||
/// A User-defined componen node (node type COMPONENT_NODE)
|
// Component(VComponent),
|
||||||
Component(VComponent),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
@@ -83,9 +82,6 @@ pub struct VText {
|
|||||||
pub text: String,
|
pub text: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
|
||||||
pub struct VComponent {}
|
|
||||||
|
|
||||||
impl VirtualNode {
|
impl VirtualNode {
|
||||||
/// Create a new virtual element node with a given tag.
|
/// Create a new virtual element node with a given tag.
|
||||||
///
|
///
|
||||||
@@ -171,7 +167,7 @@ impl VirtualNode {
|
|||||||
CreatedNode::without_closures(text_node.create_text_node())
|
CreatedNode::without_closures(text_node.create_text_node())
|
||||||
}
|
}
|
||||||
VirtualNode::Element(element_node) => element_node.create_element_node().into(),
|
VirtualNode::Element(element_node) => element_node.create_element_node().into(),
|
||||||
VirtualNode::Component(_) => todo!("WIP on Component Syntax"),
|
// VirtualNode::Component(_) => todo!("WIP on Component Syntax"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,10 +307,9 @@ impl VElement {
|
|||||||
closures.extend(child.closures);
|
closures.extend(child.closures);
|
||||||
|
|
||||||
element.append_child(&child_elem).unwrap();
|
element.append_child(&child_elem).unwrap();
|
||||||
}
|
} // VirtualNode::Component(_) => {
|
||||||
VirtualNode::Component(_) => {
|
// todo!("WIP on Component Syntax")
|
||||||
todo!("WIP on Component Syntax")
|
// }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -542,7 +537,7 @@ impl fmt::Debug for VirtualNode {
|
|||||||
match self {
|
match self {
|
||||||
VirtualNode::Element(e) => write!(f, "Node::{:?}", e),
|
VirtualNode::Element(e) => write!(f, "Node::{:?}", e),
|
||||||
VirtualNode::Text(t) => write!(f, "Node::{:?}", t),
|
VirtualNode::Text(t) => write!(f, "Node::{:?}", t),
|
||||||
VirtualNode::Component(c) => write!(f, "Node::{:?}", c),
|
// VirtualNode::Component(c) => write!(f, "Node::{:?}", c),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user