From 8657b474015b28984c999b54f1af338d076fbf60 Mon Sep 17 00:00:00 2001 From: Nolan Darilek Date: Thu, 9 Mar 2023 11:05:41 -0600 Subject: [PATCH 01/10] Add function to remove all global shortcuts. --- packages/desktop/src/desktop_context.rs | 5 +++++ packages/desktop/src/shortcut.rs | 12 ++++++++++++ 2 files changed, 17 insertions(+) diff --git a/packages/desktop/src/desktop_context.rs b/packages/desktop/src/desktop_context.rs index 7db554517..2ed4bbee9 100644 --- a/packages/desktop/src/desktop_context.rs +++ b/packages/desktop/src/desktop_context.rs @@ -271,6 +271,11 @@ impl DesktopContext { self.shortcut_manager.remove_shortcut(id) } + /// Remove all global shortcuts + pub fn remove_all_shortcuts(&self) { + self.shortcut_manager.remove_all() + } + /// Push an objc view to the window #[cfg(target_os = "ios")] pub fn push_view(&self, view: objc_id::ShareId) { diff --git a/packages/desktop/src/shortcut.rs b/packages/desktop/src/shortcut.rs index cf70d307a..5232bdb8b 100644 --- a/packages/desktop/src/shortcut.rs +++ b/packages/desktop/src/shortcut.rs @@ -113,6 +113,18 @@ impl ShortcutRegistry { } } } + + pub(crate) fn remove_all(&self) { + let mut shortcuts = self.shortcuts.borrow_mut(); + shortcuts.clear(); + let _ = self.manager.borrow_mut().unregister_all(); + // prevent CTRL+R from reloading the page which breaks apps + let _ = self.add_shortcut( + Some(ModifiersState::CONTROL), + KeyCode::KeyR, + Box::new(|| {}), + ); + } } #[non_exhaustive] From f40ba5ec3c0e153c8cf1a1d7328336958a587918 Mon Sep 17 00:00:00 2001 From: Michael Clayton Date: Thu, 9 Mar 2023 12:36:49 -0500 Subject: [PATCH 02/10] fix Guide link in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5b680a1ba..40981401e 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ | Examples | - Guide + Guide | 中文 | From 9ae5f47d19dc1c9882e42e1f33a81487da927700 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Thu, 9 Mar 2023 17:01:41 -0800 Subject: [PATCH 03/10] Allow liveview to spawn pre-injected virtualdoms --- packages/liveview/src/pool.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/liveview/src/pool.rs b/packages/liveview/src/pool.rs index 022641d5c..e02c8195b 100644 --- a/packages/liveview/src/pool.rs +++ b/packages/liveview/src/pool.rs @@ -37,7 +37,16 @@ impl LiveViewPool { app: fn(Scope) -> Element, props: T, ) -> Result<(), LiveViewError> { - match self.pool.spawn_pinned(move || run(app, props, ws)).await { + self.launch_virtualdom(ws, move || VirtualDom::new_with_props(app, props)) + .await + } + + pub async fn launch_virtualdom VirtualDom + Send + 'static>( + &self, + ws: impl LiveViewSocket, + make_app: F, + ) -> Result<(), LiveViewError> { + match self.pool.spawn_pinned(move || run(make_app(), ws)).await { Ok(Ok(_)) => Ok(()), Ok(Err(e)) => Err(e), Err(_) => Err(LiveViewError::SendingFailed), @@ -95,14 +104,7 @@ impl LiveViewSocket for S where /// As long as your framework can provide a Sink and Stream of Strings, you can use this function. /// /// You might need to transform the error types of the web backend into the LiveView error type. -pub async fn run( - app: Component, - props: T, - ws: impl LiveViewSocket, -) -> Result<(), LiveViewError> -where - T: Send + 'static, -{ +pub async fn run(mut vdom: VirtualDom, ws: impl LiveViewSocket) -> Result<(), LiveViewError> { #[cfg(all(feature = "hot-reload", debug_assertions))] let mut hot_reload_rx = { let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); @@ -112,8 +114,6 @@ where rx }; - let mut vdom = VirtualDom::new_with_props(app, props); - // todo: use an efficient binary packed format for this let edits = serde_json::to_string(&vdom.rebuild()).unwrap(); From eee6cbabb20258c0d64621ce9bc156342b25d7ce Mon Sep 17 00:00:00 2001 From: Kyle Smith Date: Fri, 10 Mar 2023 08:07:53 -0500 Subject: [PATCH 04/10] Update Router book to reflect crate separation and need for `web` feature. (#873) --- docs/router/src/README.md | 11 ++++++----- packages/router/README.md | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/router/src/README.md b/docs/router/src/README.md index fcbd79aef..055c3009b 100644 --- a/docs/router/src/README.md +++ b/docs/router/src/README.md @@ -1,10 +1,11 @@ # Dioxus Router: Introduction + Whether or not you're building a website, desktop app, or mobile app, organizing your app's views into "pages" can be an effective method for organization and maintainability. -Dioxus comes with a router built-in. To start utilizing Dioxus Router, enable the ``router`` feature in your ``Cargo.toml`` file. -```toml -[dependencies] -dioxus = { version = "x.x.x", features = [.., "router"] } -``` +The `dioxus-router` crate contains the Router module. To add it to your project run: + + cargo add dioxus-router + +> **Be sure to include the `web` feature (`--feature web`) for deployment into a browser!** In this book you'll find a short [guide](./guide/index.md) to get up to speed with Dioxus Router, as well as the router's [reference](./reference/index.md). \ No newline at end of file diff --git a/packages/router/README.md b/packages/router/README.md index 0e38512e8..c7be4496d 100644 --- a/packages/router/README.md +++ b/packages/router/README.md @@ -1,4 +1,4 @@ -# Dioxus Native Core +# Dioxus Router [![Crates.io][crates-badge]][crates-url] [![MIT licensed][mit-badge]][mit-url] From 4847789a839d1486fcba18ca849cbac8565c310f Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Sun, 12 Mar 2023 14:47:30 -0500 Subject: [PATCH 05/10] fix event bubbling within a single template --- packages/core/src/arena.rs | 6 +++--- packages/core/src/virtual_dom.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/core/src/arena.rs b/packages/core/src/arena.rs index 7fbaf0e12..caa863adf 100644 --- a/packages/core/src/arena.rs +++ b/packages/core/src/arena.rs @@ -175,10 +175,10 @@ impl VirtualDom { } impl ElementPath { - pub(crate) fn is_ascendant(&self, big: &&[u8]) -> bool { + pub(crate) fn is_decendant(&self, small: &&[u8]) -> bool { match *self { - ElementPath::Deep(small) => small.len() <= big.len() && small == &big[..small.len()], - ElementPath::Root(r) => big.len() == 1 && big[0] == r as u8, + ElementPath::Deep(big) => small.len() <= big.len() && *small == &big[..small.len()], + ElementPath::Root(r) => small.len() == 1 && small[0] == r as u8, } } } diff --git a/packages/core/src/virtual_dom.rs b/packages/core/src/virtual_dom.rs index a29671f5d..2269815aa 100644 --- a/packages/core/src/virtual_dom.rs +++ b/packages/core/src/virtual_dom.rs @@ -396,7 +396,7 @@ impl VirtualDom { // Remove the "on" prefix if it exists, TODO, we should remove this and settle on one if attr.name.trim_start_matches("on") == name - && target_path.is_ascendant(&this_path) + && target_path.is_decendant(&this_path) { listeners.push(&attr.value); From fda125de5f620a8fdf6334fa9cb13d6e94a01bac Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Sun, 12 Mar 2023 15:13:34 -0500 Subject: [PATCH 06/10] fix clippy --- packages/tui/src/config.rs | 9 ++------- packages/tui/src/focus.rs | 9 ++------- packages/tui/src/node.rs | 9 ++------- 3 files changed, 6 insertions(+), 21 deletions(-) diff --git a/packages/tui/src/config.rs b/packages/tui/src/config.rs index 8251b13b6..41e068542 100644 --- a/packages/tui/src/config.rs +++ b/packages/tui/src/config.rs @@ -46,18 +46,13 @@ impl Default for Config { } } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub enum RenderingMode { /// only 16 colors by accessed by name, no alpha support BaseColors, /// 8 bit colors, will be downsampled from rgb colors Ansi, /// 24 bit colors, most terminals support this + #[default] Rgb, } - -impl Default for RenderingMode { - fn default() -> Self { - RenderingMode::Rgb - } -} diff --git a/packages/tui/src/focus.rs b/packages/tui/src/focus.rs index 57f1c9e1f..89245d9b9 100644 --- a/packages/tui/src/focus.rs +++ b/packages/tui/src/focus.rs @@ -14,8 +14,9 @@ use dioxus_native_core::{ state::NodeDepState, }; -#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)] pub(crate) enum FocusLevel { + #[default] Unfocusable, Focusable, Ordered(std::num::NonZeroU16), @@ -53,12 +54,6 @@ impl Ord for FocusLevel { } } -impl Default for FocusLevel { - fn default() -> Self { - FocusLevel::Unfocusable - } -} - #[derive(Clone, PartialEq, Debug, Default)] pub(crate) struct Focus { pub level: FocusLevel, diff --git a/packages/tui/src/node.rs b/packages/tui/src/node.rs index 26ea4412e..7ef7d9c9a 100644 --- a/packages/tui/src/node.rs +++ b/packages/tui/src/node.rs @@ -20,7 +20,7 @@ pub(crate) struct NodeState { pub focused: bool, } -#[derive(PartialEq, Debug, Clone)] +#[derive(PartialEq, Debug, Clone, Default)] pub(crate) enum PreventDefault { Focus, KeyPress, @@ -32,6 +32,7 @@ pub(crate) enum PreventDefault { MouseEnter, MouseLeave, MouseOut, + #[default] Unknown, MouseOver, ContextMenu, @@ -39,12 +40,6 @@ pub(crate) enum PreventDefault { MouseUp, } -impl Default for PreventDefault { - fn default() -> Self { - PreventDefault::Unknown - } -} - impl NodeDepState for PreventDefault { type DepState = (); type Ctx = (); From 2a648226156fcd53038389b6d4842763e39c5cf3 Mon Sep 17 00:00:00 2001 From: marcerhans <121002093+marcerhans@users.noreply.github.com> Date: Mon, 13 Mar 2023 14:12:41 +0100 Subject: [PATCH 07/10] Updated link in docs for use_hook. (#880) --- docs/guide/src/en/interactivity/custom_hooks.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/src/en/interactivity/custom_hooks.md b/docs/guide/src/en/interactivity/custom_hooks.md index 2f0155cb5..ebf4f94db 100644 --- a/docs/guide/src/en/interactivity/custom_hooks.md +++ b/docs/guide/src/en/interactivity/custom_hooks.md @@ -14,7 +14,7 @@ For example, if many components need to access an `AppSettings` struct, you can ## Custom Hook Logic -You can use [`cx.use_hook`](https://docs.rs/dioxus/latest/dioxus/prelude/struct.Scope.html#method.use_hook) to build your own hooks. In fact, this is what all the standard hooks are built on! +You can use [`cx.use_hook`](https://docs.rs/dioxus/latest/dioxus/prelude/struct.ScopeState.html#method.use_hook) to build your own hooks. In fact, this is what all the standard hooks are built on! `use_hook` accepts a single closure for initializing the hook. It will be only run the first time the component is rendered. The return value of that closure will be used as the value of the hook – Dioxus will take it, and store it for as long as the component is alive. On every render (not just the first one!), you will get a reference to this value. From 226bd3a6e186a225932add48d71609d666024de5 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 13 Mar 2023 15:50:05 -0500 Subject: [PATCH 08/10] fix panic when waking future on shutdown --- packages/core/src/scheduler/task.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/core/src/scheduler/task.rs b/packages/core/src/scheduler/task.rs index 997953f8e..fc668b364 100644 --- a/packages/core/src/scheduler/task.rs +++ b/packages/core/src/scheduler/task.rs @@ -72,9 +72,9 @@ pub struct LocalTaskHandle { impl ArcWake for LocalTaskHandle { fn wake_by_ref(arc_self: &Arc) { - arc_self + // This can fail if the scheduler has been dropped while the application is shutting down + let _ = arc_self .tx - .unbounded_send(SchedulerMsg::TaskNotified(arc_self.id)) - .unwrap(); + .unbounded_send(SchedulerMsg::TaskNotified(arc_self.id)); } } From f0c9dadf7718a3258793d2e868bf198ee9700471 Mon Sep 17 00:00:00 2001 From: marcerhans <121002093+marcerhans@users.noreply.github.com> Date: Wed, 15 Mar 2023 15:08:29 +0100 Subject: [PATCH 09/10] Added mention of StreamExt trait extension. (#886) --- docs/guide/src/en/async/use_coroutine.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/guide/src/en/async/use_coroutine.md b/docs/guide/src/en/async/use_coroutine.md index 95c932901..537e27ea4 100644 --- a/docs/guide/src/en/async/use_coroutine.md +++ b/docs/guide/src/en/async/use_coroutine.md @@ -92,6 +92,8 @@ With Coroutines, we can centralize our async logic. The `rx` parameter is an Cha ```rust +use futures_util::stream::StreamExt; + enum ProfileUpdate { SetUsername(String), SetAge(i32) @@ -117,6 +119,10 @@ cx.render(rsx!{ }) ``` + +> Note: In order to use/run the `rx.next().await` statement you will need to extend the [`Stream`] trait (used by [`UnboundedReceiver`]) by adding 'futures_util' as a dependency to your project and adding the `use futures_util::stream::StreamExt;`. + + For sufficiently complex apps, we could build a bunch of different useful "services" that loop on channels to update the app. ```rust @@ -164,6 +170,8 @@ fn Banner(cx: Scope) -> Element { Now, in our sync service, we can structure our state however we want. We only need to update the view values when ready. ```rust +use futures_util::stream::StreamExt; + enum SyncAction { SetUsername(String), } From 46cc07e04827f8ea63bd210eaf6b72727441b6bf Mon Sep 17 00:00:00 2001 From: marcerhans <121002093+marcerhans@users.noreply.github.com> Date: Fri, 17 Mar 2023 13:15:18 +0100 Subject: [PATCH 10/10] Updated links in docs for custom use_hook. (#891) Found some more dead links. --- docs/guide/src/en/interactivity/custom_hooks.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/guide/src/en/interactivity/custom_hooks.md b/docs/guide/src/en/interactivity/custom_hooks.md index ebf4f94db..07472bb95 100644 --- a/docs/guide/src/en/interactivity/custom_hooks.md +++ b/docs/guide/src/en/interactivity/custom_hooks.md @@ -22,5 +22,5 @@ You can use [`cx.use_hook`](https://docs.rs/dioxus/latest/dioxus/prelude/struct. Inside the initialization closure, you will typically make calls to other `cx` methods. For example: -- The `use_state` hook tracks state in the hook value, and uses [`cx.schedule_update`](https://docs.rs/dioxus/latest/dioxus/prelude/struct.Scope.html#method.schedule_update) to make Dioxus re-render the component whenever it changes. -- The `use_context` hook calls [`cx.consume_context`](https://docs.rs/dioxus/latest/dioxus/prelude/struct.Scope.html#method.consume_context) (which would be expensive to call on every render) to get some context from the scope \ No newline at end of file +- The `use_state` hook tracks state in the hook value, and uses [`cx.schedule_update`](https://docs.rs/dioxus/latest/dioxus/prelude/struct.ScopeState.html#method.schedule_update) to make Dioxus re-render the component whenever it changes. +- The `use_context` hook calls [`cx.consume_context`](https://docs.rs/dioxus/latest/dioxus/prelude/struct.ScopeState.html#method.consume_context) (which would be expensive to call on every render) to get some context from the scope