Feat: dioxus frontend crate
This commit is contained in:
1 parent
6c1205e91b
commit
4d7ac5bb5d
13 files changed
+465
-15
No files matched your search
@@ -1,10 +1,12 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
# Built-in
|
# Built-in
|
||||||
|
"packages/dioxus",
|
||||||
"packages/core",
|
"packages/core",
|
||||||
"packages/hooks",
|
"packages/hooks",
|
||||||
"packages/recoil",
|
"packages/recoil",
|
||||||
"packages/redux",
|
"packages/redux",
|
||||||
|
"packages/core-macro",
|
||||||
# TODO @Jon, share the validation code
|
# TODO @Jon, share the validation code
|
||||||
# "packages/web",
|
# "packages/web",
|
||||||
"packages/cli",
|
"packages/cli",
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
# Subscriptions
|
||||||
|
|
||||||
|
Yew subscriptions are used to schedule update for components into the future. The `Context` object can create subscriptions:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn Component(ctx: Component<()>) -> VNode {
|
||||||
|
let update = ctx.schedule();
|
||||||
|
|
||||||
|
// Now, when the subscription is called, the component will be re-evaluted
|
||||||
|
update.consume();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Whenever a component's subscription is called, the component will then re-evaluated. You can consider the input properties of
|
||||||
|
a component to be just another form of subscription. By default, the Dioxus component system automatically diffs a component's props
|
||||||
|
when the parent function is called, and if the props are different, the child component's subscription is called.
|
||||||
|
|
||||||
|
The subscription API exposes this functionality allowing hooks and state management solutions the ability to update components whenever
|
||||||
|
some state or event occurs outside of the component. For instance, the `use_context` hook uses this to subscribe components that use a
|
||||||
|
particular context.
|
||||||
|
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn use_context<I>(ctx: Context<T>) -> I {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
+16
-1
@@ -9,14 +9,21 @@ edition = "2018"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
fern = { version = "0.6.0", features = ["colored"] }
|
fern = { version = "0.6.0", features = ["colored"] }
|
||||||
log = "0.4.1"
|
log = "0.4.1"
|
||||||
dioxus-core = { path = "../packages/core" }
|
dioxus = { path = "../packages/dioxus" }
|
||||||
rand = "0.8.2"
|
rand = "0.8.2"
|
||||||
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
# For the tide ssr examples
|
||||||
async-std = { version = "1.9.0", features = ["attributes"] }
|
async-std = { version = "1.9.0", features = ["attributes"] }
|
||||||
tide = { version = "0.15.0" }
|
tide = { version = "0.15.0" }
|
||||||
|
|
||||||
|
# For the doc generator
|
||||||
|
pulldown-cmark = { version = "0.8.0", default-features = false }
|
||||||
|
|
||||||
|
|
||||||
|
anyhow = "*"
|
||||||
|
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "common.rs"
|
path = "common.rs"
|
||||||
@@ -28,3 +35,11 @@ name = "hello"
|
|||||||
[[example]]
|
[[example]]
|
||||||
path = "tide_ssr.rs"
|
path = "tide_ssr.rs"
|
||||||
name = "tide_ssr"
|
name = "tide_ssr"
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
path = "doc_generator.rs"
|
||||||
|
name = "doc_generator"
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
path = "router.rs"
|
||||||
|
name = "router"
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
//! The docs generator takes in the `docs` folder and creates a neat, statically-renderer webpage.
|
||||||
|
//! These docs are used to generate the public-facing doc content, showcasing Dioxus' abiltity to
|
||||||
|
//! be used in custom static rendering pipelines.
|
||||||
|
//!
|
||||||
|
//! We use pulldown_cmark as the markdown parser, but instead of outputting html directly, we output
|
||||||
|
//! VNodes to be used in conjuction with our custom templates.
|
||||||
|
|
||||||
|
use dioxus::core::prelude::*;
|
||||||
|
use pulldown_cmark::{Options, Parser};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let gen_dir = "../docs/";
|
||||||
|
|
||||||
|
let site: FC<()> = |_| {
|
||||||
|
html! {
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static Homepage: FC<()> = |_| {
|
||||||
|
html! {<div> </div>}
|
||||||
|
};
|
||||||
|
|
||||||
|
static DocPage: FC<()> = |_| {
|
||||||
|
html! {<div> </div>}
|
||||||
|
};
|
||||||
|
|
||||||
|
// struct StaticSiteCfg {
|
||||||
|
// gen_dir: &'static str,
|
||||||
|
// homepage_template: fn() -> VNode,
|
||||||
|
// page_template: fn(page: &'static str) -> VNode,
|
||||||
|
// }
|
||||||
|
|
||||||
|
// impl StaticSiteCfg {
|
||||||
|
// fn render(self) -> anyhow::Result<VNode> {
|
||||||
|
// let StaticSiteCfg { .. } = self;
|
||||||
|
|
||||||
|
// // Set up options and parser. Strikethroughs are not part of the CommonMark standard
|
||||||
|
// // and we therefore must enable it explicitly.
|
||||||
|
// let mut options = Options::empty();
|
||||||
|
// options.insert(Options::ENABLE_STRIKETHROUGH);
|
||||||
|
// let parser = Parser::new_ext(markdown_input, options);
|
||||||
|
|
||||||
|
// //
|
||||||
|
|
||||||
|
// Ok(html! {<div> </div>})
|
||||||
|
// }
|
||||||
|
// }
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
//! Dioxus Router
|
||||||
|
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut app = App::new();
|
||||||
|
|
||||||
|
// app.at(c)
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
//! Server-side-renderered webpages are a great use of Rust's async story, where servers can handle
|
//! Server-side-renderered webpages are a great use of Rust's async story, where servers can handle
|
||||||
//! thousands of simultaneous clients on minimal hardware.
|
//! thousands of simultaneous clients on minimal hardware.
|
||||||
|
|
||||||
use dioxus_core::prelude::*;
|
use dioxus::prelude::*;
|
||||||
use tide::{Request, Response};
|
use tide::{Request, Response};
|
||||||
|
|
||||||
#[async_std::main]
|
#[async_std::main]
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
[package]
|
||||||
|
name = "dioxus-core-macro"
|
||||||
|
version = "0.0.0"
|
||||||
|
authors = ["Jonathan Kelley <jkelleyrtp@gmail.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
proc-macro = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
proc-macro2 = "1.0.6"
|
||||||
|
quote = "1.0"
|
||||||
|
syn = { version = "1.0.11", features = ["full"] }
|
||||||
|
|
||||||
|
# testing
|
||||||
|
[dev-dependencies]
|
||||||
|
rustversion = "1.0"
|
||||||
|
trybuild = "1.0"
|
||||||
@@ -0,0 +1,211 @@
|
|||||||
|
use proc_macro2::TokenStream;
|
||||||
|
use quote::{quote, quote_spanned, ToTokens};
|
||||||
|
use syn::parse::{Parse, ParseStream};
|
||||||
|
use syn::spanned::Spanned;
|
||||||
|
use syn::{
|
||||||
|
parse_macro_input, Attribute, Block, FnArg, Ident, Item, ItemFn, ReturnType, Type, Visibility,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FunctionComponent {
|
||||||
|
block: Box<Block>,
|
||||||
|
props_type: Box<Type>,
|
||||||
|
arg: FnArg,
|
||||||
|
vis: Visibility,
|
||||||
|
attrs: Vec<Attribute>,
|
||||||
|
name: Ident,
|
||||||
|
return_type: Box<Type>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for FunctionComponent {
|
||||||
|
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||||
|
let parsed: Item = input.parse()?;
|
||||||
|
|
||||||
|
match parsed {
|
||||||
|
Item::Fn(func) => {
|
||||||
|
let ItemFn {
|
||||||
|
attrs,
|
||||||
|
vis,
|
||||||
|
sig,
|
||||||
|
block,
|
||||||
|
} = func;
|
||||||
|
|
||||||
|
if !sig.generics.params.is_empty() {
|
||||||
|
return Err(syn::Error::new_spanned(
|
||||||
|
sig.generics,
|
||||||
|
"function components can't contain generics",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if sig.asyncness.is_some() {
|
||||||
|
return Err(syn::Error::new_spanned(
|
||||||
|
sig.asyncness,
|
||||||
|
"function components can't be async",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if sig.constness.is_some() {
|
||||||
|
return Err(syn::Error::new_spanned(
|
||||||
|
sig.constness,
|
||||||
|
"const functions can't be function components",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if sig.abi.is_some() {
|
||||||
|
return Err(syn::Error::new_spanned(
|
||||||
|
sig.abi,
|
||||||
|
"extern functions can't be function components",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let return_type = match sig.output {
|
||||||
|
ReturnType::Default => {
|
||||||
|
return Err(syn::Error::new_spanned(
|
||||||
|
sig,
|
||||||
|
"function components must return `yew::Html`",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
ReturnType::Type(_, ty) => ty,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut inputs = sig.inputs.into_iter();
|
||||||
|
let arg: FnArg = inputs
|
||||||
|
.next()
|
||||||
|
.unwrap_or_else(|| syn::parse_quote! { _: &() });
|
||||||
|
|
||||||
|
let ty = match &arg {
|
||||||
|
FnArg::Typed(arg) => match &*arg.ty {
|
||||||
|
Type::Reference(ty) => {
|
||||||
|
if ty.lifetime.is_some() {
|
||||||
|
return Err(syn::Error::new_spanned(
|
||||||
|
&ty.lifetime,
|
||||||
|
"reference must not have a lifetime",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ty.mutability.is_some() {
|
||||||
|
return Err(syn::Error::new_spanned(
|
||||||
|
&ty.mutability,
|
||||||
|
"reference must not be mutable",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
ty.elem.clone()
|
||||||
|
}
|
||||||
|
ty => {
|
||||||
|
let msg = format!(
|
||||||
|
"expected a reference to a `Properties` type (try: `&{}`)",
|
||||||
|
ty.to_token_stream()
|
||||||
|
);
|
||||||
|
return Err(syn::Error::new_spanned(ty, msg));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
FnArg::Receiver(_) => {
|
||||||
|
return Err(syn::Error::new_spanned(
|
||||||
|
arg,
|
||||||
|
"function components can't accept a receiver",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Checking after param parsing may make it a little inefficient
|
||||||
|
// but that's a requirement for better error messages in case of receivers
|
||||||
|
// `>0` because first one is already consumed.
|
||||||
|
if inputs.len() > 0 {
|
||||||
|
let params: TokenStream = inputs.map(|it| it.to_token_stream()).collect();
|
||||||
|
return Err(syn::Error::new_spanned(
|
||||||
|
params,
|
||||||
|
"function components can accept at most one parameter for the props",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
props_type: ty,
|
||||||
|
block,
|
||||||
|
arg,
|
||||||
|
vis,
|
||||||
|
attrs,
|
||||||
|
name: sig.ident,
|
||||||
|
return_type,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
item => Err(syn::Error::new_spanned(
|
||||||
|
item,
|
||||||
|
"`function_component` attribute can only be applied to functions",
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FunctionComponentName {
|
||||||
|
component_name: Ident,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for FunctionComponentName {
|
||||||
|
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||||
|
if input.is_empty() {
|
||||||
|
return Err(input.error("expected identifier for the component"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let component_name = input.parse()?;
|
||||||
|
|
||||||
|
Ok(Self { component_name })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn function_component(
|
||||||
|
attr: proc_macro::TokenStream,
|
||||||
|
item: proc_macro::TokenStream,
|
||||||
|
) -> proc_macro::TokenStream {
|
||||||
|
let item = parse_macro_input!(item as FunctionComponent);
|
||||||
|
let attr = parse_macro_input!(attr as FunctionComponentName);
|
||||||
|
|
||||||
|
function_component_impl(attr, item)
|
||||||
|
.unwrap_or_else(|err| err.to_compile_error())
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn function_component_impl(
|
||||||
|
name: FunctionComponentName,
|
||||||
|
component: FunctionComponent,
|
||||||
|
) -> syn::Result<TokenStream> {
|
||||||
|
let FunctionComponentName { component_name } = name;
|
||||||
|
|
||||||
|
let FunctionComponent {
|
||||||
|
block,
|
||||||
|
props_type,
|
||||||
|
arg,
|
||||||
|
vis,
|
||||||
|
attrs,
|
||||||
|
name: function_name,
|
||||||
|
return_type,
|
||||||
|
} = component;
|
||||||
|
|
||||||
|
if function_name == component_name {
|
||||||
|
return Err(syn::Error::new_spanned(
|
||||||
|
component_name,
|
||||||
|
"the component must not have the same name as the function",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let ret_type = quote_spanned!(return_type.span()=> ::yew::html::Html);
|
||||||
|
|
||||||
|
let quoted = quote! {
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
#vis struct #function_name;
|
||||||
|
|
||||||
|
impl ::yew_functional::FunctionProvider for #function_name {
|
||||||
|
type TProps = #props_type;
|
||||||
|
|
||||||
|
fn run(#arg) -> #ret_type {
|
||||||
|
#block
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#(#attrs)*
|
||||||
|
#vis type #component_name = ::yew_functional::FunctionComponent<#function_name>;
|
||||||
|
};
|
||||||
|
Ok(quoted)
|
||||||
|
}
|
||||||
@@ -11,8 +11,8 @@ description = "Core functionality for Dioxus - a concurrent renderer-agnostic Vi
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
generational-arena = "0.2.8"
|
generational-arena = "0.2.8"
|
||||||
dioxus-html-macro = { path = "../html-macro", version = "0.1.0" }
|
|
||||||
once_cell = "1.5.2"
|
once_cell = "1.5.2"
|
||||||
|
dioxus-html-macro = { path = "../html-macro", version = "0.1.0" }
|
||||||
|
|
||||||
|
|
||||||
# web-sys = "0.3.46"
|
# web-sys = "0.3.46"
|
||||||
|
|||||||
+77
-12
@@ -1,6 +1,47 @@
|
|||||||
//! Dioxus: a concurrent, functional, virtual dom for any renderer in Rust
|
//! <div align="center">
|
||||||
|
//! <h1>🌗🚀 📦 Dioxus</h1>
|
||||||
|
//! <p>
|
||||||
|
//! <strong>A concurrent, functional, virtual DOM for Rust</strong>
|
||||||
|
//! </p>
|
||||||
|
//! </div>
|
||||||
|
//! Dioxus: a concurrent, functional, reactive virtual dom for any renderer in Rust.
|
||||||
//!
|
//!
|
||||||
//!
|
//!
|
||||||
|
//! Dioxus is an efficient virtual dom implementation for building interactive user interfaces in Rust.
|
||||||
|
//! This crate aims to maintain a uniform hook-based, renderer-agnostic UI framework for cross-platform development.
|
||||||
|
//!
|
||||||
|
//! ## Components
|
||||||
|
//! The base unit of Dioxus is the `component`. Components can be easily created from just a function - no traits required:
|
||||||
|
//! ```
|
||||||
|
//! use dioxus_core::prelude::*;
|
||||||
|
//!
|
||||||
|
//! fn Example(ctx: Context<()>) -> VNode {
|
||||||
|
//! html! { <div> "Hello world!" </div> }
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
//! Components need to take a "Context" parameter which is generic over some properties. This defines how the component can be used
|
||||||
|
//! and what properties can be used to specify it in the VNode output. All components in Dioxus are hook-based, which might be more
|
||||||
|
//! complex than other approaches that use traits + lifecycle events. Alternatively, we provide a "lifecycle hook" if you want more
|
||||||
|
//! granualar control with behavior similar to other UI frameworks.
|
||||||
|
//!
|
||||||
|
//! ## Hooks
|
||||||
|
//! Dioxus uses hooks for state management. Hooks are a form of state persisted between calls of the function component. Instead of
|
||||||
|
//! using a single struct to store data, hooks use the "use_hook" building block which allows the persistence of data between
|
||||||
|
//! function component renders.
|
||||||
|
//!
|
||||||
|
//! This allows functions to reuse stateful logic between components, simplify large complex components, and adopt more clear context
|
||||||
|
//! subscription patterns to make components easier to read.
|
||||||
|
//!
|
||||||
|
//! ## Supported Renderers
|
||||||
|
//! Instead of being tightly coupled to a platform, browser, or toolkit, Dioxus implements a VirtualDOM object which
|
||||||
|
//! can be consumed to draw the UI. The Dioxus VDOM is reactive and easily consumable by 3rd-party renderers via
|
||||||
|
//! the `Patch` object. See [Implementing a Renderer](docs/8-custom-renderer.md) and the `StringRenderer` classes for information
|
||||||
|
//! on how to implement your own custom renderer. We provide 1st-class support for these renderers:
|
||||||
|
//! - dioxus-desktop (via WebView)
|
||||||
|
//! - dioxus-web (via WebSys)
|
||||||
|
//! - dioxus-ssr (via StringRenderer)
|
||||||
|
//! - dioxus-liveview (SSR + StringRenderer)
|
||||||
|
//!
|
||||||
|
|
||||||
/// Re-export common types for ease of development use.
|
/// Re-export common types for ease of development use.
|
||||||
/// Essential when working with the html! macro
|
/// Essential when working with the html! macro
|
||||||
@@ -9,12 +50,12 @@
|
|||||||
///
|
///
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
use crate::nodes;
|
use crate::nodes;
|
||||||
pub use crate::virtual_dom::Context;
|
pub use crate::virtual_dom::{Context, VirtualDom, FC};
|
||||||
pub use crate::virtual_dom::VirtualDom;
|
|
||||||
pub use nodes::iterables::IterableNodes;
|
pub use nodes::iterables::IterableNodes;
|
||||||
pub use nodes::*;
|
pub use nodes::*;
|
||||||
|
|
||||||
// hack "VNode"
|
// TODO @Jon, fix this
|
||||||
|
// hack the VNode type until VirtualNode is fixed in the macro crate
|
||||||
pub type VirtualNode = VNode;
|
pub type VirtualNode = VNode;
|
||||||
|
|
||||||
// Re-export from the macro crate
|
// Re-export from the macro crate
|
||||||
@@ -24,7 +65,6 @@ pub mod prelude {
|
|||||||
/// The Dioxus Virtual Dom integrates an event system and virtual nodes to create reactive user interfaces.
|
/// The Dioxus Virtual Dom integrates an event system and virtual nodes to create reactive user interfaces.
|
||||||
///
|
///
|
||||||
/// This module includes all life-cycle related mechanics, including the virtual dom, scopes, properties, and lifecycles.
|
/// This module includes all life-cycle related mechanics, including the virtual dom, scopes, properties, and lifecycles.
|
||||||
///
|
|
||||||
pub mod virtual_dom {
|
pub mod virtual_dom {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::nodes::VNode;
|
use crate::nodes::VNode;
|
||||||
@@ -33,7 +73,12 @@ pub mod virtual_dom {
|
|||||||
/// 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.
|
||||||
pub struct VirtualDom {
|
pub struct VirtualDom {
|
||||||
arena: Arena<Scope>,
|
/// All mounted components are arena allocated to make additions, removals, and references easy to work with
|
||||||
|
/// A generational arean is used to re-use slots of deleted scopes without having to resize the underlying arena.
|
||||||
|
components: Arena<Scope>,
|
||||||
|
|
||||||
|
/// Components generate lifecycle events
|
||||||
|
event_queue: Vec<LifecycleEvent>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VirtualDom {
|
impl VirtualDom {
|
||||||
@@ -51,25 +96,41 @@ pub mod virtual_dom {
|
|||||||
/// This is useful when a component tree can be driven by external state (IE SSR) but it would be too expensive
|
/// This is useful when a component tree can be driven by external state (IE SSR) but it would be too expensive
|
||||||
/// to toss out the entire tree.
|
/// to toss out the entire tree.
|
||||||
pub fn new_with_props<T>(root: FC<T>) -> Self {
|
pub fn new_with_props<T>(root: FC<T>) -> Self {
|
||||||
|
// Set a first lifecycle event to add the component
|
||||||
|
let first_event = LifecycleEvent::Add;
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
arena: Arena::new(),
|
components: Arena::new(),
|
||||||
|
event_queue: vec![first_event],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum LifecycleEvent {
|
||||||
|
Add,
|
||||||
|
}
|
||||||
|
|
||||||
/// Functional Components leverage the type FC to
|
/// Functional Components leverage the type FC to
|
||||||
pub type FC<T> = fn(&mut Context<T>) -> VNode;
|
pub type FC<T> = fn(&mut Context<T>) -> VNode;
|
||||||
|
|
||||||
/// The Scope that wraps a functional component
|
/// The Scope that wraps a functional component
|
||||||
/// Scope's hold subscription, context, and hook information, however, it is allocated on the heap.
|
/// Scope's hold subscription, context, and hook information, however, it is allocated on the heap.
|
||||||
pub struct Scope {}
|
pub struct Scope {
|
||||||
|
hook_idx: i32,
|
||||||
|
hooks: Vec<()>,
|
||||||
|
}
|
||||||
|
|
||||||
impl Scope {
|
impl Scope {
|
||||||
fn new<T>() -> Self {
|
fn new<T>() -> Self {
|
||||||
Self {}
|
Self {
|
||||||
|
hook_idx: 0,
|
||||||
|
hooks: vec![],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct HookState {}
|
||||||
|
|
||||||
/// Components in Dioxus use the "Context" object to interact with their lifecycle.
|
/// Components in Dioxus use the "Context" object to interact with their lifecycle.
|
||||||
/// This lets components schedule updates, integrate hooks, and expose their context via the context api.
|
/// This lets components schedule updates, integrate hooks, and expose their context via the context api.
|
||||||
///
|
///
|
||||||
@@ -92,7 +153,12 @@ pub mod virtual_dom {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait Properties {}
|
pub trait Properties {}
|
||||||
|
|
||||||
|
// Auto derive for pure components
|
||||||
impl Properties for () {}
|
impl Properties for () {}
|
||||||
|
|
||||||
|
// Set up a derive macro
|
||||||
|
// #[derive(Macro)]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Virtual Node Support
|
/// Virtual Node Support
|
||||||
@@ -600,9 +666,8 @@ pub mod nodes {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
/// The diffing algorithm to compare two VNode trees and generate a list of patches to update the VDom.
|
||||||
///
|
/// Currently, using an index-based patching algorithm
|
||||||
///
|
|
||||||
///
|
///
|
||||||
pub mod diff {
|
pub mod diff {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
[package]
|
||||||
|
name = "dioxus"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Jonathan Kelley <jkelleyrtp@gmail.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
description = "Core functionality for Dioxus - a concurrent renderer-agnostic Virtual DOM for interactive user experiences"
|
||||||
|
"license" = "MIT/Apache-2.0"
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
dioxus-core = { path = "../core", version = "0.1.0" }
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Dioxus
|
||||||
|
|
||||||
|
This crate serves as the thin frontend over dioxus-core and dioxus-app. Here, we support docs, feature flags, and incorporate some extra tools and utilities into a consistent API.
|
||||||
|
|
||||||
|
Ideally, we can prevent cfg creep into the core crate by moving it all into this frontend crate.
|
||||||
|
|
||||||
|
For now, see dioxus-core for all docs and details
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
pub mod prelude {
|
||||||
|
pub use dioxus_core::prelude::*;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Re-export core completely
|
||||||
|
pub use dioxus_core as core;
|
||||||
|
|
||||||
|
struct App {}
|
||||||
|
|
||||||
|
fn new() -> App {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Router {}
|
||||||
|
|
||||||
|
struct Route {}
|
||||||
Reference in new issue
Block a user