Renderers are now packages, not features. (#387)

* feat: use synchronous router design

* feat: function to get router out of dom

* chore: restructure workspace to use renderers as packages, not features
This commit is contained in:
Jon Kelley 2022-07-09 15:15:20 -04:00 committed by GitHub
parent c97ca7dff6
commit d9546d9504
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
181 changed files with 487 additions and 1463 deletions

View File

@ -40,4 +40,4 @@ jobs:
- uses: actions-rs/cargo@v1
with:
command: test
args: --features "desktop, ssr, router"
args: --all --tests

View File

@ -43,6 +43,7 @@ jobs:
- uses: actions-rs/cargo@v1
with:
command: check
args: --all --examples --tests
test:
if: github.event.pull_request.draft == false

View File

@ -71,6 +71,6 @@ jobs:
rustc -Vv
cargo -V
set RUST_BACKTRACE=1
cargo build --features "desktop, ssr, router"
cargo test --features "desktop, ssr, router"
cargo build --all --tests --examples
cargo test --all --tests
shell: cmd

View File

@ -1,61 +1,10 @@
[package]
name = "dioxus"
version = "0.2.4"
authors = ["Jonathan Kelley"]
edition = "2021"
description = "Core functionality for Dioxus - a concurrent renderer-agnostic Virtual DOM for interactive user experiences"
license = "MIT OR Apache-2.0"
repository = "https://github.com/DioxusLabs/dioxus/"
homepage = "https://dioxuslabs.com"
documentation = "https://dioxuslabs.com"
keywords = ["dom", "ui", "gui", "react", "wasm"]
rust-version = "1.60.0"
[dependencies]
dioxus-core = { path = "./packages/core", version = "^0.2.1" }
dioxus-html = { path = "./packages/html", version = "^0.2.1", optional = true }
dioxus-core-macro = { path = "./packages/core-macro", version = "^0.2.1", optional = true }
dioxus-hooks = { path = "./packages/hooks", version = "^0.2.1", optional = true }
fermi = { path = "./packages/fermi", version = "^0.2.1", optional = true }
dioxus-web = { path = "./packages/web", version = "^0.2.1", optional = true }
dioxus-desktop = { path = "./packages/desktop", version = "^0.2.3", optional = true }
dioxus-ssr = { path = "./packages/ssr", version = "^0.2.1", optional = true }
dioxus-router = { path = "./packages/router", version = "^0.2.3", optional = true }
dioxus-interpreter-js = { path = "./packages/interpreter", version = "^0.2.1", optional = true }
dioxus-tui = { path = "./packages/tui", version = "^0.2.2", optional = true }
dioxus-rsx = { path = "./packages/rsx", optional = true }
dioxus-rsx-interpreter = { path = "./packages/rsx_interpreter", optional = true }
dioxus-liveview = { path = "./packages/liveview", version = "^0.1.0", optional = true }
dioxus-native-core = { path = "./packages/native-core", version = "^0.2.0", optional = true }
dioxus-native-core-macro = { path = "./packages/native-core-macro", version = "^0.2.0", optional = true }
# dioxus-mobile = { path = "./packages/mobile", version = "^0.2.0", optional = true }
# dioxus-rsx = { path = "./packages/rsx", optional = true }
# macro = ["dioxus-core-macro", "dioxus-rsx"]
[features]
default = ["macro", "hooks", "html"]
macro = ["dioxus-core-macro", "dioxus-rsx"]
hooks = ["dioxus-hooks"]
html = ["dioxus-html"]
ssr = ["dioxus-ssr"]
web = ["dioxus-web", "dioxus-router?/web"]
desktop = ["dioxus-desktop"]
router = ["dioxus-router"]
tui = ["dioxus-tui"]
liveview = ["dioxus-liveview"]
hot-reload = ["dioxus-core-macro/hot-reload", "dioxus-rsx-interpreter", "dioxus-desktop?/hot-reload", "dioxus-web?/hot-reload", "dioxus-router?/hot-reload"]
native-core = ["dioxus-native-core", "dioxus-native-core-macro"]
[workspace]
members = [
"packages/dioxus",
"packages/core",
"packages/core-macro",
"packages/router",
"packages/html",
"packages/hooks",
"packages/web",
@ -71,11 +20,32 @@ members = [
"packages/rsx_interpreter",
"packages/native-core",
"packages/native-core-macro",
"packages/rsx-prelude",
"docs/guide",
]
# This is a "virtual package"
# It is not meant to be published, but is used so "cargo run --example XYZ" works properly
[package]
name = "dioxus-examples"
version = "0.0.0"
authors = ["Jonathan Kelley"]
edition = "2021"
description = "Top level crate for the Dioxus repository"
license = "MIT OR Apache-2.0"
repository = "https://github.com/DioxusLabs/dioxus/"
homepage = "https://dioxuslabs.com"
documentation = "https://dioxuslabs.com"
keywords = ["dom", "ui", "gui", "react", "wasm"]
rust-version = "1.60.0"
[dev-dependencies]
dioxus = { path = "./packages/dioxus" }
dioxus-desktop = { path = "./packages/desktop" }
dioxus-ssr = { path = "./packages/ssr" }
dioxus-router = { path = "./packages/router" }
fermi = { path = "./packages/fermi" }
futures-util = "0.3.21"
log = "0.4.14"
num-format = "0.4.0"
@ -87,21 +57,6 @@ serde_json = "1.0.79"
rand = { version = "0.8.4", features = ["small_rng"] }
tokio = { version = "1.16.1", features = ["full"] }
reqwest = { version = "0.11.9", features = ["json"] }
dioxus = { path = ".", features = ["desktop", "ssr", "router", "fermi", "tui", "hot-reload"] }
fern = { version = "0.6.0", features = ["colored"] }
criterion = "0.3.5"
thiserror = "1.0.30"
env_logger = "0.9.0"
[[bench]]
name = "create"
harness = false
[[bench]]
name = "jsframework"
harness = false
[[bench]]
name = "tui_update"
harness = false

View File

@ -6,7 +6,16 @@ description = "Dioxus guide, including testable examples"
license = "MIT/Apache-2.0"
[dev-dependencies]
dioxus = { path = "../..", features = ["desktop", "web", "ssr", "router", "fermi", "tui"] }
dioxus = { path = "../../packages/dioxus" }
dioxus-desktop = { path = "../../packages/desktop" }
dioxus-web = { path = "../../packages/web" }
dioxus-ssr = { path = "../../packages/ssr" }
dioxus-router = { path = "../../packages/router" }
dioxus-tui = { path = "../../packages/tui" }
fermi = { path = "../../packages/fermi" }
# dioxus = { path = "../../packages/dioxus", features = ["desktop", "web", "ssr", "router", "fermi", "tui"] }
serde = { version = "1.0.138", features=["derive"] }
reqwest = { version = "0.11.11", features = ["json"] }
tokio = { version = "1.19.2" , features=[]}

View File

@ -2,7 +2,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(App);
dioxus_desktop::launch(App);
}
fn App(cx: Scope) -> Element {

View File

@ -2,7 +2,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(App);
dioxus_desktop::launch(App);
}
// ANCHOR: App

View File

@ -3,7 +3,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(App);
dioxus_desktop::launch(App);
}
fn App(cx: Scope) -> Element {

View File

@ -3,7 +3,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(App);
dioxus_desktop::launch(App);
}
fn App(cx: Scope) -> Element {

View File

@ -3,7 +3,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(App);
dioxus_desktop::launch(App);
}
fn App(cx: Scope) -> Element {

View File

@ -2,7 +2,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(App);
dioxus_desktop::launch(App);
}
// ANCHOR: App

View File

@ -2,7 +2,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(App);
dioxus_desktop::launch(App);
}
fn App(cx: Scope) -> Element {

View File

@ -2,7 +2,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(App);
dioxus_desktop::launch(App);
}
// ANCHOR: App

View File

@ -2,7 +2,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(App);
dioxus_desktop::launch(App);
}
pub fn App(cx: Scope) -> Element {

View File

@ -2,7 +2,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(App);
dioxus_desktop::launch(App);
}
fn App(cx: Scope) -> Element {

View File

@ -2,7 +2,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(App);
dioxus_desktop::launch(App);
}
fn App(cx: Scope) -> Element {

View File

@ -4,7 +4,7 @@ use dioxus::events::MouseEvent;
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(App);
dioxus_desktop::launch(App);
}
fn App(cx: Scope) -> Element {

View File

@ -2,7 +2,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(App);
dioxus_desktop::launch(App);
}
fn App(cx: Scope) -> Element {

View File

@ -2,7 +2,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(App);
dioxus_desktop::launch(App);
}
fn App(cx: Scope) -> Element {

View File

@ -3,7 +3,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(App);
dioxus_desktop::launch(App);
}
// ANCHOR: component

View File

@ -2,7 +2,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::tui::launch(App);
dioxus_tui::launch(App);
}
fn App(cx: Scope) -> Element {

View File

@ -3,16 +3,16 @@
use dioxus::events::{KeyCode, KeyboardEvent};
use dioxus::prelude::*;
use dioxus::tui::TuiContext;
use dioxus_tui::TuiContext;
fn main() {
dioxus::tui::launch_cfg(
dioxus_tui::launch_cfg(
App,
dioxus::tui::Config::new()
dioxus_tui::Config::new()
.without_ctrl_c_quit()
// Some older terminals only support 16 colors or ANSI colors
// If your terminal is one of these, change this to BaseColors or ANSI
.with_rendering_mode(dioxus::tui::RenderingMode::Rgb),
.with_rendering_mode(dioxus_tui::RenderingMode::Rgb),
);
}

View File

@ -2,7 +2,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::web::launch(App);
dioxus_web::launch(App);
}
fn App(cx: Scope) -> Element {

View File

@ -4,7 +4,7 @@ use dioxus::prelude::*;
use std::collections::HashMap;
fn main() {
dioxus::desktop::launch(App);
dioxus_desktop::launch(App);
}
fn App(cx: Scope) -> Element {

View File

@ -2,7 +2,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(App);
dioxus_desktop::launch(App);
}
// ANCHOR: component

View File

@ -2,7 +2,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(App);
dioxus_desktop::launch(App);
}
// ANCHOR: component

View File

@ -2,7 +2,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(App);
dioxus_desktop::launch(App);
}
// ANCHOR: component

View File

@ -2,7 +2,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(App);
dioxus_desktop::launch(App);
}
// ANCHOR: component

View File

@ -2,7 +2,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(App);
dioxus_desktop::launch(App);
}
// ANCHOR: component

View File

@ -5,7 +5,7 @@ use dioxus::events::FormEvent;
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(MemeEditor);
dioxus_desktop::launch(MemeEditor);
}
// ANCHOR: meme_editor

View File

@ -5,7 +5,7 @@ use dioxus::events::FormEvent;
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(App);
dioxus_desktop::launch(App);
}
// ANCHOR: DarkMode_struct

View File

@ -3,7 +3,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(App);
dioxus_desktop::launch(App);
}
#[derive(PartialEq, Clone)]

View File

@ -3,7 +3,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(App);
dioxus_desktop::launch(App);
}
pub fn App(cx: Scope) -> Element {

View File

@ -3,7 +3,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(App);
dioxus_desktop::launch(App);
}
fn App(cx: Scope) -> Element {

View File

@ -3,7 +3,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(App);
dioxus_desktop::launch(App);
}
#[derive(serde::Deserialize, Debug)]

View File

@ -33,7 +33,7 @@ let name = "jane";
let pending = false;
let count = 10;
dioxus::ssr::render_lazy(html! {
dioxus_ssr::render_lazy(html! {
<div>
<p> "Hello, {name}!" </p>
<p> "Status: {pending}!" </p>
@ -51,7 +51,7 @@ When helpful, the Dioxus VSCode extension provides a way of converting a selecti
It's also a bit easier on the eyes than HTML.
```rust
dioxus::ssr::render_lazy(rsx! {
dioxus_ssr::render_lazy(rsx! {
div {
p {"Hello, {name}!"}
p {"Status: {pending}!"}

View File

@ -159,7 +159,7 @@ force_render(ScopeId(0));
In our guides, we frequently use the phrase "re-render" to describe updates to our app. You'll often hear this paired with "preventing unnecessary re-renders." But what exactly does this mean?
When we call `dioxus::desktop::launch`, Dioxus will create a new `Scope` object and call the component we gave it. Our `rsx!` calls will create new nodes which we return back to the VirtualDom. Dioxus will then look through these nodes for child components, call their functions, and so on until every component has been "rendered." We consider these nodes "rendered" because they were created because of our explicit actions.
When we call `dioxus_desktop::launch`, Dioxus will create a new `Scope` object and call the component we gave it. Our `rsx!` calls will create new nodes which we return back to the VirtualDom. Dioxus will then look through these nodes for child components, call their functions, and so on until every component has been "rendered." We consider these nodes "rendered" because they were created because of our explicit actions.
The tree of UI that dioxus creates will roughly look like the tree of components presented earlier:

View File

@ -12,7 +12,7 @@ Instead of passing a closure, you can also pass a string to event handlers t
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(App);
dioxus_desktop::launch(App);
}
fn App(cx: Scope) -> Element {

View File

@ -16,7 +16,7 @@ For the simplest of apps, all of your state can enter the app from the root prop
```rust
let all_content = get_all_content().await;
let output = dioxus::ssr::render_lazy(rsx!{
let output = dioxus_ssr::render_lazy(rsx!{
div {
RenderContent { content: all_content }
}

View File

@ -61,7 +61,7 @@ Edit your `lib.rs`:
use dioxus::prelude::*;
fn main() {
dioxus::mobile::launch(app);
dioxus_mobile::launch(app);
}
fn app(cx: Scope) -> Element {

View File

@ -21,10 +21,10 @@ If you just want to render `rsx!` or a VirtualDom to HTML, check out the API doc
// We can render VirtualDoms
let mut vdom = VirtualDom::new(app);
let _ = vdom.rebuild();
println!("{}", dioxus::ssr::render_vdom(&vdom));
println!("{}", dioxus_ssr::render_vdom(&vdom));
// Or we can render rsx! calls directly
println!( "{}", dioxus::ssr::render_lazy(rsx! { h1 { "Hello, world!" } } );
println!( "{}", dioxus_ssr::render_lazy(rsx! { h1 { "Hello, world!" } } );
```
However, for this guide, we're going to show how to use Dioxus SSR with `Axum`.
@ -84,7 +84,7 @@ And then add our endpoint. We can either render `rsx!` directly:
```rust
async fn app_endpoint() -> Html<String> {
Html(dioxus::ssr::render_lazy(rsx! {
Html(dioxus_ssr::render_lazy(rsx! {
h1 { "hello world!" }
}))
}
@ -100,7 +100,7 @@ async fn app_endpoint() -> Html<String> {
let mut app = VirtualDom::new(app);
let _ = app.rebuild();
Html(dioxus::ssr::render_vdom(&app))
Html(dioxus_ssr::render_vdom(&app))
}
```

View File

@ -24,7 +24,7 @@ To give you an idea of what Dioxus looks like, here's a simple counter app:
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(app)
dioxus_desktop::launch(app)
}
fn app(cx: Scope) -> Element {
@ -187,7 +187,7 @@ We can add our counter from above.
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(app)
dioxus_desktop::launch(app)
}
fn app(cx: Scope) -> Element {

View File

@ -46,7 +46,7 @@ use dioxus::prelude::*;
fn main() {
// Launch Dioxus web app
dioxus::web::launch(app);
dioxus_web::launch(app);
}
// Our root component.

View File

@ -1,7 +1,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(app);
dioxus_desktop::launch(app);
}
fn app(cx: Scope) -> Element {

View File

@ -1,7 +1,7 @@
use dioxus::{events::*, prelude::*};
fn main() {
dioxus::desktop::launch(app);
dioxus_desktop::launch(app);
}
#[derive(Debug)]

View File

@ -19,7 +19,7 @@ and is proven to be safe with MIRI.
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(app);
dioxus_desktop::launch(app);
}
fn app(cx: Scope) -> Element {

View File

@ -4,12 +4,12 @@ This calculator version uses React-style state management. All state is held as
*/
use dioxus::events::*;
use dioxus::html::input_data::keyboard_types::Key;
use dioxus::prelude::*;
use dioxus_html::input_data::keyboard_types::Key;
fn main() {
use dioxus::desktop::tao::dpi::LogicalSize;
dioxus::desktop::launch_cfg(app, |cfg| {
use dioxus_desktop::tao::dpi::LogicalSize;
dioxus_desktop::launch_cfg(app, |cfg| {
cfg.with_window(|w| {
w.with_title("Calculator Demo")
.with_resizable(false)

View File

@ -1,21 +0,0 @@
# Reference Guide
This folder holds a bunch of useful reference code. However, none of the code is meant to be executed (nothing special will happen).
| Reference: | What it does |
| --------------------------------------------------- | ------------------------------------------------------ |
| [Basics](./basics.rs) | How to render a simple app |
| [Empty](./empty.rs) | Components can return None |
| [Children](./children.rs) | Components can have children |
| [Suspense](./suspense.rs) | Suspense can be achieved with use_suspense |
| [Conditional Rendering](./conditional_rendering.rs) | Elements can be hidden conditionally |
| [Controlled Inputs](./controlled_inputs.rs) | Inputs are "controlled" similar to React |
| [Fragments](./fragments.rs) | Components can return multiple elements without a root |
| [Inline Styles](./inline_styles.rs) | Styles can be inlined as element attributes |
| [Spread Pattern for Props](./spreadpattern.rs) | Props can be spread into component calls |
| [Iterators](./iterators.rs) | Lists of elements can be made from iterators |
| [Listener](./listener.rs) | State can be updated from event listeners |
| [Memo](./memo.rs) | Memoization is controlled via PartialEq |
| [Custom Elements](./custom_elements.rs) | Define custom elements |
| [Anti-patterns](./antipatterns.rs) | What not to do! |

View File

@ -1,44 +0,0 @@
//! Example: Web Components & Custom Elements
//! -----------------------------------------
//!
//! Web components are a flavor of html elements that can be user-defined.
//! See: https://www.webcomponents.org for more information.
//!
//! Users who use webcomponents typically don't use Dioxus. However, if you would like to use webcomponents in Dioxus,
//! you can easily create a new custom element with compile-time correct wrappers around the webcomponent.
//!
//! We don't support building new webcomponents with Dioxus, however. :(
use dioxus::prelude::*;
pub fn Example(cx: Scope) -> Element {
cx.render(rsx! {
div {
custom_element {
custom_attr: "custom data on custom elements"
}
}
})
}
mod dioxus_elements {
use std::fmt::Arguments;
use dioxus::prelude::DioxusElement;
#[allow(non_camel_case_types)]
pub struct custom_element;
impl DioxusElement for custom_element {
const TAG_NAME: &'static str = "custom_element";
const NAME_SPACE: Option<&'static str> = None;
}
impl custom_element {
pub fn custom_attr<'a>(&self, f: NodeFactory<'a>, val: Arguments) -> Attribute<'a> {
f.attr("custom_asttr", val, None, false)
}
}
// Re-export the normal html namespace
pub use dioxus::prelude::dioxus_elements::*;
use dioxus_core::{nodes::Attribute, NodeFactory};
}

View File

@ -1,89 +0,0 @@
//! Example: Error Handling
//! ------------------------
//!
//! Error handling in Dioxus comes in a few flavors. Because Dioxus is a Rust project, Options and Results are obviously
//! the go-to way of wrapping possibly-errored data. However, if a component fails when "unwrapping," everything will crash,
//! the page will deadlock, and your users will be sad.
//!
//! So, obviously, you need to handle your errors.
//!
//! Fortunately, it's easy to avoid panics, even during quick prototyping.
//!
//! Here are a few strategies:
//! - Leverage the ability to return "None" and propagate None directly
//! - Instead of propagating "None" manually, use the "?" syntax sugar
//! - Convert Results into Options with .ok()
//! - Manually display a separate screen by matching on Options/Results
//!
//! There *are* plans to add helpful screens for when apps completely panic in Wasm. However, you should really try to
//! avoid panicking.
use dioxus::prelude::*;
fn main() {}
/// This is one way to go about error handling (just toss things away with unwrap).
/// However, if you get it wrong, the whole app will crash.
/// This is pretty flimsy.
pub fn App(cx: Scope) -> Element {
let data = get_data().unwrap();
cx.render(rsx!( div { "{data}" } ))
}
/// This is a pretty verbose way of error handling
/// However, it's still pretty good since we don't panic, just fail to render anything
pub fn App1(cx: Scope) -> Element {
let data = match get_data() {
Some(data) => data,
None => return None,
};
cx.render(rsx!( div { "{data}" } ))
}
/// This is an even better form of error handling.
/// However, it _does_ make the component go blank, which might not be desirable.
///
/// This type of error handling is good when you have "selectors" that produce Some/None based on some state that's
/// already controlled higher in the tree. i.e. displaying a "Username" in a component that should only be shown if
/// a user is logged in.
///
/// Dioxus will throw an error in the console if the None-path is ever taken.
pub fn App2(cx: Scope) -> Element {
let data = get_data()?;
cx.render(rsx!( div { "{data}" } ))
}
/// This is top-tier error handling since it displays a failure state.
///
/// However, the error is lacking in context.
pub fn App3(cx: Scope) -> Element {
match get_data() {
Some(data) => cx.render(rsx!( div { "{data}" } )),
None => cx.render(rsx!( div { "Failed to load data :(" } )),
}
}
/// For errors that return results, it's possible to short-circuit the match-based error handling with `.ok()` which converts
/// a Result<T, V> into an Option<T> and lets you abort rendering by early-returning `None`
pub fn App4(cx: Scope) -> Element {
let data = get_data_err().ok()?;
cx.render(rsx!( div { "{data}" } ))
}
/// This is great error handling since it displays a failure state... with context!
///
/// Hopefully you'll never need to display a screen like this. It's rather bad taste
pub fn App5(cx: Scope) -> Element {
match get_data_err() {
Ok(data) => cx.render(rsx!( div { "{data}" } )),
Err(c) => cx.render(rsx!( div { "Failed to load data: {c}" } )),
}
}
// this fetching function produces "nothing"
fn get_data() -> Option<String> {
None
}
// this fetching function produces "nothing"
fn get_data_err() -> Result<String, &'static str> {
Result::Err("Failed!")
}

View File

@ -1,30 +0,0 @@
//! Examples: CSS
//! -------------
//!
//! Originally taken from:
//! - https://www.w3schools.com/html/tryit.asp?filename=tryhtml_css_internal
//!
//! Include global styles in your app!
//!
//! You can simply drop in a "style" tag and set the inner contents to your stylesheet.
//! It's slightly more manual than React, but is less magical.
//!
//! A coming update with the assets system will make it possible to include global css from child components.
use dioxus::prelude::*;
const STYLE: &str = r#"
body {background-color: powderblue;}
h1 {color: blue;}
p {color: red;}
"#;
pub fn Example(cx: Scope) -> Element {
cx.render(rsx! {
head { style { "{STYLE}" } }
body {
h1 {"This is a heading"}
p {"This is a paragraph"}
}
})
}

View File

@ -1,29 +0,0 @@
//! Example: Inline Styles
//! ----------------------
//!
//! This example shows how to use inline styles in Dioxus components.
//!
//! Inline styles function very similarly to regular attributes, just grouped together in "style".
//!
//! Inline styles in Dioxus are more performant than React since we're able to cache attributes and compare by pointers.
//! However, it's still not as performant as cascaded styles. Use with care.
use dioxus::prelude::*;
pub fn Example(cx: Scope) -> Element {
cx.render(rsx! {
head {
background_color: "powderblue"
}
body {
h1 {
color: "blue",
"This is a heading"
}
p {
color: "red",
"This is a paragraph"
}
}
})
}

View File

@ -1,84 +0,0 @@
//! Example: Memoization
//! --------------------
//!
//! This example showcases how memoization works in Dioxus.
//!
//! Memoization is the process in which Dioxus skips diffing child components if their props don't change.
//! In React, components are never memoized unless wrapped in `memo` or configured with `shouldComponentUpdate`.
//!
//! Due to the safety guarantees of Rust, we can automatically memoize components in some circumstances. Whenever a
//! component's properties are valid for the `'static` lifetime, Dioxus will automatically compare the props before
//! diffing the component. If the props don't change (according to PartialEq), the component will not be re-rendered.
//!
//! However, if the props use some generics or borrow from their parent, then Dioxus can't safely supress updates,
//! and is forced to render the child. If you think that this behavior is wrong for your usecase, you can implement
//! the memo method yourself, but beware, doing so is UNSAFE and may cause issues if you do it wrong.
//!
//! If you want to gain that little bit extra performance, consider using global state management, signals, or
//! memoized collections like im-rc which are designed for this use case.
use dioxus::prelude::*;
// By default, components with no props are always memoized.
// A props of () is considered empty.
pub fn Example(cx: Scope) -> Element {
cx.render(rsx! {
div { "100% memoized!" }
})
}
// These props do not borrow any content, and therefore can be safely memoized.
// However, the parent *must* create a new string on every render.
// Notice how these props implement PartialEq - this is required for 'static props
#[derive(PartialEq, Props)]
pub struct MyProps1 {
name: String,
}
pub fn Example1(cx: Scope<MyProps1>) -> Element {
cx.render(rsx! {
div { "100% memoized! {cx.props.name}" }
})
}
// These props do not borrow any content, and therefore can be safely memoized.
// In contrast with the `String` example, these props use `Rc<str>` which operates similar to strings in JavaScript.
// These strings cannot be modified, but may be cheaply shared in many places without issue.
#[derive(PartialEq, Props)]
pub struct MyProps2 {
name: std::rc::Rc<str>,
}
pub fn Example2(cx: Scope<MyProps2>) -> Element {
cx.render(rsx! {
div { "100% memoized! {cx.props.name}" }
})
}
// These props *do* borrow any content, and therefore cannot be safely memoized!.
#[derive(PartialEq, Props)]
pub struct MyProps3<'a> {
name: &'a str,
}
// We need to manually specify a lifetime that ensures props and scope (the component's state) share the same lifetime.
// Using the `pub fn Example(cx: Scope): Component` pattern _will_ specify a lifetime, but that lifetime will be static which might
// not exactly be what you want
fn Example3(cx: Scope<'a, MyProps3<'a>>) -> DomTree {
cx.render(rsx! {
div { "Not memoized! {cx.props.name}" }
})
}
// These props *do* borrow any content, and therefore cannot be safely memoized!.
// However, they cannot be compared, so we don't need the PartialEq flag.
#[derive(Props)]
pub struct MyProps4<'a> {
onhandle: &'a dyn Fn(),
}
// We need to manually specify a lifetime that ensures props and scope (the component's state) share the same lifetime.
fn Example4<'a>(cx: Scope<'a, MyProps4<'a>>) -> DomTree {
cx.render(rsx! {
div { "Not memoized!", onclick: move |_| (props.onhandle)() }
})
}

View File

@ -1,41 +0,0 @@
//! Example: Spread pattern for Components
//! --------------------------------------
//!
//! Dioxus supports the "spread" pattern for manually building a component's properties. This is useful when props
//! are passed down from a parent, or it's more ergonomic to construct props from outside the rsx! macro.
//!
//! To use the spread pattern, simply pass ".." followed by a Rust expression. This pattern also supports overriding
//! values, using the manual props as the base and then modifying fields specified with non-spread attributes.
use dioxus::prelude::*;
pub fn Example(cx: Scope) -> Element {
let props = MyProps {
count: 0,
live: true,
name: "Dioxus",
};
cx.render(rsx! {
Example1 { ..props, count: 10, div {"child"} }
})
}
#[derive(Props)]
pub struct MyProps<'a> {
count: u32,
live: bool,
name: &'static str,
children: Element<'a>,
}
pub fn Example1<'a>(cx: Scope<'a, MyProps<'a>>) -> Element {
let MyProps { count, live, name } = cx.props;
cx.render(rsx! {
div {
h1 { "Hello, {name}"}
h3 {"Are we alive? {live}"}
p {"Count is {count}"}
&cx.props.children
}
})
}

View File

@ -1,38 +0,0 @@
//! Example: Suspense
//! -----------------
//! This example demonstrates how the use_suspense hook can be used to load and render asynchronous data. Suspense enables
//! components to wait on futures to complete before rendering the result into VNodes. These VNodes are immediately
//! available in a suspended" fashion and will automatically propagate to the UI when the future completes.
//!
//! Currently, suspense futures are non-restartable. In the future, we'll provide more granular control of how to start,
//! stop, and reset these futures.
use dioxus::prelude::*;
#[derive(serde::Deserialize)]
struct DogApi {
message: String,
}
const ENDPOINT: &str = "https://dog.ceo/api/breeds/image/random";
pub fn Example(cx: Scope) -> Element {
let doggo = use_suspense(
cx,
|| surf::get(ENDPOINT).recv_json::<DogApi>(),
|cx, res| match res {
Ok(res) => rsx!(
cx,
img {
src: "{res.message}"
}
),
Err(_) => rsx!(cx, div { "No doggos for you :(" }),
},
);
cx.render(rsx!(
div {
h1 {"Waiting for a doggo..."}
{doggo}
}
))
}

View File

@ -1,61 +0,0 @@
//! Example: Tasks
//! --------------
//!
//! Built around the same system that powers suspense, Dioxus also allows users to write arbitrary tasks that can modify
//! state asynchronously. `use_task` takes a future and returns a task handle and an option that holds the tasks's return
//! value. When the task completes, the component will re-render with the result freshly available.
//!
//! Tasks don't necessarily need to complete, however. It would be completely reasonable to wire up a websocket receiver
//! in a task and have it work infinitely while the app is running. If the socket throws an error, the task could complete
//! and the UI could present a helpful error message.
//!
//! Tasks also return the `TaskHandle` type which lets other component logic start, stop, and restart the task at any time.
//! Tasks are very much like an async-flavoroued coroutine, making them incredibly powerful.
//!
//! Tasks must be valid for the 'static lifetime, so any state management neeeds to be cloned into the closure. `use_state`
//! has a method called `for_async` which generates an AsyncUseState wrapper. This has a very similar API to the regualr
//! `use_state` but is `static.
//!
//! Remeber `use_task` is a hook! Don't call it out of order or in loops. You might aaccidentally swap the task handles
//! and break things in subtle ways.
//!
//! Whenever a component is scheduled for deletion, the task is dropped. Make sure that whatever primitives used in the
//! task have a valid drop implementation and won't leave resources tied up.
use dioxus::prelude::*;
pub static Example: Component = |cx| {
let count = use_state(&cx, || 0);
let mut direction = use_state(&cx, || 1);
// Tasks are 'static, so we need to copy relevant items in
let (async_count, dir) = (count.for_async(), *direction);
let (task, result) = use_task(cx, move || async move {
loop {
gloo_timers::future::TimeoutFuture::new(250).await;
*async_count.get_mut() += dir;
}
});
cx.render(rsx! {
div {
h1 {"count is {count}"}
button {
onclick: move |_| task.stop(),
"Stop counting"
}
button {
onclick: move |_| task.resume(),
"Start counting"
}
button {
onclick: move |_| {
direction *= -1;
task.restart();
}
"Switch counting direcion"
}
}
})
};

View File

@ -2,9 +2,10 @@
Tiny CRM: A port of the Yew CRM example to Dioxus.
*/
use dioxus::prelude::*;
use dioxus_router::{Link, Route, Router};
fn main() {
dioxus::desktop::launch(app);
dioxus_desktop::launch(app);
}
#[derive(Clone, Debug, Default)]

View File

@ -1,7 +1,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(app);
dioxus_desktop::launch(app);
}
fn app(cx: Scope) -> Element {

View File

@ -10,7 +10,7 @@ fn main() {
let mut dom = VirtualDom::new(app);
let _ = dom.rebuild();
let output = dioxus::ssr::render_vdom(&dom);
let output = dioxus_ssr::render_vdom(&dom);
println!("{}", output);
}

View File

@ -4,11 +4,11 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch_cfg(app, |c| {
dioxus_desktop::launch_cfg(app, |c| {
c.with_custom_head("<style>body { background-color: red; }</style>".into())
});
dioxus::desktop::launch_cfg(app, |c| {
dioxus_desktop::launch_cfg(app, |c| {
c.with_custom_index(
r#"
<!DOCTYPE html>

View File

@ -1,7 +1,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(app);
dioxus_desktop::launch(app);
}
fn app(cx: Scope) -> Element {

View File

@ -2,12 +2,11 @@
//! Render a bunch of doggos!
use dioxus::prelude::*;
use std::collections::HashMap;
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(app);
dioxus_desktop::launch(app);
}
#[derive(Debug, Clone, PartialEq, serde::Deserialize)]

View File

@ -1,7 +1,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(app);
dioxus_desktop::launch(app);
}
fn app(cx: Scope) -> Element {

View File

@ -1,12 +1,12 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(app);
dioxus_desktop::launch(app);
}
fn app(cx: Scope) -> Element {
let script = use_state(&cx, String::new);
let eval = use_eval(&cx);
let eval = dioxus_desktop::use_eval(&cx);
cx.render(rsx! {
div {
@ -17,7 +17,6 @@ fn app(cx: Scope) -> Element {
}
button {
onclick: move |_| eval(script),
"Execute"
}
}

View File

@ -1,9 +1,10 @@
#![allow(non_snake_case)]
use dioxus::prelude::*;
use fermi::*;
fn main() {
dioxus::desktop::launch(app)
dioxus_desktop::launch(app)
}
static NAME: Atom<String> = |_| "world".to_string();

View File

@ -11,7 +11,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch_cfg(app, |c| c.with_window(|w| w.with_resizable(true)));
dioxus_desktop::launch_cfg(app, |c| c.with_window(|w| w.with_resizable(true)));
}
fn app(cx: Scope) -> Element {

View File

@ -1,7 +1,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch_with_props(app, (), |c| {
dioxus_desktop::launch_with_props(app, (), |c| {
c.with_file_drop_handler(|_w, e| {
println!("{:?}", e);
true

View File

@ -1,10 +1,11 @@
use dioxus::desktop::tao::dpi::LogicalSize;
use dioxus::prelude::*;
use dioxus_desktop::tao::dpi::LogicalSize;
use dioxus_router::{Link, Route, Router};
fn main() {
env_logger::init();
dioxus::desktop::launch_cfg(app, |c| {
dioxus_desktop::launch_cfg(app, |c| {
c.with_window(|c| {
c.with_title("Spinsense Client")
.with_inner_size(LogicalSize::new(600, 1000))

View File

@ -6,12 +6,11 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(app);
dioxus_desktop::launch(app);
}
fn app(cx: Scope) -> Element {
cx.render(rsx! {
Router {
div {
h1 { "Form" }
form {
@ -25,6 +24,5 @@ fn app(cx: Scope) -> Element {
button { r#type: "submit", value: "Submit", "Submit the form" }
}
}
}
})
}

View File

@ -4,7 +4,7 @@ use dioxus::prelude::*;
use rand::prelude::*;
fn main() {
dioxus::desktop::launch(app);
dioxus_desktop::launch(app);
}
#[derive(Clone, PartialEq)]

View File

@ -10,7 +10,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(app);
dioxus_desktop::launch(app);
}
fn app(cx: Scope) -> Element {

View File

@ -1,7 +1,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(app);
dioxus_desktop::launch(app);
}
fn app(cx: Scope) -> Element {

View File

@ -10,13 +10,12 @@
//! proof-of-concept for the hydration feature, but you'll probably only want to use hydration for the web.
use dioxus::prelude::*;
use dioxus::ssr;
fn main() {
let vdom = VirtualDom::new(app);
let content = ssr::render_vdom_cfg(&vdom, |f| f.pre_render(true));
let content = dioxus_ssr::render_vdom_cfg(&vdom, |f| f.pre_render(true));
dioxus::desktop::launch_cfg(app, |c| c.with_prerendered(content));
dioxus_desktop::launch_cfg(app, |c| c.with_prerendered(content));
}
fn app(cx: Scope) -> Element {

View File

@ -24,7 +24,7 @@ fn Thing4<'a>(cx: Scope<'a>, _a: &'a u32) -> Element<'a> {
}
fn main() {
dioxus::desktop::launch(app);
dioxus_desktop::launch(app);
}
fn app(cx: Scope) -> Element {

View File

@ -5,7 +5,7 @@
use dioxus::{events::FormEvent, prelude::*};
fn main() {
dioxus::desktop::launch(app);
dioxus_desktop::launch(app);
}
const FIELDS: &[(&str, &str)] = &[

View File

@ -1,25 +1,21 @@
use dioxus::prelude::*;
use dioxus_router::{Link, Route, Router};
fn main() {
dioxus::desktop::launch(app);
dioxus_desktop::launch(app);
}
fn app(cx: Scope) -> Element {
cx.render(rsx! (
div {
p {
a {
href: "http://dioxuslabs.com/",
"Default link - links outside of your app"
}
a { href: "http://dioxuslabs.com/", "Default link - links outside of your app" }
}
p {
a {
href: "http://dioxuslabs.com/",
prevent_default: "onclick",
onclick: |_| {
println!("Hello Dioxus");
},
onclick: |_| println!("Hello Dioxus"),
"Custom event link - links inside of your app",
}
}
@ -28,7 +24,6 @@ fn app(cx: Scope) -> Element {
Router {
Route { to: "/", h1 { "Home" } },
Route { to: "/settings", h1 { "settings" } },
p { "----"}
ul {
Link { to: "/", li { "Router link to home" } },

View File

@ -5,7 +5,7 @@ use dioxus::events::*;
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(app);
dioxus_desktop::launch(app);
}
fn app(cx: Scope) -> Element {

View File

@ -7,7 +7,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(app);
dioxus_desktop::launch(app);
}
fn app(cx: Scope) -> Element {

View File

@ -7,7 +7,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(app);
dioxus_desktop::launch(app);
}
fn app(cx: Scope) -> Element {

View File

@ -17,13 +17,13 @@
//! the RefCell will panic and crash. You can use `try_get_mut` or `.modify` to avoid this problem, or just not hold two
//! RefMuts at the same time.
use dioxus::desktop::wry::application::dpi::LogicalSize;
use dioxus::events::*;
use dioxus::html::input_data::keyboard_types::Key;
use dioxus::prelude::*;
use dioxus_html::input_data::keyboard_types::Key;
use dioxus_desktop::wry::application::dpi::LogicalSize;
fn main() {
dioxus::desktop::launch_cfg(app, |cfg| {
dioxus_desktop::launch_cfg(app, |cfg| {
cfg.with_window(|w| {
w.with_title("Calculator Demo")
.with_resizable(false)

View File

@ -11,7 +11,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(app);
dioxus_desktop::launch(app);
}
fn app(cx: Scope) -> Element {

View File

@ -5,7 +5,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(app);
dioxus_desktop::launch(app);
}
fn app(cx: Scope) -> Element {

View File

@ -1,11 +1,11 @@
#![allow(non_snake_case)]
use dioxus::prelude::*;
use dioxus::router::{Link, Route, Router};
use dioxus_router::{Link, Route, Router};
use serde::Deserialize;
fn main() {
dioxus::desktop::launch(app);
dioxus_desktop::launch(app);
}
fn app(cx: Scope) -> Element {
@ -30,7 +30,7 @@ fn app(cx: Scope) -> Element {
}
fn BlogPost(cx: Scope) -> Element {
let post = dioxus::router::use_route(&cx).last_segment()?;
let post = dioxus_router::use_route(&cx).last_segment()?;
cx.render(rsx! {
div {
@ -46,9 +46,9 @@ struct Query {
}
fn User(cx: Scope) -> Element {
let post = dioxus::router::use_route(&cx).last_segment()?;
let post = dioxus_router::use_route(&cx).last_segment()?;
let query = dioxus::router::use_route(&cx)
let query = dioxus_router::use_route(&cx)
.query::<Query>()
.unwrap_or(Query { bold: false });

View File

@ -7,7 +7,7 @@ fn main() {
let mut vdom = VirtualDom::new(example);
vdom.rebuild();
let out = dioxus::ssr::render_vdom_cfg(&vdom, |c| c.newline(true).indent(true));
let out = dioxus_ssr::render_vdom_cfg(&vdom, |c| c.newline(true).indent(true));
println!("{}", out);
}

View File

@ -39,7 +39,7 @@
//! - Allow top-level fragments
//!
fn main() {
dioxus::desktop::launch(app);
dioxus_desktop::launch(app);
}
/// When trying to return "nothing" to Dioxus, you'll need to specify the type parameter or Rust will be sad.

View File

@ -10,12 +10,12 @@ fn main() {
// We can render VirtualDoms
let mut vdom = VirtualDom::new(app);
let _ = vdom.rebuild();
println!("{}", dioxus::ssr::render_vdom(&vdom));
println!("{}", dioxus_ssr::render_vdom(&vdom));
// Or we can render rsx! calls themselves
println!(
"{}",
dioxus::ssr::render_lazy(rsx! {
dioxus_ssr::render_lazy(rsx! {
div {
h1 { "Hello, world!" }
}
@ -25,14 +25,14 @@ fn main() {
// We can configure the SSR rendering to add ids for rehydration
println!(
"{}",
dioxus::ssr::render_vdom_cfg(&vdom, |c| c.pre_render(true))
dioxus_ssr::render_vdom_cfg(&vdom, |c| c.pre_render(true))
);
// We can even render as a writer
let mut file = String::new();
let _ = file.write_fmt(format_args!(
"{}",
dioxus::ssr::TextRenderer::from_vdom(&vdom, Default::default())
dioxus_ssr::TextRenderer::from_vdom(&vdom, Default::default())
));
println!("{}", file);
}

View File

@ -16,8 +16,8 @@
use dioxus::prelude::*;
fn main() {
use dioxus::desktop::tao::dpi::LogicalSize;
dioxus::desktop::launch_cfg(app, |cfg| {
use dioxus_desktop::tao::dpi::LogicalSize;
dioxus_desktop::launch_cfg(app, |cfg| {
cfg.with_window(|w| {
w.with_title("Doggo Fetcher")
.with_inner_size(LogicalSize::new(600.0, 800.0))

View File

@ -3,7 +3,7 @@
use dioxus::{events::MouseEvent, prelude::*};
fn main() {
dioxus::desktop::launch(app);
dioxus_desktop::launch(app);
}
fn app(cx: Scope) -> Element {

View File

@ -71,5 +71,5 @@ fn app(cx: Scope) -> Element {
}
fn main() {
dioxus::desktop::launch(app);
dioxus_desktop::launch(app);
}

View File

@ -11,7 +11,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch_cfg(app, |c| {
dioxus_desktop::launch_cfg(app, |c| {
c.with_custom_head("<script src=\"https://cdn.tailwindcss.com\"></script>".to_string())
});
}

View File

@ -6,7 +6,7 @@ use dioxus::prelude::*;
use std::time::Duration;
fn main() {
dioxus::desktop::launch(app);
dioxus_desktop::launch(app);
}
fn app(cx: Scope) -> Element {

View File

@ -3,7 +3,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(app);
dioxus_desktop::launch(app);
}
fn app(cx: Scope) -> Element {

View File

@ -2,7 +2,7 @@ use dioxus::prelude::*;
use dioxus_elements::input_data::keyboard_types::Key;
fn main() {
dioxus::desktop::launch(app);
dioxus_desktop::launch(app);
}
#[derive(PartialEq)]

View File

@ -1,13 +1,13 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch_cfg(app, |cfg| {
dioxus_desktop::launch_cfg(app, |cfg| {
cfg.with_window(|w| w.with_title("BorderLess Demo").with_decorations(false))
});
}
fn app(cx: Scope) -> Element {
let window = dioxus::desktop::use_window(&cx);
let window = dioxus_desktop::use_window(&cx);
// if you want to make window fullscreen, you need close the resizable.
// window.set_fullscreen(true);

View File

@ -1,8 +1,8 @@
use dioxus::desktop::use_window;
use dioxus::prelude::*;
use dioxus_desktop::use_window;
fn main() {
dioxus::desktop::launch(app);
dioxus_desktop::launch(app);
}
fn app(cx: Scope) -> Element {

View File

@ -5,7 +5,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(app);
dioxus_desktop::launch(app);
}
fn app(cx: Scope) -> Element {

View File

@ -1,46 +0,0 @@
# Parity with React
Parity has moved to the homepage
## Required services:
---
Gloo is covering a lot of these. We want to build hooks around these and provide examples on how to use them.
https://github.com/rustwasm/gloo
For example, resize observer would function like this:
```rust
pub static Example: Component = |cx| {
let observer = use_resize_observer();
cx.render(rsx!(
div { ref: observer.node_ref
"Size, x: {observer.x} y: {observer.y}"
}
))
}
```
However, resize observing is _not_ cross-platform, so this hook (internally) needs to abstract over the rendering platform.
For other services, we shell out to gloo. If the gloo service doesn't exist, then we need to contribute to the project to make sure it exists.
| Service | Hook examples | Current Projects |
| ---------------------------- | ------------- | ---------------- |
| Fetch | 👀 | Reqwest/surf |
| Local storage (cache) | 👀 | Gloo |
| Persistent storage (IndexDB) | 👀 | 👀 |
| WebSocket | 👀 | Gloo |
| 3D Renderer / WebGL | 👀 | Gloo |
| Web Worker | 👀 | 👀 |
| Router | 👀 | 👀 |
| Notifications | 👀 | 👀 |
| WebRTC Client | 👀 | 👀 |
| Service Workers | 👀 | 👀 |
| Resize Observer | 👀 | 👀 |
| Canvas | 👀 | 👀 |
| Clipboard | 👀 | 👀 |
| Fullscreen | 👀 | 👀 |
| History API | 👀 | 👀 |

View File

@ -44,7 +44,7 @@ To launch an app, we use the `launch` method for the specific renderer we want t
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(app);
dioxus_desktop::launch(app);
}
fn app(cx: Scope) -> Element {
@ -276,7 +276,7 @@ Using components, templates, and hooks, we can build a simple app.
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(App);
dioxus_desktop::launch(App);
}
fn App(cx: Scope) -> Element {

View File

@ -1,90 +0,0 @@
# Road map
This release map gives a sense of the release cadence and features per update going forward into the future. PRs are required to be squashed before merging. For each point release, we save a branch on master (0.1, 0.2, 0.3, master). Eventually, we'll remove these in favor of higher point releases when dioxus is stabilized. Any live PRs will be merged into the dev branch.
Until 0.3, Dioxus will be in stealth mode. The goal is to launch with a bountiful feature set and a cohesive API before OSS tears it apart :).
## v0.1: Bare Necessities
> Enable ergonomic and performant webapps
---
Dioxus Core
- Lifecycles for components
- Internal event system
- Diffing
- Patching
Html macro
- special formatting
- closure handlers
- child handlers
- iterator handlers
Dioxus web
- a
Dioxus CLI
- Develop
- Bundle
- Test
Server-side-rendering
- Write nodes to string
- Integration with tide, Actix, warp
Dioxus WebView (desktop)
- One-file setup for desktop apps
- Integration with the web browser for rapid development
## v0.2: Bread and butter
> Complex apps? CHECK
---
State management
- Dioxus-Reducer as the blessed redux alternative
- Includes thunks and reducers (async dispatches)
- Dioxus-DataFlow as the blessed recoil alternative
- The hip, new approach for granular state
Dioxus CLI
- Visual tool?
- Asset bundling service
Dioxus DevTools integration with the web
- Basic support for pure liveview/webview
## v0.3: Superpowers
> Enable LiveView for fullstack development
---
Dioxus LiveView
- Custom server built on Actix (or something fast)
- Ergonomic builders
- Concurrent system built into dioxus core
Dioxus iOS
- Initial support via webview
- Look into native support based on how Flutter/SwiftUI works
Dioxus Android
## v0.4: Community
> Foster the incoming community

View File

@ -1,26 +0,0 @@
# Safety
We don't claim to be a "safe" library. We want to be 100% safe, and will create tests and validate that we are, but our priorities for this library are:
- productivity
- performance
- safety
We are willing to use sharp tools (ie transmuting self-referential pointer types) in order to achieve higher ergonomics (ie returning self-referential listeners).
However, we can only use these sharp tools if we verify that it's not possible to write user-facing code that breaks safety guarantees. For internal code... well, whoever contributes needs to understand the architecture and read the comments related to safety.
We are doing one of the more annoying things to do with Rust: self-referential graph structures. VNodes reference a bump arena which is contained by scope. Conveniently, the bump arenas also belong to scope, and now we have a self-referential struct.
We */would/* use a solution like ourborous or self_referential, but these libraries generate "imaginary code" that doesn't integrate with RA. It's simpler and easier to review if we set some rules on what is/isn't allowed.
Here's the two main sources of unsafety:
- 1) vnodes, bump arenas, and scope
- 2) context_api and use_context
For 1), we can fairly confidently guarantee safety by being careful about lifetime casts and by using tools like refcell as flags.
For 2), use_context authors (mostly state management) can implement either the Unsafe API or the Safe API. The Safe API is less performant, but will likely do everything you need. The Unsafe API is more performant, but will bite you if you don't implement it properly. Always validate with MIRI!
Because of 2), we provide two state management solutions (D-Reducer and D-Dataflow) that use the Unsafe API, but will still be 100% safe.

Some files were not shown because too many files have changed in this diff Show More