From ab19ad462477867b42576cec585dfb6284c11fea Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Fri, 3 Oct 2025 21:43:47 +0100 Subject: [PATCH] native: open links in default webbrowser (#4623) --- Cargo.lock | 1 + Cargo.toml | 1 + packages/desktop/Cargo.toml | 2 +- packages/native/Cargo.toml | 1 + packages/native/src/lib.rs | 9 ++++++++- packages/native/src/link_handler.rs | 18 ++++++++++++++++++ 6 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 packages/native/src/link_handler.rs diff --git a/Cargo.lock b/Cargo.lock index 48c596cda..c4dcc2118 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5724,6 +5724,7 @@ dependencies = [ "rustc-hash 2.1.1", "tokio", "tracing", + "webbrowser", "winit", ] diff --git a/Cargo.toml b/Cargo.toml index 3a4f0c894..8434662d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -350,6 +350,7 @@ objc = { version = "0.2.7", features = ["exception"] } objc_id = "0.1.1" tray-icon = "0.21.0" open = "5.3.2" +webbrowser = "1.0" # web gloo-dialogs = "0.2.0" diff --git a/packages/desktop/Cargo.toml b/packages/desktop/Cargo.toml index c136dadc9..5d3bbb828 100644 --- a/packages/desktop/Cargo.toml +++ b/packages/desktop/Cargo.toml @@ -50,7 +50,7 @@ base64 = { workspace = true } libc = "0.2.174" rand = { workspace = true, features = ["std_rng"] } subtle = { version = "2.6", features = ["const-generics"] } -webbrowser = { version = "1.0" } +webbrowser = { workspace = true } [target.'cfg(unix)'.dependencies] signal-hook = "0.3.18" diff --git a/packages/native/Cargo.toml b/packages/native/Cargo.toml index eabc0ff82..90f0e8ed7 100644 --- a/packages/native/Cargo.toml +++ b/packages/native/Cargo.toml @@ -47,6 +47,7 @@ keyboard-types = { workspace = true } # IO & Networking tokio = { workspace = true, features = ["rt-multi-thread"], optional = true } +webbrowser = { workspace = true } # Other dependencies tracing = { workspace = true, optional = true } diff --git a/packages/native/src/lib.rs b/packages/native/src/lib.rs index 724fe95ef..a7638ea06 100644 --- a/packages/native/src/lib.rs +++ b/packages/native/src/lib.rs @@ -13,6 +13,7 @@ mod assets; mod contexts; mod dioxus_application; mod dioxus_renderer; +mod link_handler; #[doc(inline)] pub use dioxus_native_dom::*; @@ -26,7 +27,10 @@ pub use dioxus_renderer::{use_wgpu, DioxusNativeWindowRenderer, Features, Limits use blitz_shell::{create_default_event_loop, BlitzShellEvent, Config, WindowConfig}; use dioxus_core::{ComponentFunction, Element, VirtualDom}; +use link_handler::DioxusNativeNavigationProvider; use std::any::Any; +#[cfg(feature = "html")] +use std::sync::Arc; use winit::window::WindowAttributes; /// Launch an interactive HTML/CSS renderer driven by the Dioxus virtualdom @@ -125,16 +129,19 @@ pub fn launch_cfg_with_props( let net_provider = None; #[cfg(feature = "html")] - let html_parser_provider = Some(std::sync::Arc::new(blitz_html::HtmlProvider) as _); + let html_parser_provider = Some(Arc::new(blitz_html::HtmlProvider) as _); #[cfg(not(feature = "html"))] let html_parser_provider = None; + let navigation_provider = Some(Arc::new(DioxusNativeNavigationProvider) as _); + // Create document + window from the baked virtualdom let doc = DioxusDocument::new( vdom, DocumentConfig { net_provider, html_parser_provider, + navigation_provider, ..Default::default() }, ); diff --git a/packages/native/src/link_handler.rs b/packages/native/src/link_handler.rs new file mode 100644 index 000000000..01a938ff8 --- /dev/null +++ b/packages/native/src/link_handler.rs @@ -0,0 +1,18 @@ +use blitz_traits::{ + navigation::{NavigationOptions, NavigationProvider}, + net::Method, +}; + +pub(crate) struct DioxusNativeNavigationProvider; + +impl NavigationProvider for DioxusNativeNavigationProvider { + fn navigate_to(&self, options: NavigationOptions) { + if options.method == Method::GET + && matches!(options.url.scheme(), "http" | "https" | "mailto") + { + if let Err(err) = webbrowser::open(options.url.as_str()) { + tracing::error!("Failed to open URL: {}", err); + } + } + } +}