diff --git a/notes/CHANGELOG.md b/notes/CHANGELOG.md index eae647acd..b6d3ceec9 100644 --- a/notes/CHANGELOG.md +++ b/notes/CHANGELOG.md @@ -5,6 +5,10 @@ Welcome to the first iteration of the Dioxus Virtual DOM! This release brings su - Server-rendering with custom ToString implementation - State management - Build CLI +- Foundational hooks +- Context API +- Basic suspense +- Controlled components ---- ## Project: Initial VDOM support (TBD) > 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] dirty tagging, compression - [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) - not sure what this means anymore - [ ] Beef up the dioxus CLI tool to report build progress - [ ] Extract arena logic out for better safety guarantees - [ ] Extract BumpFrame logic out for better safety guarantees - [ ] make SSR follow HTML spec -- [ ] fix keys on elements - [ ] MIRI tests - [ ] all synthetic events filled out - [ ] double check event targets and stuff - [ ] Documentation overhaul - [ ] Website -- [ ] controlled components lower priority features - [ ] Attributes on elements should implement format_args instead of string fmt diff --git a/notes/Parity.md b/notes/Parity.md new file mode 100644 index 000000000..1b7e124c3 --- /dev/null +++ b/notes/Parity.md @@ -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 | 👀 | ✅ | diff --git a/packages/recoil/Cargo.toml b/packages/recoil/Cargo.toml index e6fa17095..30567fbca 100644 --- a/packages/recoil/Cargo.toml +++ b/packages/recoil/Cargo.toml @@ -8,8 +8,8 @@ edition = "2018" [dependencies] dioxus-core = { path = "../core" } -uuid = "0.8.2" [dev-dependencies] +uuid = { version = "0.8.2", features = ["v4"] } dioxus-web = { path = "../web" } wasm-bindgen-futures = "*" diff --git a/packages/recoil/examples/family.rs b/packages/recoil/examples/family.rs index 29bea4b5d..d9e300b6b 100644 --- a/packages/recoil/examples/family.rs +++ b/packages/recoil/examples/family.rs @@ -2,16 +2,22 @@ use std::collections::HashMap; use dioxus_core::prelude::*; use recoil::*; +use uuid::Uuid; -const TODOS: AtomFamily<&str, Todo> = |_| HashMap::new(); +const TODOS: AtomFamily = |_| HashMap::new(); #[derive(PartialEq)] struct Todo { checked: bool, + title: String, contents: String, } static App: FC<()> = |ctx, _| { + use_init_recoil_root(ctx); + + let todos = use_recoil_family(ctx, &TODOS); + rsx! { in ctx, div { "Basic Todolist with AtomFamilies in Recoil.rs" @@ -19,11 +25,20 @@ static App: FC<()> = |ctx, _| { } }; -static Child: FC<()> = |ctx, _| { - // let todo = use_recoil_value(ctx, &TODOS); +#[derive(Props, PartialEq)] +struct ChildProps { + id: Uuid, +} + +static Child: FC = |ctx, props| { + let (todo, set_todo) = use_recoil_state(ctx, &TODOS.select(&props.id)); + rsx! { in ctx, div { - + h1 {"{todo.title}"} + input { type: "checkbox", name: "scales", checked: "{todo.checked}" } + label { "{todo.contents}", for: "scales" } + p {"{todo.contents}"} } } }; diff --git a/packages/recoil/examples/selectorlist.rs b/packages/recoil/examples/selectorlist.rs index 8f495530d..28f4afab8 100644 --- a/packages/recoil/examples/selectorlist.rs +++ b/packages/recoil/examples/selectorlist.rs @@ -18,8 +18,9 @@ const D_SELECTOR: SelectorFamilyBorrowed = |api, key| -> &i32 { }; 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 = ""; rsx! { in ctx, div { diff --git a/packages/recoil/src/lib.rs b/packages/recoil/src/lib.rs index 5e7bb7703..a879d8c7e 100644 --- a/packages/recoil/src/lib.rs +++ b/packages/recoil/src/lib.rs @@ -43,6 +43,7 @@ pub struct CollectionSelection { _never: PhantomData, } impl Readable for CollectionSelection {} +impl Writeable for CollectionSelection {} // ================= // Selectors @@ -125,22 +126,26 @@ mod hooks { pub fn use_set_state<'a, T: PartialEq>( c: Context<'a>, - t: &'static impl Writeable, + t: &impl Writeable, ) -> &'a Rc { todo!() } pub fn use_recoil_state<'a, T: PartialEq + 'static>( ctx: Context<'a>, - readable: &'static impl Writeable, + writeable: &impl Writeable, ) -> (&'a T, &'a Rc) { todo!() } - pub fn use_recoil_value<'a, T: PartialEq>( + pub fn use_recoil_value<'a, T: PartialEq>(ctx: Context<'a>, t: &impl Readable) -> &'a T { + todo!() + } + + pub fn use_recoil_family<'a, K, V, C: FamilyCollection>( ctx: Context<'a>, - t: &'static impl Readable, - ) -> &'a T { + t: &AtomFamily, + ) -> &'a C { todo!() } diff --git a/packages/web/examples/todomvcsingle.rs b/packages/web/examples/todomvcsingle.rs index 4d5d0a0a7..354c90009 100644 --- a/packages/web/examples/todomvcsingle.rs +++ b/packages/web/examples/todomvcsingle.rs @@ -13,16 +13,24 @@ use recoil::*; use std::collections::HashMap; 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() { - wasm_bindgen_futures::spawn_local(dioxus_web::WebsysRenderer::start(App)); +#[derive(Debug, PartialEq, Clone)] +pub struct TodoItem { + pub id: Uuid, + pub checked: bool, + pub contents: String, } // Declare our global app state -const TODO_LIST: Atom> = atom(|_| Default::default()); -const FILTER: Atom = atom(|_| FilterState::All); -const TODOS_LEFT: selector = selector(|api| api.get(&TODO_LIST).len()); +const TODO_LIST: Atom> = |_| Default::default(); +const FILTER: Atom = |_| FilterState::All; +const TODOS_LEFT: Selector = |api| api.get(&TODO_LIST).len(); // Implement a simple abstraction over sets/gets of multiple atoms struct TodoManager(RecoilApi); @@ -64,32 +72,7 @@ impl TodoManager { } } -#[derive(PartialEq, Clone, Copy)] -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 { +pub fn TodoList(ctx: Context, _props: &()) -> DomTree { let draft = use_state_new(&ctx, || "".to_string()); let todos = use_recoil_value(&ctx, &TODO_LIST); 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 { - let reducer = use_recoil_context::(ctx); - let items_left = use_selector(ctx, &TODOS_LEFT); +pub fn FilterToggles(ctx: Context, _props: &()) -> DomTree { + let reducer = use_recoil_callback(ctx, |api| TodoManager(api)); + let items_left = use_recoil_value(ctx, &TODOS_LEFT); let toggles = [ ("All", "", FilterState::All), @@ -168,10 +151,9 @@ pub fn FilterToggles(ctx: Context, props: &()) -> DomTree { rsx!( li { class: "{name}" - a { + a { "{name}", href: "{path}", 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, footer { 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)); +}