Feat: listeners now have scope information

This commit is contained in:
Jonathan Kelley committed 2021-03-03 11:13:46 -05:00
1 parent cb74d70f83
commit fcd68e61d2
17 files changed
+897 -906

No files matched your search

+1
View File
@@ -48,6 +48,7 @@ mod tests {
ctx.render(html! {
<div>
</div>
})
};
+16 -6
View File
@@ -31,6 +31,8 @@ use std::{
pub struct Context<'src> {
pub idx: AtomicUsize,
pub scope: ScopeIdx,
// Borrowed from scope
pub(crate) arena: &'src typed_arena::Arena<Hook>,
pub(crate) hooks: &'src RefCell<Vec<*mut Hook>>,
@@ -76,12 +78,17 @@ impl<'a> Context<'a> {
/// ctx.render(lazy_tree)
/// }
///```
pub fn render(self, lazy_nodes: impl FnOnce(NodeCtx<'a>) -> VNode<'a> + 'a) -> DomTree {
let ctx = NodeCtx { bump: self.bump };
let safe_nodes = lazy_nodes(ctx);
pub fn render(self, lazy_nodes: impl FnOnce(&'a NodeCtx<'a>) -> VNode<'a> + 'a) -> DomTree {
let ctx = NodeCtx {
bump: self.bump,
idx: 0.into(),
scope: self.scope,
};
todo!();
// let safe_nodes = lazy_nodes(&ctx);
let unsafe_nodes = unsafe { std::mem::transmute::<VNode<'a>, VNode<'static>>(safe_nodes) };
self.final_nodes.deref().borrow_mut().replace(unsafe_nodes);
// let unsafe_nodes = unsafe { std::mem::transmute::<VNode<'a>, VNode<'static>>(safe_nodes) };
// self.final_nodes.deref().borrow_mut().replace(unsafe_nodes);
DomTree {}
}
@@ -100,8 +107,11 @@ impl<'a> Context<'a> {
// NodeCtx is used to build VNodes in the component's memory space.
// This struct adds metadata to the final DomTree about listeners, attributes, and children
#[derive(Debug, Clone)]
pub struct NodeCtx<'a> {
bump: &'a Bump,
pub bump: &'a Bump,
pub idx: RefCell<usize>,
pub scope: ScopeIdx,
}
impl NodeCtx<'_> {
+20 -97
View File
@@ -78,12 +78,6 @@ impl<'a> DiffMachine<'a> {
new: &VNode<'a>,
// scope: Option<generational_arena::Index>,
) {
log::debug!("old {:#?}", old);
log::debug!("new {:#?}", new);
// Set it while diffing
// Reset it when finished diffing
// self.current_idx = scope;
/*
For each valid case, we "commit traversal", meaning we save this current position in the tree.
Then, we diff and queue an edit event (via chagelist). s single trees - when components show up, we save that traversal and then re-enter later.
@@ -98,7 +92,6 @@ impl<'a> DiffMachine<'a> {
}
}
// Definitely different, need to commit update
(VNode::Text(_), VNode::Element(_)) => {
// TODO: Hook up the events properly
// todo!("Hook up events registry");
@@ -109,112 +102,37 @@ impl<'a> DiffMachine<'a> {
self.change_list.replace_with();
}
// Definitely different, need to commit update
(VNode::Element(_), VNode::Text(_)) => {
self.change_list.commit_traversal();
self.create(new);
// create(cached_set, self.change_list, registry, new, cached_roots);
// Note: text nodes cannot have event listeners, so we don't need to
// remove the old node's listeners from our registry her.
self.change_list.replace_with();
}
// compare elements
// if different, schedule different types of update
(VNode::Element(eold), VNode::Element(enew)) => {
// log::debug!("elements are different");
// If the element type is completely different, the element needs to be re-rendered completely
if enew.tag_name != eold.tag_name || enew.namespace != eold.namespace {
self.change_list.commit_traversal();
// create(cached_set, self.change_list, registry, new, cached_roots);
// registry.remove_subtree(&old);
self.change_list.replace_with();
return;
}
self.diff_listeners(eold.listeners, enew.listeners);
self.diff_attr(eold.attributes, enew.attributes, enew.namespace.is_some());
self.diff_children(eold.children, enew.children);
}
// No immediate change to dom. If props changed though, queue a "props changed" update
// However, mark these for a
(VNode::Component(_), VNode::Component(_)) => {
todo!("Usage of component VNode not currently supported");
// // Both the new and old nodes are cached.
// (&NodeKind::Cached(ref new), &NodeKind::Cached(ref old)) => {
// cached_roots.insert(new.id);
// if new.id == old.id {
// // This is the same cached node, so nothing has changed!
// return;
// }
// let (new, new_template) = cached_set.get(new.id);
// let (old, old_template) = cached_set.get(old.id);
// if new_template == old_template {
// // If they are both using the same template, then just diff the
// // subtrees.
// diff(cached_set, change_list, registry, old, new, cached_roots);
// } else {
// // Otherwise, they are probably different enough that
// // re-constructing the subtree from scratch should be faster.
// // This doubly holds true if we have a new template.
// change_list.commit_traversal();
// create_and_replace(
// cached_set,
// change_list,
// registry,
// new_template,
// old,
// new,
// cached_roots,
// );
// }
// }
// queue a lifecycle event.
// no change
}
// A component has been birthed!
// Queue its arrival
(_, VNode::Component(_)) => {
todo!("Usage of component VNode not currently supported");
// // Old cached node and new non-cached node. Again, assume that they are
// // probably pretty different and create the new non-cached node afresh.
// (_, &NodeKind::Cached(_)) => {
// change_list.commit_traversal();
// create(cached_set, change_list, registry, new, cached_roots);
// registry.remove_subtree(&old);
// change_list.replace_with();
// }
// }
}
// A component was removed :(
// Queue its removal
(VNode::Component(_), _) => {
// // New cached node when the old node was not cached. In this scenario,
// // we assume that they are pretty different, and it isn't worth diffing
// // the subtrees, so we just create the new cached node afresh.
// (&NodeKind::Cached(ref c), _) => {
// change_list.commit_traversal();
// cached_roots.insert(c.id);
// let (new, new_template) = cached_set.get(c.id);
// create_and_replace(
// cached_set,
// change_list,
// registry,
// new_template,
// old,
// new,
// cached_roots,
// );
// }
todo!("Usage of component VNode not currently supported");
}
// A suspended component appeared!
// Don't do much, just wait
(VNode::Suspended, _) | (_, VNode::Suspended) => {
// (VNode::Element(_), VNode::Suspended) => {}
// (VNode::Text(_), VNode::Suspended) => {}
@@ -254,17 +172,19 @@ impl<'a> DiffMachine<'a> {
if new_l.event == old_l.event {
// if let Some(scope) = self.current_idx {
// let cb = CbIdx::from_gi_index(scope, l_idx);
self.change_list.update_event_listener(event_type, cb);
self.change_list
.update_event_listener(event_type, new_l.scope, new_l.id);
// }
continue 'outer1;
}
}
if let Some(scope) = self.current_idx {
let cb = CbIdx::from_gi_index(scope, l_idx);
self.change_list.new_event_listener(event_type, cb);
}
// if let Some(scope) = self.current_idx {
// let cb = CbIdx::from_gi_index(scope, l_idx);
self.change_list
.new_event_listener(event_type, new_l.scope, new_l.id);
// }
}
'outer2: for old_l in old {
@@ -893,14 +813,17 @@ impl<'a> DiffMachine<'a> {
}
listeners.iter().enumerate().for_each(|(id, listener)| {
if let Some(index) = self.current_idx {
self.change_list
.new_event_listener(listener.event, CbIdx::from_gi_index(index, id));
} else {
// Don't panic
// Used for testing
log::trace!("Failed to set listener, create was not called in the context of the virtual dom");
}
// if let Some(index) = self.current_idx {
self.change_list.new_event_listener(
listener.event,
listener.scope,
listener.id,
);
// } else {
// Don't panic
// Used for testing
// log::trace!("Failed to set listener, create was not called in the context of the virtual dom");
// }
});
// for l in listeners {
// unsafe {
+51 -631
View File
@@ -3,6 +3,7 @@
use std::ops::Deref;
use crate::{
context::NodeCtx,
events::VirtualEvent,
innerlude::VComponent,
nodes::{Attribute, Listener, NodeKey, VNode},
@@ -17,14 +18,14 @@ use bumpalo::Bump;
/// Typically constructed with element-specific constructors, eg the `div`
/// function for building `<div>` elements or the `button` function for building
/// `<button>` elements.
#[derive(Clone, Debug)]
#[derive(Debug)]
pub struct ElementBuilder<'a, Listeners, Attributes, Children>
where
Listeners: 'a + AsRef<[Listener<'a>]>,
Attributes: 'a + AsRef<[Attribute<'a>]>,
Children: 'a + AsRef<[VNode<'a>]>,
{
bump: &'a Bump,
ctx: &'a NodeCtx<'a>,
key: NodeKey,
tag_name: &'a str,
listeners: Listeners,
@@ -64,13 +65,11 @@ impl<'a>
/// let my_element_builder = ElementBuilder::new(&b, tag_name);
/// # fn flip_coin() -> bool { true }
/// ```
pub fn new<B>(bump: B, tag_name: &'a str) -> Self
where
B: Into<&'a Bump>,
{
let bump = bump.into();
pub fn new(ctx: &'a NodeCtx<'a>, tag_name: &'static str) -> Self {
// pub fn new<B>(ctx: &'a mut NodeCtx<'a>, tag_name: &'a str) -> Self {
let bump = ctx.bump();
ElementBuilder {
bump,
ctx,
key: NodeKey::NONE,
tag_name,
listeners: bumpalo::collections::Vec::new_in(bump),
@@ -120,7 +119,7 @@ where
L: 'a + AsRef<[Listener<'a>]>,
{
ElementBuilder {
bump: self.bump,
ctx: self.ctx,
key: self.key,
tag_name: self.tag_name,
listeners,
@@ -159,7 +158,7 @@ where
A: 'a + AsRef<[Attribute<'a>]>,
{
ElementBuilder {
bump: self.bump,
ctx: self.ctx,
key: self.key,
tag_name: self.tag_name,
listeners: self.listeners,
@@ -198,7 +197,7 @@ where
C: 'a + AsRef<[VNode<'a>]>,
{
ElementBuilder {
bump: self.bump,
ctx: self.ctx,
key: self.key,
tag_name: self.tag_name,
listeners: self.listeners,
@@ -225,7 +224,7 @@ where
#[inline]
pub fn namespace(self, namespace: Option<&'a str>) -> Self {
ElementBuilder {
bump: self.bump,
ctx: self.ctx,
key: self.key,
tag_name: self.tag_name,
listeners: self.listeners,
@@ -291,17 +290,17 @@ where
/// ```
#[inline]
pub fn finish(self) -> VNode<'a> {
let children: &'a Children = self.bump.alloc(self.children);
let children: &'a Children = self.ctx.bump().alloc(self.children);
let children: &'a [VNode<'a>] = children.as_ref();
let listeners: &'a Listeners = self.bump.alloc(self.listeners);
let listeners: &'a Listeners = self.ctx.bump().alloc(self.listeners);
let listeners: &'a [Listener<'a>] = listeners.as_ref();
let attributes: &'a Attributes = self.bump.alloc(self.attributes);
let attributes: &'a Attributes = self.ctx.bump().alloc(self.attributes);
let attributes: &'a [Attribute<'a>] = attributes.as_ref();
VNode::element(
self.bump,
self.ctx.bump(),
self.key,
self.tag_name,
listeners,
@@ -340,10 +339,18 @@ where
/// ```
#[inline]
pub fn on(mut self, event: &'static str, callback: impl Fn(VirtualEvent) + 'a) -> Self {
// todo:
// increment listner id from nodectx ref
// add listener attrs here instead of later?
self.listeners.push(Listener {
event,
callback: self.bump.alloc(callback),
callback: self.ctx.bump.alloc(callback),
id: *self.ctx.idx.borrow(),
scope: self.ctx.scope,
});
// bump the context id forward
*self.ctx.idx.borrow_mut() += 1;
self
}
}
@@ -435,593 +442,6 @@ where
}
}
macro_rules! builder_constructors {
( $(
$(#[$attr:meta])*
$name:ident;
)* ) => {
$(
$(#[$attr])*
#[inline]
pub fn $name<'a, B>(
bump: B,
) -> ElementBuilder<
'a,
bumpalo::collections::Vec<'a, Listener<'a>>,
bumpalo::collections::Vec<'a, Attribute<'a>>,
bumpalo::collections::Vec<'a, VNode<'a>>,
>
where
B: Into<&'a Bump>
{
ElementBuilder::new(bump, stringify!($name))
}
)*
};
( $(
$(#[$attr:meta])*
$name:ident <> $namespace:tt;
)* ) => {
$(
$(#[$attr])*
#[inline]
pub fn $name<'a>(
bump: &'a Bump,
) -> ElementBuilder<
'a,
bumpalo::collections::Vec<'a, Listener<'a>>,
bumpalo::collections::Vec<'a, Attribute<'a>>,
bumpalo::collections::Vec<'a, VNode<'a>>,
> {
let builder = ElementBuilder::new(bump, stringify!($name));
builder.namespace(Some($namespace))
}
)*
}
}
// Organized in the same order as
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element
//
// Does not include obsolete elements.
builder_constructors! {
// Document metadata
/// Build a
/// [`<base>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base)
/// element.
base;
/// Build a
/// [`<head>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/head)
/// element.
head;
/// Build a
/// [`<link>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link)
/// element.
link;
/// Build a
/// [`<meta>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta)
/// element.
meta;
/// Build a
/// [`<style>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/style)
/// element.
style;
/// Build a
/// [`<title>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/title)
/// element.
title;
// Sectioning root
/// Build a
/// [`<body>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/body)
/// element.
body;
// Content sectioning
/// Build a
/// [`<address>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/address)
/// element.
address;
/// Build a
/// [`<article>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/article)
/// element.
article;
/// Build a
/// [`<aside>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/aside)
/// element.
aside;
/// Build a
/// [`<footer>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/footer)
/// element.
footer;
/// Build a
/// [`<header>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/header)
/// element.
header;
/// Build a
/// [`<h1>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/h1)
/// element.
h1;
/// Build a
/// [`<h2>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/h2)
/// element.
h2;
/// Build a
/// [`<h3>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/h3)
/// element.
h3;
/// Build a
/// [`<h4>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/h4)
/// element.
h4;
/// Build a
/// [`<h5>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/h5)
/// element.
h5;
/// Build a
/// [`<h6>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/h6)
/// element.
h6;
/// Build a
/// [`<hgroup>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/hgroup)
/// element.
hgroup;
/// Build a
/// [`<main>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/main)
/// element.
main;
/// Build a
/// [`<nav>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/nav)
/// element.
nav;
/// Build a
/// [`<section>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/section)
/// element.
section;
// Text content
/// Build a
/// [`<blockquote>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/blockquote)
/// element.
blockquote;
/// Build a
/// [`<dd>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dd)
/// element.
dd;
/// Build a
/// [`<div>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/div)
/// element.
div;
/// Build a
/// [`<dl>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dl)
/// element.
dl;
/// Build a
/// [`<dt>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dt)
/// element.
dt;
/// Build a
/// [`<figcaption>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/figcaption)
/// element.
figcaption;
/// Build a
/// [`<figure>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/figure)
/// element.
figure;
/// Build a
/// [`<hr>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/hr)
/// element.
hr;
/// Build a
/// [`<li>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/li)
/// element.
li;
/// Build a
/// [`<ol>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ol)
/// element.
ol;
/// Build a
/// [`<p>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/p)
/// element.
p;
/// Build a
/// [`<pre>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/pre)
/// element.
pre;
/// Build a
/// [`<ul>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul)
/// element.
ul;
// Inline text semantics
/// Build a
/// [`<a>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a)
/// element.
a;
/// Build a
/// [`<abbr>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/abbr)
/// element.
abbr;
/// Build a
/// [`<b>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/b)
/// element.
b;
/// Build a
/// [`<bdi>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/bdi)
/// element.
bdi;
/// Build a
/// [`<bdo>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/bdo)
/// element.
bdo;
/// Build a
/// [`<br>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/br)
/// element.
br;
/// Build a
/// [`<cite>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/cite)
/// element.
cite;
/// Build a
/// [`<code>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/code)
/// element.
code;
/// Build a
/// [`<data>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/data)
/// element.
data;
/// Build a
/// [`<dfn>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dfn)
/// element.
dfn;
/// Build a
/// [`<em>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/em)
/// element.
em;
/// Build a
/// [`<i>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/i)
/// element.
i;
/// Build a
/// [`<kbd>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/kbd)
/// element.
kbd;
/// Build a
/// [`<mark>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/mark)
/// element.
mark;
/// Build a
/// [`<q>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/q)
/// element.
q;
/// Build a
/// [`<rb>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/rb)
/// element.
rb;
/// Build a
/// [`<rp>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/rp)
/// element.
rp;
/// Build a
/// [`<rt>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/rt)
/// element.
rt;
/// Build a
/// [`<rtc>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/rtc)
/// element.
rtc;
/// Build a
/// [`<ruby>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ruby)
/// element.
ruby;
/// Build a
/// [`<s>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/s)
/// element.
s;
/// Build a
/// [`<samp>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/samp)
/// element.
samp;
/// Build a
/// [`<small>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/small)
/// element.
small;
/// Build a
/// [`<span>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/span)
/// element.
span;
/// Build a
/// [`<strong>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/strong)
/// element.
strong;
/// Build a
/// [`<sub>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/sub)
/// element.
sub;
/// Build a
/// [`<sup>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/sup)
/// element.
sup;
/// Build a
/// [`<time>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/time)
/// element.
time;
/// Build a
/// [`<u>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/u)
/// element.
u;
/// Build a
/// [`<var>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/var)
/// element.
var;
/// Build a
/// [`<wbr>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/wbr)
/// element.
wbr;
// Image and multimedia
/// Build a
/// [`<area>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/area)
/// element.
area;
/// Build a
/// [`<audio>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/audio)
/// element.
audio;
/// Build a
/// [`<img>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img)
/// element.
img;
/// Build a
/// [`<map>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/map)
/// element.
map;
/// Build a
/// [`<track>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/track)
/// element.
track;
/// Build a
/// [`<video>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video)
/// element.
video;
// Embedded content
/// Build a
/// [`<embed>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/embed)
/// element.
embed;
/// Build a
/// [`<iframe>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe)
/// element.
iframe;
/// Build a
/// [`<object>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/object)
/// element.
object;
/// Build a
/// [`<param>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/param)
/// element.
param;
/// Build a
/// [`<picture>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture)
/// element.
picture;
/// Build a
/// [`<source>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/source)
/// element.
source;
// Scripting
/// Build a
/// [`<canvas>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/canvas)
/// element.
canvas;
/// Build a
/// [`<noscript>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/noscript)
/// element.
noscript;
/// Build a
/// [`<script>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script)
/// element.
script;
// Demarcating edits
/// Build a
/// [`<del>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/del)
/// element.
del;
/// Build a
/// [`<ins>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ins)
/// element.
ins;
// Table content
/// Build a
/// [`<caption>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/caption)
/// element.
caption;
/// Build a
/// [`<col>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/col)
/// element.
col;
/// Build a
/// [`<colgroup>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/colgroup)
/// element.
colgroup;
/// Build a
/// [`<table>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/table)
/// element.
table;
/// Build a
/// [`<tbody>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/tbody)
/// element.
tbody;
/// Build a
/// [`<td>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/td)
/// element.
td;
/// Build a
/// [`<tfoot>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/tfoot)
/// element.
tfoot;
/// Build a
/// [`<th>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/th)
/// element.
th;
/// Build a
/// [`<thead>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/thead)
/// element.
thead;
/// Build a
/// [`<tr>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/tr)
/// element.
tr;
// Forms
/// Build a
/// [`<button>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button)
/// element.
button;
/// Build a
/// [`<datalist>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/datalist)
/// element.
datalist;
/// Build a
/// [`<fieldset>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/fieldset)
/// element.
fieldset;
/// Build a
/// [`<form>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form)
/// element.
form;
/// Build a
/// [`<input>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input)
/// element.
input;
/// Build a
/// [`<label>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/label)
/// element.
label;
/// Build a
/// [`<legend>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/legend)
/// element.
legend;
/// Build a
/// [`<meter>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meter)
/// element.
meter;
/// Build a
/// [`<optgroup>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/optgroup)
/// element.
optgroup;
/// Build a
/// [`<option>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/option)
/// element.
option;
/// Build a
/// [`<output>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/output)
/// element.
output;
/// Build a
/// [`<progress>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/progress)
/// element.
progress;
/// Build a
/// [`<select>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/select)
/// element.
select;
/// Build a
/// [`<textarea>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea)
/// element.
textarea;
// Interactive elements
/// Build a
/// [`<details>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details)
/// element.
details;
/// Build a
/// [`<dialog>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog)
/// element.
dialog;
/// Build a
/// [`<menu>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/menu)
/// element.
menu;
/// Build a
/// [`<menuitem>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/menuitem)
/// element.
menuitem;
/// Build a
/// [`<summary>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/summary)
/// element.
summary;
// Web components
/// Build a
/// [`<slot>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/slot)
/// element.
slot;
/// Build a
/// [`<template>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template)
/// element.
template;
}
builder_constructors! {
// SVG components
/// Build a
/// [`<svg>`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/svg)
/// element.
svg <> "http://www.w3.org/2000/svg" ;
/// Build a
/// [`<path>`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/path)
/// element.
path <> "http://www.w3.org/2000/svg";
/// Build a
/// [`<circle>`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/circle)
/// element.
circle <> "http://www.w3.org/2000/svg";
/// Build a
/// [`<ellipse>`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/ellipse)
/// element.
ellipse <> "http://www.w3.org/2000/svg";
/// Build a
/// [`<line>`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/line)
/// element.
line <> "http://www.w3.org/2000/svg";
/// Build a
/// [`<polygon>`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/polygon)
/// element.
polygon <> "http://www.w3.org/2000/svg";
/// Build a
/// [`<polyline>`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/polyline)
/// element.
polyline <> "http://www.w3.org/2000/svg";
/// Build a
/// [`<rect>`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/rect)
/// element.
rect <> "http://www.w3.org/2000/svg";
/// Build a
/// [`<image>`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/image)
/// element.
image <> "http://www.w3.org/2000/svg";
}
/// Construct a text VNode.
///
/// This is `dioxus`'s virtual DOM equivalent of `document.createTextVNode`.
@@ -1062,33 +482,33 @@ pub fn attr<'a>(name: &'static str, value: &'a str) -> Attribute<'a> {
Attribute { name, value }
}
/// Create an event listener.
///
/// `event` is the type of event to listen for, e.g. `"click"`. The `callback`
/// is the function that will be invoked when the event occurs.
///
/// # Example
///
/// ```no_run
/// use dioxus::{builder::*, bumpalo::Bump};
///
/// let b = Bump::new();
///
/// let listener = on(&b, "click", |root, vdom, event| {
/// // do something when a click happens...
/// });
/// ```
pub fn on<'a, 'b>(
// pub fn on<'a, 'b, F: 'static>(
bump: &'a Bump,
event: &'static str,
callback: impl Fn(VirtualEvent) + 'a,
) -> Listener<'a> {
Listener {
event,
callback: bump.alloc(callback),
}
}
// /// Create an event listener.
// ///
// /// `event` is the type of event to listen for, e.g. `"click"`. The `callback`
// /// is the function that will be invoked when the event occurs.
// ///
// /// # Example
// ///
// /// ```no_run
// /// use dioxus::{builder::*, bumpalo::Bump};
// ///
// /// let b = Bump::new();
// ///
// /// let listener = on(&b, "click", |root, vdom, event| {
// /// // do something when a click happens...
// /// });
// /// ```
// pub fn on<'a, 'b>(
// // pub fn on<'a, 'b, F: 'static>(
// bump: &'a Bump,
// event: &'static str,
// callback: impl Fn(VirtualEvent) + 'a,
// ) -> Listener<'a> {
// Listener {
// event,
// callback: bump.alloc(callback),
// }
// }
pub fn virtual_child<'a, T>(_bump: &'a Bump, _props: T, _f: crate::innerlude::FC<T>) -> VNode<'a> {
todo!()
+6 -3
View File
@@ -97,6 +97,8 @@ mod velement {
// use crate::{events::VirtualEvent, innerlude::CbIdx};
use crate::{events::VirtualEvent, innerlude::ScopeIdx};
use super::*;
use std::fmt::Debug;
@@ -182,7 +184,8 @@ mod velement {
pub struct ListenerHandle {
pub event: &'static str,
pub idx: CbIdx,
pub scope: ScopeIdx,
pub id: usize,
}
/// An event listener.
@@ -190,8 +193,8 @@ mod velement {
/// The type of event to listen for.
pub(crate) event: &'static str,
// ref to the real listener
// pub(crate) id: u32,
pub scope: ScopeIdx,
pub id: usize,
// pub(crate) _i: &'bump str,
// #[serde(skip_serializing, skip_deserializing, default="")]
+34 -51
View File
@@ -58,7 +58,15 @@ pub enum Edit<'d> {
PopPushReverseChild { n: u32 },
RemoveChild { n: u32 },
SetClass { class_name: &'d str },
PushKnown { node: ScopeIdx },
// push a known node on to the stack
TraverseToKnown { node: ScopeIdx },
// Add the current top of the stack to the known nodes
MakeKnown { node: ScopeIdx },
// Remove the current top of the stack from the known nodes
RemoveKnown,
}
pub type EditList<'src> = Vec<Edit<'src>>;
@@ -67,7 +75,6 @@ pub struct EditMachine<'src> {
pub traversal: Traversal,
next_temporary: u32,
forcing_new_listeners: bool,
pub emitter: EditList<'src>,
}
@@ -80,8 +87,12 @@ impl<'b> EditMachine<'b> {
emitter: EditList::default(),
}
}
}
/// Traversal methods.
// ===================================
// Traversal Methods
// ===================================
impl<'b> EditMachine<'b> {
pub fn go_down(&mut self) {
self.traversal.down();
}
@@ -158,6 +169,9 @@ impl<'b> EditMachine<'b> {
}
}
// ===================================
// Stack methods
// ===================================
impl<'a> EditMachine<'a> {
pub fn next_temporary(&self) -> u32 {
self.next_temporary
@@ -205,11 +219,6 @@ impl<'a> EditMachine<'a> {
self.emitter.push(Edit::InsertBefore {})
}
pub fn ensure_string(&mut self, _string: &str) -> StringKey {
todo!()
// self.strings.ensure_string(string, &self.emitter)
}
pub fn set_text(&mut self, text: &'a str) {
debug_assert!(self.traversal_is_committed());
// debug!("emit: set_text({:?})", text);
@@ -307,42 +316,26 @@ impl<'a> EditMachine<'a> {
self.forcing_new_listeners = previous;
}
pub fn new_event_listener(&mut self, event: &'a str, idx: CbIdx) {
pub fn new_event_listener(&mut self, event: &'a str, scope: ScopeIdx, id: usize) {
debug_assert!(self.traversal_is_committed());
self.emitter.push(Edit::NewEventListener {
event_type: event,
s: idx,
s: scope,
});
// todo!("Event listener not wired up yet");
// log::debug!("emit: new_event_listener({:?})", listener);
// let (a, b) = listener.get_callback_parts();
// debug_assert!(a != 0);
// // let event_id = self.ensure_string(listener.event);
// self.emitter.new_event_listener(listener.event.into(), a, b);
}
pub fn update_event_listener(&mut self, event: &'a str, idx: CbIdx) {
pub fn update_event_listener(&mut self, event: &'a str, scope: ScopeIdx, id: usize) {
debug_assert!(self.traversal_is_committed());
if self.forcing_new_listeners {
self.new_event_listener(event, idx);
self.new_event_listener(event, scope, id);
return;
}
self.emitter.push(Edit::NewEventListener {
event_type: event,
s: idx,
s: scope,
});
// log::debug!("emit: update_event_listener({:?})", listener);
// // todo!("Event listener not wired up yet");
// let (a, b) = listener.get_callback_parts();
// debug_assert!(a != 0);
// self.emitter.push(Edit::UpdateEventListener {
// event_type: listener.event.into(),
// a,
// b,
// });
// self.emitter.update_event_listener(event_id.into(), a, b);
}
pub fn remove_event_listener(&mut self, event: &'a str) {
@@ -350,16 +343,8 @@ impl<'a> EditMachine<'a> {
self.emitter
.push(Edit::RemoveEventListener { event_type: event });
// debug!("emit: remove_event_listener({:?})", event);
// let _event_id = self.ensure_string(event);
// todo!("Event listener not wired up yet");
// self.emitter.remove_event_listener(event_id.into());
}
// #[inline]
// pub fn has_template(&mut self, id: CacheId) -> bool {
// self.templates.contains(&id)
// }
// pub fn save_template(&mut self, id: CacheId) {
// debug_assert!(self.traversal_is_committed());
// debug_assert!(!self.has_template(id));
@@ -516,10 +501,8 @@ impl Traversal {
/// Commit this traversals moves and return the optimized path from the last
/// commit.
#[inline]
pub fn commit(&mut self) -> Moves {
Moves {
inner: self.uncommitted.drain(..),
}
pub fn commit(&mut self) -> std::vec::Drain<'_, MoveTo> {
self.uncommitted.drain(..)
}
#[inline]
@@ -528,18 +511,18 @@ impl Traversal {
}
}
pub struct Moves<'a> {
inner: std::vec::Drain<'a, MoveTo>,
}
// pub struct Moves<'a> {
// inner: std::vec::Drain<'a, MoveTo>,
// }
impl Iterator for Moves<'_> {
type Item = MoveTo;
// impl Iterator for Moves<'_> {
// type Item = MoveTo;
#[inline]
fn next(&mut self) -> Option<MoveTo> {
self.inner.next()
}
}
// #[inline]
// fn next(&mut self) -> Option<MoveTo> {
// self.inner.next()
// }
// }
#[cfg(test)]
mod tests {
+52 -30
View File
@@ -45,13 +45,21 @@ pub struct Scope {
// lying, cheating reference >:(
pub props: Box<dyn std::any::Any>,
// our own index
pub myidx: ScopeIdx,
// pub props_type: TypeId,
pub caller: *const (),
}
impl Scope {
// create a new scope from a function
pub fn new<'a, P1, P2: 'static>(f: FC<P1>, props: P1, parent: Option<ScopeIdx>) -> Self {
pub fn new<'a, P1, P2: 'static>(
f: FC<P1>,
props: P1,
myidx: ScopeIdx,
parent: Option<ScopeIdx>,
) -> Self {
let hook_arena = typed_arena::Arena::new();
let hooks = RefCell::new(Vec::new());
@@ -79,6 +87,7 @@ impl Scope {
let props = unsafe { std::mem::transmute::<_, Box<P2>>(props) };
Self {
myidx,
hook_arena,
hooks,
caller,
@@ -109,6 +118,7 @@ impl Scope {
idx: 0.into(),
_p: PhantomData {},
final_nodes: node_slot.clone(),
scope: self.myidx,
};
unsafe {
@@ -276,25 +286,34 @@ mod tests {
#[test]
fn check_listeners() -> Result<()> {
let mut scope = Scope::new::<(), ()>(ListenerTest, (), None);
scope.run::<()>();
todo!()
// let mut scope = Scope::new::<(), ()>(ListenerTest, (), None);
// scope.run::<()>();
let nodes = scope.new_frame();
dbg!(nodes);
// let nodes = scope.new_frame();
// dbg!(nodes);
Ok(())
// Ok(())
}
#[test]
fn test_scope() {
let example: FC<()> = |ctx, props| {
use crate::builder::*;
ctx.render(|ctx| div(ctx.bump()).child(text("a")).finish())
ctx.render(|ctx| {
builder::ElementBuilder::new(ctx, "div")
.child(text("a"))
.finish()
})
};
let props = ();
let parent = None;
let scope = Scope::new::<(), ()>(example, props, parent);
let mut nodes = generational_arena::Arena::new();
nodes.insert_with(|f| {
let scope = Scope::new::<(), ()>(example, props, f, parent);
//
});
}
#[derive(Debug)]
@@ -320,39 +339,42 @@ mod tests {
let childprops: ExampleProps<'a> = ExampleProps { name: content };
// let childprops: ExampleProps<'a> = ExampleProps { name: content };
ctx.render(move |ctx| {
let b = ctx.bump();
div(b)
.child(text(props.name))
// .child(text(props.name))
.child(virtual_child::<ExampleProps>(b, childprops, child_example))
// .child(virtual_child::<ExampleProps<'a>>(b, childprops, CHILD))
// as for<'scope> fn(Context<'_>, &'scope ExampleProps<'scope>) -> DomTree
// |ctx, pops| todo!(),
// .child(virtual_child::<'a>(
// b,
// child_example,
// ExampleProps { name: text },
// ))
.finish()
todo!()
// let b = ctx.bump();
// div(b)
// .child(text(props.name))
// // .child(text(props.name))
// .child(virtual_child::<ExampleProps>(b, childprops, child_example))
// // .child(virtual_child::<ExampleProps<'a>>(b, childprops, CHILD))
// // as for<'scope> fn(Context<'_>, &'scope ExampleProps<'scope>) -> DomTree
// // |ctx, pops| todo!(),
// // .child(virtual_child::<'a>(
// // b,
// // child_example,
// // ExampleProps { name: text },
// // ))
// .finish()
})
}
fn child_example<'b>(ctx: Context<'b>, props: &'b ExampleProps) -> DomTree {
ctx.render(move |ctx| {
div(ctx.bump())
.child(text(props.name))
//
.finish()
todo!()
// div(ctx.bump())
// .child(text(props.name))
// //
// .finish()
})
}
static CHILD: FC<ExampleProps> = |ctx, props: &'_ ExampleProps| {
// todo!()
ctx.render(move |ctx| {
div(ctx.bump())
.child(text(props.name))
//
.finish()
todo!()
// div(ctx.bump())
// .child(text(props.name))
// //
// .finish()
})
};
#[test]
+8 -6
View File
@@ -56,7 +56,8 @@ impl VirtualDom {
// Create a reference to the component in the arena
// Note: we are essentially running the "Mount" lifecycle event manually while the vdom doesnt yet exist
// This puts the dom in a usable state on creation, rather than being potentially invalid
let base_scope = components.insert(Scope::new::<_, P>(root, root_props, None));
let base_scope =
components.insert_with(|id| Scope::new::<_, P>(root, root_props, id, None));
// evaluate the component, pushing any updates its generates into the lifecycle queue
// todo!
@@ -277,11 +278,12 @@ mod tests {
#[test]
fn start_dom() {
let mut dom = VirtualDom::new(|ctx, props| {
ctx.render(|ctx| {
use crate::builder::*;
let bump = ctx.bump();
div(bump).child(text("hello, world")).finish()
})
todo!()
// ctx.render(|ctx| {
// use crate::builder::*;
// let bump = ctx.bump();
// div(bump).child(text("hello, world")).finish()
// })
});
let edits = dom.rebuild().unwrap();
println!("{:#?}", edits);