wip: pre vnodes instead of vnode
This commit is contained in:
1 parent
e3d9db0847
commit
fe6938ceb3
21 files changed
+303
-441
No files matched your search
+3
-3
@@ -5,11 +5,11 @@ members = [
|
|||||||
"packages/core",
|
"packages/core",
|
||||||
"packages/web",
|
"packages/web",
|
||||||
"packages/dioxus",
|
"packages/dioxus",
|
||||||
"packages/recoil",
|
|
||||||
"packages/docsite",
|
|
||||||
"packages/ssr",
|
"packages/ssr",
|
||||||
"packages/webview",
|
|
||||||
]
|
]
|
||||||
|
# "packages/recoil",
|
||||||
|
# "packages/docsite",
|
||||||
|
# "packages/webview",
|
||||||
|
|
||||||
# "packages/cli",
|
# "packages/cli",
|
||||||
# "packages/webview",
|
# "packages/webview",
|
||||||
|
|||||||
@@ -8,15 +8,13 @@
|
|||||||
Dioxus is a portable, performant, and ergonomic framework for building cross-platform user experiences in Rust.
|
Dioxus is a portable, performant, and ergonomic framework for building cross-platform user experiences in Rust.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
fn Example(ctx: Context<()>) -> VNode {
|
fn Example(ctx: Context<()>) -> VNodes {
|
||||||
let (selection, set_selection) = use_state(&ctx, move || "..?");
|
let (selection, set_selection) = use_state(&ctx, move || "..?");
|
||||||
|
|
||||||
ctx.render(rsx! {
|
ctx.render(rsx! {
|
||||||
div {
|
h1 { "Hello, {selection}" }
|
||||||
h1 { "Hello, {selection}" }
|
button { "?", onclick: move |_| set_selection("world!")}
|
||||||
button { "?", onclick: move |_| set_selection("world!")}
|
button { "?", onclick: move |_| set_selection("Dioxus 🎉")}
|
||||||
button { "?", onclick: move |_| set_selection("Dioxus 🎉")}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|||||||
+35
-35
@@ -2,41 +2,41 @@
|
|||||||
|
|
||||||
Sorted by priority
|
Sorted by priority
|
||||||
|
|
||||||
| Feature | Dioxus | React | Notes |
|
| Feature | Dioxus | React | Notes |
|
||||||
| ---------------------- | ------ | ----- | ------------------------------------ |
|
| ---------------------- | ------ | ----- | ------------------------------------------------ |
|
||||||
| ----- Phase 1 ----- | ----- | ----- | ----- |
|
| ----- Phase 1 ----- | ----- | ----- | ----- |
|
||||||
| Conditional Rendering | ✅ | ✅ | if/then to hide/show component |
|
| Conditional Rendering | ✅ | ✅ | if/then to hide/show component |
|
||||||
| Map, Iterator | ✅ | ✅ | map/filter/reduce rsx! |
|
| Map, Iterator | ✅ | ✅ | map/filter/reduce rsx! |
|
||||||
| Keyed Components | ✅ | ✅ | advanced diffing with keys |
|
| Keyed Components | ✅ | ✅ | advanced diffing with keys |
|
||||||
| Web | ✅ | ✅ | renderer for web browser |
|
| Web | ✅ | ✅ | renderer for web browser |
|
||||||
| Desktop (webview) | ✅ | ✅ | renderer for desktop |
|
| Desktop (webview) | ✅ | ✅ | renderer for desktop |
|
||||||
| Context | ✅ | ✅ | share state through the tree |
|
| Context | ✅ | ✅ | share state through the tree |
|
||||||
| Hook | ✅ | ✅ | memory cells in components |
|
| Hook | ✅ | ✅ | memory cells in components |
|
||||||
| SSR | ✅ | ✅ | render directly to string |
|
| SSR | ✅ | ✅ | render directly to string |
|
||||||
| Runs natively | ✅ | 👀 | runs as a sharable binary |
|
| Runs natively | ✅ | 👀 | runs as a sharable binary |
|
||||||
| Null components | 👀 | ✅ | allow returning None |
|
| Component Children | ✅ | ✅ | ctx.children() as a list of nodes |
|
||||||
| Fragments | 👀 | ✅ | no requirement on main root |
|
| Null components | ✅ | ✅ | allow returning no components |
|
||||||
| Component Children | 👀 | ✅ | ctx.children() as a list of nodes |
|
| No-div components | ✅ | ✅ | components that render components |
|
||||||
| NodeRef | 👀 | ✅ | gain direct access to nodes |
|
| Fragments | ✅ | ✅ | rsx! can return multiple elements without a root |
|
||||||
| Controlled Inputs | 👀 | ✅ | stateful wrappers around inputs |
|
| NodeRef | 👀 | ✅ | gain direct access to nodes |
|
||||||
| No-div components | 👀 | ✅ | components that render components |
|
| Controlled Inputs | 👀 | ✅ | stateful wrappers around inputs |
|
||||||
| CSS/Inline Styles | 🛠 | ✅ | syntax for inline/conditional styles |
|
| CSS/Inline Styles | 🛠 | ✅ | syntax for inline/conditional styles |
|
||||||
| 1st class global state | 🛠 | ✅ | redux/recoil/mobx on top of context |
|
| 1st class global state | 🛠 | ✅ | redux/recoil/mobx on top of context |
|
||||||
| ----- Phase 2 ----- | ----- | ----- | ----- |
|
| ----- Phase 2 ----- | ----- | ----- | ----- |
|
||||||
| 1st class router | 👀 | ✅ | Hook built on top of history |
|
| 1st class router | 👀 | ✅ | Hook built on top of history |
|
||||||
| Assets | 👀 | ✅ | include css/svg/img url statically |
|
| Assets | 👀 | ✅ | include css/svg/img url statically |
|
||||||
| Integrated classnames | 🛠 | 👀 | built-in `classnames` |
|
| Integrated classnames | 🛠 | 👀 | built-in `classnames` |
|
||||||
| Suspense | 👀 | 👀 | schedule future render from future |
|
| Suspense | 👀 | 👀 | schedule future render from future |
|
||||||
| Transition | 👀 | 👀 | High-level control over suspense |
|
| Transition | 👀 | 👀 | High-level control over suspense |
|
||||||
| Animation | 👀 | ✅ | Spring-style animations |
|
| Animation | 👀 | ✅ | Spring-style animations |
|
||||||
| Mobile | 👀 | ✅ | Render with cacao |
|
| Mobile | 👀 | ✅ | Render with cacao |
|
||||||
| Desktop (native) | 👀 | ✅ | Render with native desktop |
|
| Desktop (native) | 👀 | ✅ | Render with native desktop |
|
||||||
| 3D Renderer | 👀 | ✅ | react-three-fiber |
|
| 3D Renderer | 👀 | ✅ | react-three-fiber |
|
||||||
| ----- Phase 3 ----- | ----- | ----- | ----- |
|
| ----- Phase 3 ----- | ----- | ----- | ----- |
|
||||||
| Portal | 👀 | ✅ | cast elements through tree |
|
| Portal | 👀 | ✅ | cast elements through tree |
|
||||||
| Error/Panic boundary | 👀 | ✅ | catch panics and display BSOD |
|
| Error/Panic boundary | 👀 | ✅ | catch panics and display BSOD |
|
||||||
| Code-splitting | 👀 | ✅ | Make bundle smaller/lazy |
|
| Code-splitting | 👀 | ✅ | Make bundle smaller/lazy |
|
||||||
| LiveView | 👀 | 👀 | Example for SSR + WASM apps |
|
| LiveView | 👀 | 👀 | Example for SSR + WASM apps |
|
||||||
|
|
||||||
## Required services:
|
## Required services:
|
||||||
|
|
||||||
|
|||||||
@@ -50,15 +50,9 @@ impl Parse for AmbiguousElement {
|
|||||||
false => {
|
false => {
|
||||||
let first_char = name_str.chars().next().unwrap();
|
let first_char = name_str.chars().next().unwrap();
|
||||||
if first_char.is_ascii_uppercase() {
|
if first_char.is_ascii_uppercase() {
|
||||||
if name_str == "Fragment" {
|
input
|
||||||
input
|
.parse::<Component>()
|
||||||
.parse::<Fragment>()
|
.map(|c| AmbiguousElement::Component(c))
|
||||||
.map(|c| AmbiguousElement::Fragment(c))
|
|
||||||
} else {
|
|
||||||
input
|
|
||||||
.parse::<Component>()
|
|
||||||
.map(|c| AmbiguousElement::Component(c))
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
let name = input.parse::<Ident>().unwrap();
|
let name = input.parse::<Ident>().unwrap();
|
||||||
Err(Error::new(
|
Err(Error::new(
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ pub struct Component {
|
|||||||
// accept any path-like argument
|
// accept any path-like argument
|
||||||
name: syn::Path,
|
name: syn::Path,
|
||||||
body: Vec<ComponentField>,
|
body: Vec<ComponentField>,
|
||||||
_children: Vec<Node>,
|
children: Vec<Node>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for Component {
|
impl Parse for Component {
|
||||||
@@ -41,7 +41,7 @@ impl Parse for Component {
|
|||||||
syn::braced!(content in s);
|
syn::braced!(content in s);
|
||||||
|
|
||||||
let mut body: Vec<ComponentField> = Vec::new();
|
let mut body: Vec<ComponentField> = Vec::new();
|
||||||
let _children: Vec<Node> = Vec::new();
|
let mut children: Vec<Node> = Vec::new();
|
||||||
|
|
||||||
'parsing: loop {
|
'parsing: loop {
|
||||||
// [1] Break if empty
|
// [1] Break if empty
|
||||||
@@ -49,7 +49,7 @@ impl Parse for Component {
|
|||||||
break 'parsing;
|
break 'parsing;
|
||||||
}
|
}
|
||||||
|
|
||||||
if content.peek(token::Brace) {
|
if content.peek(token::Brace) && content.peek2(Token![...]) {
|
||||||
let inner: ParseBuffer;
|
let inner: ParseBuffer;
|
||||||
syn::braced!(inner in content);
|
syn::braced!(inner in content);
|
||||||
if inner.peek(Token![...]) {
|
if inner.peek(Token![...]) {
|
||||||
@@ -57,7 +57,11 @@ impl Parse for Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
body.push(content.parse::<ComponentField>()?);
|
if content.peek(Ident) && content.peek2(Token![:]) {
|
||||||
|
body.push(content.parse::<ComponentField>()?);
|
||||||
|
} else {
|
||||||
|
children.push(content.parse::<Node>()?);
|
||||||
|
}
|
||||||
|
|
||||||
// consume comma if it exists
|
// consume comma if it exists
|
||||||
// we don't actually care if there *are* commas between attrs
|
// we don't actually care if there *are* commas between attrs
|
||||||
@@ -66,13 +70,10 @@ impl Parse for Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: add support for children
|
|
||||||
let children: Vec<Node> = vec![];
|
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
name,
|
name,
|
||||||
body,
|
body,
|
||||||
_children: children,
|
children,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -109,9 +110,32 @@ impl ToTokens for Component {
|
|||||||
None => quote! {None},
|
None => quote! {None},
|
||||||
};
|
};
|
||||||
|
|
||||||
let _toks = tokens.append_all(quote! {
|
let childs = &self.children;
|
||||||
dioxus::builder::virtual_child(__ctx, #name, #builder, #key_token)
|
let children = quote! {
|
||||||
});
|
ChildrenList::new(__ctx)
|
||||||
|
#( .add_child(#childs) )*
|
||||||
|
.finish()
|
||||||
|
};
|
||||||
|
let name_str = name.segments.last().unwrap().ident.to_string();
|
||||||
|
match name_str.as_str() {
|
||||||
|
"Fragment" => tokens.append_all(quote! {
|
||||||
|
dioxus::builder::vfragment(
|
||||||
|
__ctx,
|
||||||
|
#key_token,
|
||||||
|
#children
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
_ => tokens.append_all(quote! {
|
||||||
|
dioxus::builder::virtual_child(
|
||||||
|
__ctx,
|
||||||
|
#name,
|
||||||
|
#builder,
|
||||||
|
#key_token,
|
||||||
|
#children
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -133,6 +133,10 @@ impl Parse for ElementAttr {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match name_str.as_str() {
|
match name_str.as_str() {
|
||||||
|
"key" => {
|
||||||
|
// todo: better error here
|
||||||
|
AttrType::BumpText(s.parse::<LitStr>()?)
|
||||||
|
}
|
||||||
"style" => {
|
"style" => {
|
||||||
//
|
//
|
||||||
todo!("inline style not yet supported")
|
todo!("inline style not yet supported")
|
||||||
@@ -196,10 +200,23 @@ impl ToTokens for ElementAttr {
|
|||||||
let name = self.name.to_string();
|
let name = self.name.to_string();
|
||||||
let nameident = &self.name;
|
let nameident = &self.name;
|
||||||
let _attr_stream = TokenStream2::new();
|
let _attr_stream = TokenStream2::new();
|
||||||
|
|
||||||
match &self.ty {
|
match &self.ty {
|
||||||
AttrType::BumpText(value) => {
|
AttrType::BumpText(value) => match name.as_str() {
|
||||||
|
"key" => {
|
||||||
|
tokens.append_all(quote! {
|
||||||
|
.key2(format_args_f!(#value))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
tokens.append_all(quote! {
|
||||||
|
.attr(#name, format_args_f!(#value))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
AttrType::FieldTokens(exp) => {
|
||||||
tokens.append_all(quote! {
|
tokens.append_all(quote! {
|
||||||
.attr(#name, format_args_f!(#value))
|
.attr(#name, #exp)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
AttrType::Event(event) => {
|
AttrType::Event(event) => {
|
||||||
@@ -207,16 +224,11 @@ impl ToTokens for ElementAttr {
|
|||||||
.add_listener(dioxus::events::on::#nameident(__ctx, #event))
|
.add_listener(dioxus::events::on::#nameident(__ctx, #event))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
AttrType::FieldTokens(exp) => {
|
|
||||||
tokens.append_all(quote! {
|
|
||||||
.attr(#name, #exp)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
AttrType::EventTokens(event) => {
|
AttrType::EventTokens(event) => {
|
||||||
//
|
//
|
||||||
tokens.append_all(quote! {
|
tokens.append_all(quote! {
|
||||||
.add_listener(dioxus::events::on::#nameident(__ctx, #event))
|
.add_listener(dioxus::events::on::#nameident(__ctx, #event))
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ static Header: FC<()> = |ctx| {
|
|||||||
ctx.render(dioxus::prelude::LazyNodes::new(|nodectx| {
|
ctx.render(dioxus::prelude::LazyNodes::new(|nodectx| {
|
||||||
builder::ElementBuilder::new(nodectx, "div")
|
builder::ElementBuilder::new(nodectx, "div")
|
||||||
.child(VNode::Component(nodectx.bump().alloc(VComponent::new(
|
.child(VNode::Component(nodectx.bump().alloc(VComponent::new(
|
||||||
|
nodectx,
|
||||||
Bottom,
|
Bottom,
|
||||||
(),
|
(),
|
||||||
None,
|
None,
|
||||||
|
|||||||
@@ -7,21 +7,12 @@
|
|||||||
|
|
||||||
use crate::innerlude::FC;
|
use crate::innerlude::FC;
|
||||||
|
|
||||||
pub type ScopeIdx = generational_arena::Index;
|
|
||||||
|
|
||||||
pub unsafe trait Properties: PartialEq + Sized {
|
pub unsafe trait Properties: PartialEq + Sized {
|
||||||
type Builder;
|
type Builder;
|
||||||
const CAN_BE_MEMOIZED: bool;
|
const CAN_BE_MEMOIZED: bool;
|
||||||
fn builder() -> Self::Builder;
|
fn builder() -> Self::Builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EmptyBuilder;
|
|
||||||
impl EmptyBuilder {
|
|
||||||
pub fn build(self) -> () {
|
|
||||||
()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Properties for () {
|
unsafe impl Properties for () {
|
||||||
const CAN_BE_MEMOIZED: bool = true;
|
const CAN_BE_MEMOIZED: bool = true;
|
||||||
type Builder = EmptyBuilder;
|
type Builder = EmptyBuilder;
|
||||||
@@ -31,151 +22,14 @@ unsafe impl Properties for () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fc_to_builder<T: Properties>(_f: FC<T>) -> T::Builder {
|
pub struct EmptyBuilder;
|
||||||
|
impl EmptyBuilder {
|
||||||
|
#[inline]
|
||||||
|
pub fn build(self) -> () {
|
||||||
|
()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fc_to_builder<T: Properties>(_: FC<T>) -> T::Builder {
|
||||||
T::builder()
|
T::builder()
|
||||||
}
|
}
|
||||||
|
|
||||||
mod testing {
|
|
||||||
use std::{any::Any, ops::Deref};
|
|
||||||
|
|
||||||
use crate::innerlude::VNode;
|
|
||||||
|
|
||||||
// trait PossibleProps {
|
|
||||||
// type POut: PartialEq;
|
|
||||||
// fn as_partial_eq(&self) -> Option<&Self::POut> {
|
|
||||||
// None
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// impl<T: PartialEq> PossibleProps for T {
|
|
||||||
// type POut = Self;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// struct SomeProps2<'a> {
|
|
||||||
// inner: &'a str,
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Fallback trait for to all types to default to `false`.
|
|
||||||
trait NotEq {
|
|
||||||
const IS_EQ: bool = false;
|
|
||||||
}
|
|
||||||
impl<T> NotEq for T {}
|
|
||||||
|
|
||||||
// Concrete wrapper type where `IS_COPY` becomes `true` if `T: Copy`.
|
|
||||||
struct IsEq<G, T>(std::marker::PhantomData<(G, T)>);
|
|
||||||
|
|
||||||
impl<G: PartialEq, T: PartialEq<G>> IsEq<G, T> {
|
|
||||||
// Because this is implemented directly on `IsCopy`, it has priority over
|
|
||||||
// the `NotCopy` trait impl.
|
|
||||||
//
|
|
||||||
// Note: this is a *totally different* associated constant from that in
|
|
||||||
// `NotCopy`. This does not specialize the `NotCopy` trait impl on `IsCopy`.
|
|
||||||
const IS_EQ: bool = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
|
||||||
struct SomeProps {
|
|
||||||
inner: &'static str,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SomeProps2 {
|
|
||||||
inner: &'static str,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test() {
|
|
||||||
let g = IsEq::<SomeProps, SomeProps>::IS_EQ;
|
|
||||||
|
|
||||||
// let g = IsEq::<Vec<u32>>::IS_COPY;
|
|
||||||
// let g = IsEq::<u32>::IS_COPY;
|
|
||||||
// dbg!(g);
|
|
||||||
|
|
||||||
// let props = SomeProps { inner: "asd" };
|
|
||||||
|
|
||||||
// let intermediate: Box<dyn PartialEq<SomeProps>> = Box::new(props);
|
|
||||||
// let as_any: Box<dyn Any> = Box::new(intermediate);
|
|
||||||
|
|
||||||
// let as_partialeq = as_any
|
|
||||||
// .downcast_ref::<Box<dyn PartialEq<SomeProps>>>()
|
|
||||||
// .unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
// struct blah {}
|
|
||||||
// #[reorder_args]
|
|
||||||
pub fn blah(a: i32, b: &str, c: &str) {}
|
|
||||||
|
|
||||||
// pub mod blah {
|
|
||||||
// pub const a: u8 = 0;
|
|
||||||
// pub const b: u8 = 1;
|
|
||||||
// }
|
|
||||||
|
|
||||||
trait Eat {}
|
|
||||||
impl Eat for fn() {}
|
|
||||||
impl<T> Eat for fn(T) {}
|
|
||||||
impl<T, K> Eat for fn(T, K) {}
|
|
||||||
|
|
||||||
mod other {
|
|
||||||
use super::blah;
|
|
||||||
fn test2() {
|
|
||||||
// rsx!{
|
|
||||||
// div {
|
|
||||||
// Ele {
|
|
||||||
// a: 10,
|
|
||||||
// b: "asd"
|
|
||||||
// c: impl Fn() -> ()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// becomes
|
|
||||||
|
|
||||||
// const reorder: fn(_, _) = |a, b| {};
|
|
||||||
// blah::META;
|
|
||||||
// let a = 10;
|
|
||||||
// let b = "asd";
|
|
||||||
// let g = [10, 10.0];
|
|
||||||
// let c = g.a;
|
|
||||||
|
|
||||||
// blah(10, "asd");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Inner<'a> {
|
|
||||||
a: String,
|
|
||||||
b: i32,
|
|
||||||
c: &'a str,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Custom<'a, P: 'a> {
|
|
||||||
inner: &'a P,
|
|
||||||
// inner: *const (),
|
|
||||||
_p: std::marker::PhantomData<&'a P>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, P> Custom<'a, P> {
|
|
||||||
fn props(&self) -> &P {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// impl<P> Deref for Custom<P> {
|
|
||||||
// type Target = Inner;
|
|
||||||
|
|
||||||
// fn deref(&self) -> &Self::Target {
|
|
||||||
// unsafe { &*self.inner }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
fn test2<'a>(a: Custom<'a, Inner<'a>>) -> VNode {
|
|
||||||
let r = a.inner;
|
|
||||||
|
|
||||||
todo!()
|
|
||||||
// let g = a.props();
|
|
||||||
// todo!()
|
|
||||||
// let g = &a.a;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_comp() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod style {}
|
|
||||||
+28
-20
@@ -201,11 +201,13 @@ impl<'a> DiffMachine<'a> {
|
|||||||
todo!("Suspended components not currently available")
|
todo!("Suspended components not currently available")
|
||||||
}
|
}
|
||||||
|
|
||||||
// (VNode::Fragment(_), VNode::Fragment(_)) => {
|
|
||||||
// todo!("Fragments not currently supported in diffing")
|
|
||||||
// }
|
|
||||||
// Fragments are special
|
// Fragments are special
|
||||||
(VNode::Fragment(_), _) | (_, VNode::Fragment(_)) => {
|
// we actually have to remove a bunch of nodes
|
||||||
|
(VNode::Fragment(_), _) => {
|
||||||
|
todo!("Fragments not currently supported in diffing")
|
||||||
|
}
|
||||||
|
|
||||||
|
(_, VNode::Fragment(_)) => {
|
||||||
todo!("Fragments not currently supported in diffing")
|
todo!("Fragments not currently supported in diffing")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -227,7 +229,7 @@ impl<'a> DiffMachine<'a> {
|
|||||||
self.change_list.create_text_node(text);
|
self.change_list.create_text_node(text);
|
||||||
}
|
}
|
||||||
VNode::Element(&VElement {
|
VNode::Element(&VElement {
|
||||||
key: _,
|
key,
|
||||||
tag_name,
|
tag_name,
|
||||||
listeners,
|
listeners,
|
||||||
attributes,
|
attributes,
|
||||||
@@ -266,7 +268,12 @@ impl<'a> DiffMachine<'a> {
|
|||||||
|
|
||||||
for child in children {
|
for child in children {
|
||||||
self.create(child);
|
self.create(child);
|
||||||
self.change_list.append_child();
|
if let VNode::Fragment(_) = child {
|
||||||
|
// do nothing
|
||||||
|
// fragments append themselves
|
||||||
|
} else {
|
||||||
|
self.change_list.append_child();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,22 +291,23 @@ impl<'a> DiffMachine<'a> {
|
|||||||
// those references are stable, even if the component arena moves around in memory, thanks to the bump arenas.
|
// those references are stable, even if the component arena moves around in memory, thanks to the bump arenas.
|
||||||
// However, there is no way to convey this to rust, so we need to use unsafe to pierce through the lifetime.
|
// However, there is no way to convey this to rust, so we need to use unsafe to pierce through the lifetime.
|
||||||
|
|
||||||
|
let parent_idx = self.cur_idx;
|
||||||
|
|
||||||
// Insert a new scope into our component list
|
// Insert a new scope into our component list
|
||||||
let idx = self
|
let idx = self
|
||||||
.components
|
.components
|
||||||
.with(|components| {
|
.with(|components| {
|
||||||
components.insert_with(|new_idx| {
|
components.insert_with(|new_idx| {
|
||||||
let cur_idx = self.cur_idx;
|
let parent_scope = self.components.try_get(parent_idx).unwrap();
|
||||||
let cur_scope = self.components.try_get(cur_idx).unwrap();
|
let height = parent_scope.height + 1;
|
||||||
let height = cur_scope.height + 1;
|
|
||||||
Scope::new(
|
Scope::new(
|
||||||
caller,
|
caller,
|
||||||
new_idx,
|
new_idx,
|
||||||
Some(cur_idx),
|
Some(parent_idx),
|
||||||
height,
|
height,
|
||||||
self.event_queue.new_channel(height, new_idx),
|
self.event_queue.new_channel(height, new_idx),
|
||||||
self.components.clone(),
|
self.components.clone(),
|
||||||
&[],
|
component.children,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -323,24 +331,24 @@ impl<'a> DiffMachine<'a> {
|
|||||||
// Run the scope for one iteration to initialize it
|
// Run the scope for one iteration to initialize it
|
||||||
new_component.run_scope().unwrap();
|
new_component.run_scope().unwrap();
|
||||||
|
|
||||||
// // Navigate the diff machine to the right point in the output dom
|
|
||||||
// self.change_list.load_known_root(id);
|
|
||||||
// let root_id = component.stable_addr
|
|
||||||
|
|
||||||
// And then run the diff algorithm
|
// And then run the diff algorithm
|
||||||
self.diff_node(new_component.old_frame(), new_component.next_frame());
|
self.diff_node(new_component.old_frame(), new_component.next_frame());
|
||||||
|
|
||||||
// Finally, insert this node as a seen node.
|
// Finally, insert this node as a seen node.
|
||||||
self.seen_nodes.insert(idx);
|
self.seen_nodes.insert(idx);
|
||||||
}
|
}
|
||||||
VNode::Suspended => {
|
|
||||||
todo!("Creation of VNode::Suspended not yet supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
// we go the the "known root" but only operate on a sibling basis
|
// we go the the "known root" but only operate on a sibling basis
|
||||||
VNode::Fragment(frag) => {
|
VNode::Fragment(frag) => {
|
||||||
//
|
// create the children directly in the space
|
||||||
todo!("Cannot current create fragments")
|
for child in frag.children {
|
||||||
|
self.create(child);
|
||||||
|
self.change_list.append_child();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VNode::Suspended => {
|
||||||
|
todo!("Creation of VNode::Suspended not yet supported")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,8 +87,6 @@ pub mod builder {
|
|||||||
pub use super::nodebuilder::*;
|
pub use super::nodebuilder::*;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod support;
|
|
||||||
|
|
||||||
// types used internally that are important
|
// types used internally that are important
|
||||||
pub(crate) mod innerlude {
|
pub(crate) mod innerlude {
|
||||||
pub use crate::component::*;
|
pub use crate::component::*;
|
||||||
@@ -122,14 +120,12 @@ pub mod prelude {
|
|||||||
|
|
||||||
pub use crate::nodebuilder::LazyNodes;
|
pub use crate::nodebuilder::LazyNodes;
|
||||||
|
|
||||||
|
pub use crate::nodebuilder::ChildrenList;
|
||||||
pub use crate::virtual_dom::NodeCtx;
|
pub use crate::virtual_dom::NodeCtx;
|
||||||
// pub use nodes::iterables::IterableNodes;
|
// pub use nodes::iterables::IterableNodes;
|
||||||
/// This type alias is an internal way of abstracting over the static functions that represent components.
|
/// This type alias is an internal way of abstracting over the static functions that represent components.
|
||||||
pub use crate::innerlude::FC;
|
pub use crate::innerlude::FC;
|
||||||
|
|
||||||
// TODO @Jon, fix this
|
|
||||||
// hack the VNode type until VirtualNode is fixed in the macro crate
|
|
||||||
|
|
||||||
// expose our bumpalo type
|
// expose our bumpalo type
|
||||||
pub use bumpalo;
|
pub use bumpalo;
|
||||||
pub use bumpalo::Bump;
|
pub use bumpalo::Bump;
|
||||||
@@ -141,19 +137,9 @@ pub mod prelude {
|
|||||||
|
|
||||||
pub use dioxus_core_macro::{format_args_f, html, rsx, Props};
|
pub use dioxus_core_macro::{format_args_f, html, rsx, Props};
|
||||||
|
|
||||||
pub use crate::component::ScopeIdx;
|
|
||||||
pub use crate::diff::DiffMachine;
|
pub use crate::diff::DiffMachine;
|
||||||
|
pub use crate::virtual_dom::ScopeIdx;
|
||||||
|
|
||||||
pub use crate::debug_renderer::DebugRenderer;
|
pub use crate::debug_renderer::DebugRenderer;
|
||||||
pub use crate::dioxus_main;
|
|
||||||
pub use crate::hooks::*;
|
pub use crate::hooks::*;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! dioxus_main {
|
|
||||||
($i:ident) => {
|
|
||||||
fn main() {
|
|
||||||
todo!("this macro is a placeholder for launching a dioxus app on different platforms. \nYou probably don't want to use this, but it's okay for small apps.")
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
//! Helpers for building virtual DOM VNodes.
|
//! Helpers for building virtual DOM VNodes.
|
||||||
|
|
||||||
use std::{any::Any, borrow::BorrowMut, intrinsics::transmute, u128};
|
use std::{any::Any, borrow::BorrowMut, fmt::Arguments, intrinsics::transmute, u128};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
events::VirtualEvent,
|
events::VirtualEvent,
|
||||||
innerlude::{Properties, VComponent, FC},
|
innerlude::{Properties, VComponent, FC},
|
||||||
nodes::{Attribute, Listener, NodeKey, VNode},
|
nodes::{Attribute, Listener, NodeKey, VNode},
|
||||||
prelude::VElement,
|
prelude::{VElement, VFragment},
|
||||||
virtual_dom::NodeCtx,
|
virtual_dom::NodeCtx,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -269,6 +269,20 @@ where
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn key2(mut self, args: Arguments) -> Self {
|
||||||
|
let key = match args.as_str() {
|
||||||
|
Some(static_str) => static_str,
|
||||||
|
None => {
|
||||||
|
use bumpalo::core_alloc::fmt::Write;
|
||||||
|
let mut s = bumpalo::collections::String::new_in(self.ctx.bump());
|
||||||
|
s.write_fmt(args).unwrap();
|
||||||
|
s.into_bump_str()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self.key = NodeKey(Some(key));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Create the virtual DOM VNode described by this builder.
|
/// Create the virtual DOM VNode described by this builder.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
@@ -655,14 +669,49 @@ pub fn virtual_child<'a, T: Properties + 'a>(
|
|||||||
f: FC<T>,
|
f: FC<T>,
|
||||||
props: T,
|
props: T,
|
||||||
key: Option<&'a str>, // key: NodeKey<'a>,
|
key: Option<&'a str>, // key: NodeKey<'a>,
|
||||||
|
children: &'a [VNode<'a>],
|
||||||
) -> VNode<'a> {
|
) -> VNode<'a> {
|
||||||
// currently concerned about if props have a custom drop implementation
|
// currently concerned about if props have a custom drop implementation
|
||||||
// might override it with the props macro
|
// might override it with the props macro
|
||||||
// todo!()
|
// todo!()
|
||||||
VNode::Component(
|
VNode::Component(
|
||||||
ctx.bump()
|
ctx.bump()
|
||||||
.alloc(crate::nodes::VComponent::new(ctx.bump(), f, props, key)),
|
.alloc(crate::nodes::VComponent::new(ctx, f, props, key, children)),
|
||||||
// ctx.bump()
|
// ctx.bump()
|
||||||
// .alloc(crate::nodes::VComponent::new(f, props, key)),
|
// .alloc(crate::nodes::VComponent::new(f, props, key)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn vfragment<'a>(
|
||||||
|
ctx: &NodeCtx<'a>,
|
||||||
|
key: Option<&'a str>, // key: NodeKey<'a>,
|
||||||
|
children: &'a [VNode<'a>],
|
||||||
|
) -> VNode<'a> {
|
||||||
|
VNode::Fragment(ctx.bump().alloc(VFragment::new(key, children)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ChildrenList<'a, 'b> {
|
||||||
|
ctx: &'b NodeCtx<'a>,
|
||||||
|
children: bumpalo::collections::Vec<'a, VNode<'a>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> ChildrenList<'a, 'b> {
|
||||||
|
pub fn new(ctx: &'b NodeCtx<'a>) -> Self {
|
||||||
|
Self {
|
||||||
|
ctx,
|
||||||
|
children: bumpalo::collections::Vec::new_in(ctx.bump()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_child(mut self, nodes: impl IntoIterator<Item = impl IntoVNode<'a>>) -> Self {
|
||||||
|
for item in nodes {
|
||||||
|
let child = item.into_vnode(&self.ctx);
|
||||||
|
self.children.push(child);
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn finish(self) -> &'a [VNode<'a>] {
|
||||||
|
self.children.into_bump_slice()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,8 @@ use crate::{
|
|||||||
events::VirtualEvent,
|
events::VirtualEvent,
|
||||||
innerlude::{Context, Properties, Scope, ScopeIdx, FC},
|
innerlude::{Context, Properties, Scope, ScopeIdx, FC},
|
||||||
nodebuilder::text3,
|
nodebuilder::text3,
|
||||||
|
virtual_dom::NodeCtx,
|
||||||
|
// support::NodeCtx,
|
||||||
};
|
};
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use std::{
|
use std::{
|
||||||
@@ -238,7 +240,6 @@ pub struct VComponent<'src> {
|
|||||||
|
|
||||||
// a pointer to the raw fn typ
|
// a pointer to the raw fn typ
|
||||||
pub user_fc: *const (),
|
pub user_fc: *const (),
|
||||||
_p: PhantomData<&'src ()>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> VComponent<'a> {
|
impl<'a> VComponent<'a> {
|
||||||
@@ -249,14 +250,17 @@ impl<'a> VComponent<'a> {
|
|||||||
// we want them to borrow references... maybe force implementing a "to_static_unsafe" trait
|
// we want them to borrow references... maybe force implementing a "to_static_unsafe" trait
|
||||||
|
|
||||||
pub fn new<P: Properties + 'a>(
|
pub fn new<P: Properties + 'a>(
|
||||||
bump: &'a Bump,
|
// bump: &'a Bump,
|
||||||
|
ctx: &NodeCtx<'a>,
|
||||||
component: FC<P>,
|
component: FC<P>,
|
||||||
// props: bumpalo::boxed::Box<'a, P>,
|
// props: bumpalo::boxed::Box<'a, P>,
|
||||||
props: P,
|
props: P,
|
||||||
key: Option<&'a str>,
|
key: Option<&'a str>,
|
||||||
|
children: &'a [VNode<'a>],
|
||||||
) -> Self {
|
) -> Self {
|
||||||
// pub fn new<P: Properties + 'a>(component: FC<P>, props: P, key: Option<&'a str>) -> Self {
|
// pub fn new<P: Properties + 'a>(component: FC<P>, props: P, key: Option<&'a str>) -> Self {
|
||||||
// let bad_props = unsafe { transmogrify(props) };
|
// let bad_props = unsafe { transmogrify(props) };
|
||||||
|
let bump = ctx.bump();
|
||||||
let caller_ref = component as *const ();
|
let caller_ref = component as *const ();
|
||||||
let props = bump.alloc(props);
|
let props = bump.alloc(props);
|
||||||
|
|
||||||
@@ -319,8 +323,7 @@ impl<'a> VComponent<'a> {
|
|||||||
user_fc: caller_ref,
|
user_fc: caller_ref,
|
||||||
comparator,
|
comparator,
|
||||||
raw_props,
|
raw_props,
|
||||||
_p: PhantomData,
|
children,
|
||||||
children: &[],
|
|
||||||
caller,
|
caller,
|
||||||
stable_addr: RefCell::new(None),
|
stable_addr: RefCell::new(None),
|
||||||
}
|
}
|
||||||
@@ -355,3 +358,14 @@ pub struct VFragment<'src> {
|
|||||||
pub key: NodeKey<'src>,
|
pub key: NodeKey<'src>,
|
||||||
pub children: &'src [VNode<'src>],
|
pub children: &'src [VNode<'src>],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> VFragment<'a> {
|
||||||
|
pub fn new(key: Option<&'a str>, children: &'a [VNode<'a>]) -> Self {
|
||||||
|
let key = match key {
|
||||||
|
Some(key) => NodeKey::new(key),
|
||||||
|
None => NodeKey(None),
|
||||||
|
};
|
||||||
|
|
||||||
|
Self { key, children }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,165 +0,0 @@
|
|||||||
use crate::{arena::ScopeArena, innerlude::*};
|
|
||||||
use bumpalo::Bump;
|
|
||||||
use generational_arena::Arena;
|
|
||||||
use std::{
|
|
||||||
any::{Any, TypeId},
|
|
||||||
cell::RefCell,
|
|
||||||
collections::{HashMap, HashSet, VecDeque},
|
|
||||||
fmt::Debug,
|
|
||||||
future::Future,
|
|
||||||
ops::Deref,
|
|
||||||
pin::Pin,
|
|
||||||
rc::{Rc, Weak},
|
|
||||||
};
|
|
||||||
// We actually allocate the properties for components in their parent's properties
|
|
||||||
// We then expose a handle to use those props for render in the form of "OpaqueComponent"
|
|
||||||
pub(crate) type OpaqueComponent<'e> = dyn Fn(&'e Scope) -> VNode<'e> + 'e;
|
|
||||||
// pub(crate) type OpaqueComponent<'e> = dyn for<'b> Fn(&'b Scope) -> VNode<'b> + 'e;
|
|
||||||
|
|
||||||
#[derive(PartialEq, Debug, Clone, Default)]
|
|
||||||
pub(crate) struct EventQueue(pub Rc<RefCell<Vec<HeightMarker>>>);
|
|
||||||
|
|
||||||
impl EventQueue {
|
|
||||||
pub fn new_channel(&self, height: u32, idx: ScopeIdx) -> Rc<dyn Fn()> {
|
|
||||||
let inner = self.clone();
|
|
||||||
let marker = HeightMarker { height, idx };
|
|
||||||
Rc::new(move || inner.0.as_ref().borrow_mut().push(marker))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A helper type that lets scopes be ordered by their height
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
pub(crate) struct HeightMarker {
|
|
||||||
pub idx: ScopeIdx,
|
|
||||||
pub height: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Ord for HeightMarker {
|
|
||||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
|
||||||
self.height.cmp(&other.height)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialOrd for HeightMarker {
|
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
||||||
Some(self.cmp(other))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NodeCtx is used to build VNodes in the component's memory space.
|
|
||||||
// This struct adds metadata to the final VNode about listeners, attributes, and children
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct NodeCtx<'a> {
|
|
||||||
pub scope_ref: &'a Scope,
|
|
||||||
pub listener_id: RefCell<usize>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> NodeCtx<'a> {
|
|
||||||
pub fn bump(&self) -> &'a Bump {
|
|
||||||
&self.scope_ref.cur_frame().bump
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Debug for NodeCtx<'_> {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Hash)]
|
|
||||||
pub struct ContextId {
|
|
||||||
// Which component is the scope in
|
|
||||||
original: ScopeIdx,
|
|
||||||
|
|
||||||
// What's the height of the scope
|
|
||||||
height: u32,
|
|
||||||
|
|
||||||
// Which scope is it (in order)
|
|
||||||
id: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ActiveFrame {
|
|
||||||
// We use a "generation" for users of contents in the bump frames to ensure their data isn't broken
|
|
||||||
pub generation: RefCell<usize>,
|
|
||||||
|
|
||||||
// The double-buffering situation that we will use
|
|
||||||
pub frames: [BumpFrame; 2],
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct BumpFrame {
|
|
||||||
pub bump: Bump,
|
|
||||||
pub head_node: VNode<'static>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ActiveFrame {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self::from_frames(
|
|
||||||
BumpFrame {
|
|
||||||
bump: Bump::new(),
|
|
||||||
head_node: VNode::text(""),
|
|
||||||
},
|
|
||||||
BumpFrame {
|
|
||||||
bump: Bump::new(),
|
|
||||||
head_node: VNode::text(""),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn from_frames(a: BumpFrame, b: BumpFrame) -> Self {
|
|
||||||
Self {
|
|
||||||
generation: 0.into(),
|
|
||||||
frames: [a, b],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn cur_frame(&self) -> &BumpFrame {
|
|
||||||
match *self.generation.borrow() & 1 == 0 {
|
|
||||||
true => &self.frames[0],
|
|
||||||
false => &self.frames[1],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub(crate) fn cur_frame_mut(&mut self) -> &mut BumpFrame {
|
|
||||||
match *self.generation.borrow() & 1 == 0 {
|
|
||||||
true => &mut self.frames[0],
|
|
||||||
false => &mut self.frames[1],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn current_head_node<'b>(&'b self) -> &'b VNode<'b> {
|
|
||||||
let raw_node = match *self.generation.borrow() & 1 == 0 {
|
|
||||||
true => &self.frames[0],
|
|
||||||
false => &self.frames[1],
|
|
||||||
};
|
|
||||||
|
|
||||||
// Give out our self-referential item with our own borrowed lifetime
|
|
||||||
unsafe {
|
|
||||||
let unsafe_head = &raw_node.head_node;
|
|
||||||
let safe_node = std::mem::transmute::<&VNode<'static>, &VNode<'b>>(unsafe_head);
|
|
||||||
safe_node
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn prev_head_node<'b>(&'b self) -> &'b VNode<'b> {
|
|
||||||
let raw_node = match *self.generation.borrow() & 1 != 0 {
|
|
||||||
true => &self.frames[0],
|
|
||||||
false => &self.frames[1],
|
|
||||||
};
|
|
||||||
|
|
||||||
// Give out our self-referential item with our own borrowed lifetime
|
|
||||||
unsafe {
|
|
||||||
let unsafe_head = &raw_node.head_node;
|
|
||||||
let safe_node = std::mem::transmute::<&VNode<'static>, &VNode<'b>>(unsafe_head);
|
|
||||||
safe_node
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn next(&mut self) -> &mut BumpFrame {
|
|
||||||
*self.generation.borrow_mut() += 1;
|
|
||||||
|
|
||||||
if *self.generation.borrow() % 2 == 0 {
|
|
||||||
&mut self.frames[0]
|
|
||||||
} else {
|
|
||||||
&mut self.frames[1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -32,6 +32,7 @@ use std::{
|
|||||||
pin::Pin,
|
pin::Pin,
|
||||||
rc::{Rc, Weak},
|
rc::{Rc, Weak},
|
||||||
};
|
};
|
||||||
|
pub type ScopeIdx = generational_arena::Index;
|
||||||
|
|
||||||
/// An integrated virtual node system that progresses events and diffs UI trees.
|
/// 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.
|
/// Differences are converted into patches which a renderer can use to draw the UI.
|
||||||
@@ -420,8 +421,10 @@ impl Scope {
|
|||||||
>(caller)
|
>(caller)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let child_nodes = unsafe { std::mem::transmute(child_nodes) };
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
child_nodes: &[],
|
child_nodes: child_nodes,
|
||||||
caller,
|
caller,
|
||||||
parent,
|
parent,
|
||||||
arena_idx,
|
arena_idx,
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ fn use_map() {}
|
|||||||
// Elements are received as Rc<T> in case the underlying collection is shuffled around
|
// Elements are received as Rc<T> in case the underlying collection is shuffled around
|
||||||
// Setters/getters can be generated
|
// Setters/getters can be generated
|
||||||
fn use_collection<'a, T: Collection>(
|
fn use_collection<'a, T: Collection>(
|
||||||
ctx: &Context<'a>,
|
ctx: &impl Scoped<'a>,
|
||||||
f: impl Fn() -> T,
|
f: impl Fn() -> T,
|
||||||
) -> CollectionHandle<'a, T> {
|
) -> CollectionHandle<'a, T> {
|
||||||
ctx.use_hook(
|
ctx.use_hook(
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ fn update_title(api: &RecoilApi) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static App: FC<()> = |ctx| {
|
static App: FC<()> = |ctx| {
|
||||||
let title = use_read(ctx, &TITLE);
|
let title = use_read(&ctx, &TITLE);
|
||||||
let next_light = use_recoil_api(ctx, |api| move |_| update_title(&api));
|
let next_light = use_recoil_api(ctx, |api| move |_| update_title(&api));
|
||||||
|
|
||||||
rsx! { in ctx,
|
rsx! { in ctx,
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
//! Basic example that renders a simple VNode to the browser.
|
||||||
|
|
||||||
|
use dioxus_core::prelude::*;
|
||||||
|
use dioxus_web::*;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Setup logging
|
||||||
|
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
|
||||||
|
console_error_panic_hook::set_once();
|
||||||
|
|
||||||
|
// Run the app
|
||||||
|
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
|
||||||
|
}
|
||||||
|
|
||||||
|
static App: FC<()> = |ctx| {
|
||||||
|
ctx.render(rsx! {
|
||||||
|
Calcier {
|
||||||
|
h2 {"abc 1"}
|
||||||
|
h2 {"abc 2"}
|
||||||
|
h2 {"abc 3"}
|
||||||
|
h2 {"abc 4"}
|
||||||
|
h2 {"abc 5"}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
static Calcier: FC<()> = |ctx| {
|
||||||
|
ctx.render(rsx! {
|
||||||
|
div {
|
||||||
|
h1 {
|
||||||
|
"abc 0"
|
||||||
|
}
|
||||||
|
{ctx.children()}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
@@ -52,7 +52,7 @@ struct ButtonProps {
|
|||||||
id: u8,
|
id: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn CustomButton(ctx: Context, props: &ButtonProps) -> VNode {
|
fn CustomButton(ctx: Context<ButtonProps>) -> VNode {
|
||||||
let names = ctx.use_context::<CustomContext>();
|
let names = ctx.use_context::<CustomContext>();
|
||||||
let name = names.0[ctx.id as usize];
|
let name = names.0[ctx.id as usize];
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
//! Basic example that renders a simple VNode to the browser.
|
||||||
|
|
||||||
|
use dioxus_core::prelude::*;
|
||||||
|
use dioxus_web::*;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Setup logging
|
||||||
|
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
|
||||||
|
console_error_panic_hook::set_once();
|
||||||
|
|
||||||
|
// Run the app
|
||||||
|
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
|
||||||
|
}
|
||||||
|
|
||||||
|
static App: FC<()> = |ctx| {
|
||||||
|
ctx.render(rsx! {
|
||||||
|
h2 { "abc 1" }
|
||||||
|
h2 { "abc 1" }
|
||||||
|
h2 { "abc 1" }
|
||||||
|
h2 { "abc 1" }
|
||||||
|
h2 { "abc 1" }
|
||||||
|
h2 { "abc 1" }
|
||||||
|
div {
|
||||||
|
"hello world!"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
use dioxus_core::prelude::*;
|
||||||
|
use dioxus_web::WebsysRenderer;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
|
||||||
|
console_error_panic_hook::set_once();
|
||||||
|
|
||||||
|
log::info!("hello world");
|
||||||
|
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(Example));
|
||||||
|
}
|
||||||
|
|
||||||
|
static Example: FC<()> = |ctx| {
|
||||||
|
ctx.render(rsx! {
|
||||||
|
div {
|
||||||
|
span {
|
||||||
|
class: "px-2 py-1 flex w-36 mt-4 items-center text-xs rounded-md font-semibold text-yellow-500 bg-yellow-100"
|
||||||
|
"DUE DATE : 18 JUN"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
@@ -53,7 +53,7 @@ struct ButtonProps<'src, F: Fn(MouseEvent)> {
|
|||||||
handler: F
|
handler: F
|
||||||
}
|
}
|
||||||
|
|
||||||
fn CustomButton<'b, 'a, F: Fn(MouseEvent)>(ctx: Context<'a>, props: &'b ButtonProps<'b, F>) -> VNode {
|
fn CustomButton<'a, F: Fn(MouseEvent)>(ctx: Context<'a, ButtonProps<'a, F>>) -> VNode {
|
||||||
ctx.render(rsx!{
|
ctx.render(rsx!{
|
||||||
button {
|
button {
|
||||||
class: "inline-block py-4 px-8 mr-6 leading-none text-white bg-indigo-600 hover:bg-indigo-900 font-semibold rounded shadow"
|
class: "inline-block py-4 px-8 mr-6 leading-none text-white bg-indigo-600 hover:bg-indigo-900 font-semibold rounded shadow"
|
||||||
@@ -74,7 +74,7 @@ impl<F: Fn(MouseEvent)> PartialEq for ButtonProps<'_, F> {
|
|||||||
struct PlaceholderProps {
|
struct PlaceholderProps {
|
||||||
val: &'static str
|
val: &'static str
|
||||||
}
|
}
|
||||||
fn Placeholder(ctx: Context, props: &PlaceholderProps) -> VNode {
|
fn Placeholder(ctx: Context<PlaceholderProps>) -> VNode {
|
||||||
ctx.render(rsx!{
|
ctx.render(rsx!{
|
||||||
div {
|
div {
|
||||||
"child: {ctx.val}"
|
"child: {ctx.val}"
|
||||||
|
|||||||
Reference in new issue
Block a user