wip: parity document
This commit is contained in:
1 parent
ee67654f58
commit
ba975410f9
7 files changed
+115
-51
No files matched your search
+13
-2
@@ -5,6 +5,10 @@ Welcome to the first iteration of the Dioxus Virtual DOM! This release brings su
|
|||||||
- Server-rendering with custom ToString implementation
|
- Server-rendering with custom ToString implementation
|
||||||
- State management
|
- State management
|
||||||
- Build CLI
|
- Build CLI
|
||||||
|
- Foundational hooks
|
||||||
|
- Context API
|
||||||
|
- Basic suspense
|
||||||
|
- Controlled components
|
||||||
----
|
----
|
||||||
## Project: Initial VDOM support (TBD)
|
## Project: Initial VDOM support (TBD)
|
||||||
> Get the initial VDom + Event System + Patching + Diffing + Component framework up and running
|
> Get the initial VDom + Event System + Patching + Diffing + Component framework up and running
|
||||||
@@ -80,18 +84,25 @@ Welcome to the first iteration of the Dioxus Virtual DOM! This release brings su
|
|||||||
- [x] Tweak macro parsing for better errors
|
- [x] Tweak macro parsing for better errors
|
||||||
- [x] dirty tagging, compression
|
- [x] dirty tagging, compression
|
||||||
- [x] code health
|
- [x] code health
|
||||||
|
- [ ] name spacing so svg works
|
||||||
|
- [ ] fix keys on elements
|
||||||
|
- [ ] controlled components (kinda tuff since we need all these different platforms)
|
||||||
|
- [ ] Their own crate
|
||||||
|
- [ ] Re-exported through the `dioxus` crate (not core)
|
||||||
|
- [ ] Hooks
|
||||||
|
- [ ] Re-exported through the `dioxus` crate (not essential to core virtualdom)
|
||||||
|
|
||||||
|
## Less-essential todos
|
||||||
- [ ] Make events lazy (use traits + Box<dyn>) - not sure what this means anymore
|
- [ ] Make events lazy (use traits + Box<dyn>) - not sure what this means anymore
|
||||||
- [ ] Beef up the dioxus CLI tool to report build progress
|
- [ ] Beef up the dioxus CLI tool to report build progress
|
||||||
- [ ] Extract arena logic out for better safety guarantees
|
- [ ] Extract arena logic out for better safety guarantees
|
||||||
- [ ] Extract BumpFrame logic out for better safety guarantees
|
- [ ] Extract BumpFrame logic out for better safety guarantees
|
||||||
- [ ] make SSR follow HTML spec
|
- [ ] make SSR follow HTML spec
|
||||||
- [ ] fix keys on elements
|
|
||||||
- [ ] MIRI tests
|
- [ ] MIRI tests
|
||||||
- [ ] all synthetic events filled out
|
- [ ] all synthetic events filled out
|
||||||
- [ ] double check event targets and stuff
|
- [ ] double check event targets and stuff
|
||||||
- [ ] Documentation overhaul
|
- [ ] Documentation overhaul
|
||||||
- [ ] Website
|
- [ ] Website
|
||||||
- [ ] controlled components
|
|
||||||
|
|
||||||
lower priority features
|
lower priority features
|
||||||
- [ ] Attributes on elements should implement format_args instead of string fmt
|
- [ ] Attributes on elements should implement format_args instead of string fmt
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
# Parity with React
|
||||||
|
|
||||||
|
Sorted by priority
|
||||||
|
|
||||||
|
| Feature | Dioxus | React |
|
||||||
|
| ---------------------- | ------ | ----- |
|
||||||
|
| Conditional Rendering | ✅ | ✅ |
|
||||||
|
| Map, Iterator | ✅ | ✅ |
|
||||||
|
| Keyed Components | ✅ | ✅ |
|
||||||
|
| Web | ✅ | ✅ |
|
||||||
|
| Desktop (webview) | ✅ | ✅ |
|
||||||
|
| Context | ✅ | ✅ |
|
||||||
|
| Hook | ✅ | ✅ |
|
||||||
|
| SSR | ✅ | ✅ |
|
||||||
|
| Runs natively | ✅ | 👀 |
|
||||||
|
| Null components | 👀 | ✅ |
|
||||||
|
| Fragments | 👀 | ✅ |
|
||||||
|
| Component Children | 👀 | ✅ |
|
||||||
|
| NodeRef | 👀 | ✅ |
|
||||||
|
| Controlled Inputs | 👀 | ✅ |
|
||||||
|
| No-div components | 👀 | ✅ |
|
||||||
|
| CSS/Inline Styles | 👀 | ✅ |
|
||||||
|
| 1st class global state | 👀 | ✅ |
|
||||||
|
| -------------------- | ----- | ----- |
|
||||||
|
| 1st class router | 👀 | ✅ |
|
||||||
|
| Suspense | 👀 | 👀 |
|
||||||
|
| Animation | 👀 | ✅ |
|
||||||
|
| Mobile | 👀 | ✅ |
|
||||||
|
| Desktop (native) | 👀 | ✅ |
|
||||||
|
| 3D Renderer | 👀 | ✅ |
|
||||||
|
| -------------------- | ----- | ----- |
|
||||||
|
| Portal | 👀 | ✅ |
|
||||||
|
| Error boundary | 👀 | ✅ |
|
||||||
|
| Code-splitting | 👀 | ✅ |
|
||||||
@@ -8,8 +8,8 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
dioxus-core = { path = "../core" }
|
dioxus-core = { path = "../core" }
|
||||||
uuid = "0.8.2"
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
uuid = { version = "0.8.2", features = ["v4"] }
|
||||||
dioxus-web = { path = "../web" }
|
dioxus-web = { path = "../web" }
|
||||||
wasm-bindgen-futures = "*"
|
wasm-bindgen-futures = "*"
|
||||||
@@ -2,16 +2,22 @@ use std::collections::HashMap;
|
|||||||
|
|
||||||
use dioxus_core::prelude::*;
|
use dioxus_core::prelude::*;
|
||||||
use recoil::*;
|
use recoil::*;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
const TODOS: AtomFamily<&str, Todo> = |_| HashMap::new();
|
const TODOS: AtomFamily<Uuid, Todo> = |_| HashMap::new();
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
struct Todo {
|
struct Todo {
|
||||||
checked: bool,
|
checked: bool,
|
||||||
|
title: String,
|
||||||
contents: String,
|
contents: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
static App: FC<()> = |ctx, _| {
|
static App: FC<()> = |ctx, _| {
|
||||||
|
use_init_recoil_root(ctx);
|
||||||
|
|
||||||
|
let todos = use_recoil_family(ctx, &TODOS);
|
||||||
|
|
||||||
rsx! { in ctx,
|
rsx! { in ctx,
|
||||||
div {
|
div {
|
||||||
"Basic Todolist with AtomFamilies in Recoil.rs"
|
"Basic Todolist with AtomFamilies in Recoil.rs"
|
||||||
@@ -19,11 +25,20 @@ static App: FC<()> = |ctx, _| {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static Child: FC<()> = |ctx, _| {
|
#[derive(Props, PartialEq)]
|
||||||
// let todo = use_recoil_value(ctx, &TODOS);
|
struct ChildProps {
|
||||||
|
id: Uuid,
|
||||||
|
}
|
||||||
|
|
||||||
|
static Child: FC<ChildProps> = |ctx, props| {
|
||||||
|
let (todo, set_todo) = use_recoil_state(ctx, &TODOS.select(&props.id));
|
||||||
|
|
||||||
rsx! { in ctx,
|
rsx! { in ctx,
|
||||||
div {
|
div {
|
||||||
|
h1 {"{todo.title}"}
|
||||||
|
input { type: "checkbox", name: "scales", checked: "{todo.checked}" }
|
||||||
|
label { "{todo.contents}", for: "scales" }
|
||||||
|
p {"{todo.contents}"}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,8 +18,9 @@ const D_SELECTOR: SelectorFamilyBorrowed<i32, i32> = |api, key| -> &i32 {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static App: FC<()> = |ctx, _| {
|
static App: FC<()> = |ctx, _| {
|
||||||
let title = use_recoil_value(ctx, &C_SELECTOR);
|
use_init_recoil_root(ctx);
|
||||||
|
|
||||||
|
let title = use_recoil_value(ctx, &C_SELECTOR);
|
||||||
let title = "";
|
let title = "";
|
||||||
rsx! { in ctx,
|
rsx! { in ctx,
|
||||||
div {
|
div {
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ pub struct CollectionSelection<T> {
|
|||||||
_never: PhantomData<T>,
|
_never: PhantomData<T>,
|
||||||
}
|
}
|
||||||
impl<T> Readable<T> for CollectionSelection<T> {}
|
impl<T> Readable<T> for CollectionSelection<T> {}
|
||||||
|
impl<T> Writeable<T> for CollectionSelection<T> {}
|
||||||
|
|
||||||
// =================
|
// =================
|
||||||
// Selectors
|
// Selectors
|
||||||
@@ -125,22 +126,26 @@ mod hooks {
|
|||||||
|
|
||||||
pub fn use_set_state<'a, T: PartialEq>(
|
pub fn use_set_state<'a, T: PartialEq>(
|
||||||
c: Context<'a>,
|
c: Context<'a>,
|
||||||
t: &'static impl Writeable<T>,
|
t: &impl Writeable<T>,
|
||||||
) -> &'a Rc<dyn Fn(T)> {
|
) -> &'a Rc<dyn Fn(T)> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn use_recoil_state<'a, T: PartialEq + 'static>(
|
pub fn use_recoil_state<'a, T: PartialEq + 'static>(
|
||||||
ctx: Context<'a>,
|
ctx: Context<'a>,
|
||||||
readable: &'static impl Writeable<T>,
|
writeable: &impl Writeable<T>,
|
||||||
) -> (&'a T, &'a Rc<dyn Fn(T)>) {
|
) -> (&'a T, &'a Rc<dyn Fn(T)>) {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn use_recoil_value<'a, T: PartialEq>(
|
pub fn use_recoil_value<'a, T: PartialEq>(ctx: Context<'a>, t: &impl Readable<T>) -> &'a T {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn use_recoil_family<'a, K, V, C: FamilyCollection<K, V>>(
|
||||||
ctx: Context<'a>,
|
ctx: Context<'a>,
|
||||||
t: &'static impl Readable<T>,
|
t: &AtomFamily<K, V, C>,
|
||||||
) -> &'a T {
|
) -> &'a C {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,16 +13,24 @@ use recoil::*;
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
const APP_STYLE: &'static str = include_str!("./todomvc/style.css");
|
#[derive(PartialEq, Clone, Copy)]
|
||||||
|
pub enum FilterState {
|
||||||
|
All,
|
||||||
|
Active,
|
||||||
|
Completed,
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
wasm_bindgen_futures::spawn_local(dioxus_web::WebsysRenderer::start(App));
|
pub struct TodoItem {
|
||||||
|
pub id: Uuid,
|
||||||
|
pub checked: bool,
|
||||||
|
pub contents: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Declare our global app state
|
// Declare our global app state
|
||||||
const TODO_LIST: Atom<HashMap<Uuid, TodoItem>> = atom(|_| Default::default());
|
const TODO_LIST: Atom<HashMap<Uuid, TodoItem>> = |_| Default::default();
|
||||||
const FILTER: Atom<FilterState> = atom(|_| FilterState::All);
|
const FILTER: Atom<FilterState> = |_| FilterState::All;
|
||||||
const TODOS_LEFT: selector<usize> = selector(|api| api.get(&TODO_LIST).len());
|
const TODOS_LEFT: Selector<usize> = |api| api.get(&TODO_LIST).len();
|
||||||
|
|
||||||
// Implement a simple abstraction over sets/gets of multiple atoms
|
// Implement a simple abstraction over sets/gets of multiple atoms
|
||||||
struct TodoManager(RecoilApi);
|
struct TodoManager(RecoilApi);
|
||||||
@@ -64,32 +72,7 @@ impl TodoManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Copy)]
|
pub fn TodoList(ctx: Context, _props: &()) -> DomTree {
|
||||||
pub enum FilterState {
|
|
||||||
All,
|
|
||||||
Active,
|
|
||||||
Completed,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
|
||||||
pub struct TodoItem {
|
|
||||||
pub id: Uuid,
|
|
||||||
pub checked: bool,
|
|
||||||
pub contents: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn App(ctx: Context, props: &()) -> DomTree {
|
|
||||||
use_init_recoil_root(ctx);
|
|
||||||
|
|
||||||
rsx! { in ctx,
|
|
||||||
div { id: "app", style { "{APP_STYLE}" }
|
|
||||||
TodoList {}
|
|
||||||
Footer {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn TodoList(ctx: Context, props: &()) -> DomTree {
|
|
||||||
let draft = use_state_new(&ctx, || "".to_string());
|
let draft = use_state_new(&ctx, || "".to_string());
|
||||||
let todos = use_recoil_value(&ctx, &TODO_LIST);
|
let todos = use_recoil_value(&ctx, &TODO_LIST);
|
||||||
let filter = use_recoil_value(&ctx, &FILTER);
|
let filter = use_recoil_value(&ctx, &FILTER);
|
||||||
@@ -154,9 +137,9 @@ pub fn TodoEntry(ctx: Context, props: &TodoEntryProps) -> DomTree {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn FilterToggles(ctx: Context, props: &()) -> DomTree {
|
pub fn FilterToggles(ctx: Context, _props: &()) -> DomTree {
|
||||||
let reducer = use_recoil_context::<TodoManager>(ctx);
|
let reducer = use_recoil_callback(ctx, |api| TodoManager(api));
|
||||||
let items_left = use_selector(ctx, &TODOS_LEFT);
|
let items_left = use_recoil_value(ctx, &TODOS_LEFT);
|
||||||
|
|
||||||
let toggles = [
|
let toggles = [
|
||||||
("All", "", FilterState::All),
|
("All", "", FilterState::All),
|
||||||
@@ -168,10 +151,9 @@ pub fn FilterToggles(ctx: Context, props: &()) -> DomTree {
|
|||||||
rsx!(
|
rsx!(
|
||||||
li {
|
li {
|
||||||
class: "{name}"
|
class: "{name}"
|
||||||
a {
|
a { "{name}",
|
||||||
href: "{path}",
|
href: "{path}",
|
||||||
onclick: move |_| reducer.set_filter(&filter),
|
onclick: move |_| reducer.set_filter(&filter),
|
||||||
"{name}"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -196,7 +178,7 @@ pub fn FilterToggles(ctx: Context, props: &()) -> DomTree {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn Footer(ctx: Context, props: &()) -> DomTree {
|
pub fn Footer(ctx: Context, _props: &()) -> DomTree {
|
||||||
rsx! { in ctx,
|
rsx! { in ctx,
|
||||||
footer {
|
footer {
|
||||||
class: "info"
|
class: "info"
|
||||||
@@ -212,3 +194,19 @@ pub fn Footer(ctx: Context, props: &()) -> DomTree {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const APP_STYLE: &'static str = include_str!("./todomvc/style.css");
|
||||||
|
|
||||||
|
fn App(ctx: Context, _props: &()) -> DomTree {
|
||||||
|
use_init_recoil_root(ctx);
|
||||||
|
rsx! { in ctx,
|
||||||
|
div { id: "app", style { "{APP_STYLE}" }
|
||||||
|
TodoList {}
|
||||||
|
Footer {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
wasm_bindgen_futures::spawn_local(dioxus_web::WebsysRenderer::start(App));
|
||||||
|
}
|
||||||
Reference in new issue
Block a user