From 5f0dd3af3eedfdc75db31ba113cf5cc91131a174 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Tue, 25 Jul 2023 18:14:48 -0700 Subject: [PATCH 1/6] it almost lives? --- docs/guide/src/en/interactivity/router.md | 6 +- docs/guide/src/pt-br/interactivity/router.md | 6 +- docs/posts/release-0-2-0.md | 2 +- docs/router/examples/catch_all.rs | 2 +- docs/router/examples/dynamic_route.rs | 6 +- docs/router/examples/external_link.rs | 2 +- docs/router/examples/first_route.rs | 2 +- docs/router/examples/full_example.rs | 6 +- docs/router/examples/history_provider.rs | 2 +- docs/router/examples/links.rs | 4 +- docs/router/examples/navigator.rs | 2 +- docs/router/examples/nested_routes.rs | 4 +- docs/router/examples/outlet.rs | 4 +- docs/router/examples/router_cfg.rs | 2 +- docs/router/examples/routing_update.rs | 2 +- examples/crm.rs | 2 +- examples/flat_router.rs | 4 +- examples/link.rs | 4 +- examples/router.rs | 6 +- examples/simple_desktop.rs | 4 +- packages/fullstack/src/router.rs | 6 +- packages/router-macro/src/lib.rs | 33 --- packages/router/README.md | 4 +- packages/router/benches/incremental.rs | 2 +- packages/router/examples/simple_routes.rs | 6 +- .../router/src/components/default_errors.rs | 6 +- .../router/src/components/history_buttons.rs | 34 ++- packages/router/src/components/link.rs | 100 +++++++-- packages/router/src/components/outlet.rs | 12 +- packages/router/src/components/router.rs | 38 ++-- packages/router/src/contexts/navigator.rs | 10 +- packages/router/src/contexts/outlet.rs | 4 +- packages/router/src/contexts/router.rs | 203 ++++++++++++++---- packages/router/src/history/mod.rs | 142 +++++++++++- packages/router/src/hooks/use_navigator.rs | 11 +- packages/router/src/hooks/use_route.rs | 8 +- packages/router/src/hooks/use_router.rs | 7 +- packages/router/src/incremental.rs | 2 +- packages/router/src/navigation.rs | 2 +- packages/router/src/router_cfg.rs | 20 +- .../router/src/utils/use_router_internal.rs | 16 +- packages/router/tests/via_ssr/link.rs | 6 +- packages/router/tests/via_ssr/outlet.rs | 6 +- 43 files changed, 506 insertions(+), 244 deletions(-) diff --git a/docs/guide/src/en/interactivity/router.md b/docs/guide/src/en/interactivity/router.md index c5f8c7c36..b4f20eb78 100644 --- a/docs/guide/src/en/interactivity/router.md +++ b/docs/guide/src/en/interactivity/router.md @@ -26,7 +26,7 @@ Unlike other routers in the Rust ecosystem, our router is built declaratively. T ```rust, no_run rsx!{ // All of our routes will be rendered inside this Router component - Router { + Router:: { // if the current location is "/home", render the Home component Route { to: "/home", Home {} } // if the current location is "/blog", render the Blog component @@ -43,7 +43,7 @@ We can fix this one of two ways: ```rust, no_run rsx!{ - Router { + Router:: { Route { to: "/home", Home {} } Route { to: "/blog", Blog {} } // if the current location doesn't match any of the above routes, render the NotFound component @@ -56,7 +56,7 @@ rsx!{ ```rust, no_run rsx!{ - Router { + Router:: { Route { to: "/home", Home {} } Route { to: "/blog", Blog {} } // if the current location doesn't match any of the above routes, redirect to "/home" diff --git a/docs/guide/src/pt-br/interactivity/router.md b/docs/guide/src/pt-br/interactivity/router.md index 398546c0c..282508df9 100644 --- a/docs/guide/src/pt-br/interactivity/router.md +++ b/docs/guide/src/pt-br/interactivity/router.md @@ -28,7 +28,7 @@ Ao contrário de outros roteadores no ecossistema Rust, nosso roteador é constr ```rust, no_run rsx!{ - Router { + Router:: { Route { to: "/home", Home {} } Route { to: "/blog", Blog {} } } @@ -43,7 +43,7 @@ Podemos corrigir isso de duas maneiras: ```rust, no_run rsx!{ - Router { + Router:: { Route { to: "/home", Home {} } Route { to: "/blog", Blog {} } Route { to: "", NotFound {} } @@ -55,7 +55,7 @@ rsx!{ ```rust, no_run rsx!{ - Router { + Router:: { Route { to: "/home", Home {} } Route { to: "/blog", Blog {} } Redirect { from: "", to: "/home" } diff --git a/docs/posts/release-0-2-0.md b/docs/posts/release-0-2-0.md index 7901ee8b0..82d87a730 100644 --- a/docs/posts/release-0-2-0.md +++ b/docs/posts/release-0-2-0.md @@ -72,7 +72,7 @@ Apps with routers are _really_ simple now. It's easy to compose the "Router", a ```rust, no_run fn app(cx: Scope) -> Element { cx.render(rsx! { - Router { + Router:: { onchange: move |_| log::info!("Route changed!"), ul { Link { to: "/", li { "Go home!" } } diff --git a/docs/router/examples/catch_all.rs b/docs/router/examples/catch_all.rs index 38dfa11f1..0e989b7a6 100644 --- a/docs/router/examples/catch_all.rs +++ b/docs/router/examples/catch_all.rs @@ -17,7 +17,7 @@ enum Route { #[inline_props] fn App(cx: Scope) -> Element { render! { - Router {} + Router:: {} } } // ANCHOR_END: app diff --git a/docs/router/examples/dynamic_route.rs b/docs/router/examples/dynamic_route.rs index 0f0ace6a9..f8a103e7c 100644 --- a/docs/router/examples/dynamic_route.rs +++ b/docs/router/examples/dynamic_route.rs @@ -35,7 +35,7 @@ enum Route { fn App(cx: Scope) -> Element { render! { - Router {} + Router:: {} } } @@ -48,7 +48,7 @@ fn NavBar(cx: Scope) -> Element { li { Link { to: Route::BlogList {}, "Blog" } } } } - Outlet {} + Outlet:: {} } } @@ -64,7 +64,7 @@ fn Home(cx: Scope) -> Element { fn Blog(cx: Scope) -> Element { render! { h1 { "Blog" } - Outlet {} + Outlet:: {} } } // ANCHOR_END: blog diff --git a/docs/router/examples/external_link.rs b/docs/router/examples/external_link.rs index a36f41f76..ed855e2d3 100644 --- a/docs/router/examples/external_link.rs +++ b/docs/router/examples/external_link.rs @@ -20,7 +20,7 @@ fn main() {} fn GoToDioxus(cx: Scope) -> Element { render! { Link { - to: NavigationTarget::External("https://dioxuslabs.com".into()), + to: "https://dioxuslabs.com", "ExternalTarget target" } } diff --git a/docs/router/examples/first_route.rs b/docs/router/examples/first_route.rs index d13bef93d..5afa513f9 100644 --- a/docs/router/examples/first_route.rs +++ b/docs/router/examples/first_route.rs @@ -19,7 +19,7 @@ enum Route { #[inline_props] fn App(cx: Scope) -> Element { render! { - Router {} + Router:: {} } } // ANCHOR_END: app diff --git a/docs/router/examples/full_example.rs b/docs/router/examples/full_example.rs index 1a561292e..11465c38f 100644 --- a/docs/router/examples/full_example.rs +++ b/docs/router/examples/full_example.rs @@ -39,7 +39,7 @@ enum Route { fn App(cx: Scope) -> Element { render! { - Router {} + Router:: {} } } @@ -52,7 +52,7 @@ fn NavBar(cx: Scope) -> Element { li { Link { to: Route::BlogList {}, "Blog" } } } } - Outlet {} + Outlet:: {} } } @@ -67,7 +67,7 @@ fn Home(cx: Scope) -> Element { fn Blog(cx: Scope) -> Element { render! { h1 { "Blog" } - Outlet {} + Outlet:: {} } } diff --git a/docs/router/examples/history_provider.rs b/docs/router/examples/history_provider.rs index 090019ad0..57ec27732 100644 --- a/docs/router/examples/history_provider.rs +++ b/docs/router/examples/history_provider.rs @@ -12,7 +12,7 @@ enum Route { #[inline_props] fn App(cx: Scope) -> Element { render! { - Router { + Router:: { config: || RouterConfig::default().history(WebHistory::default()) } } diff --git a/docs/router/examples/links.rs b/docs/router/examples/links.rs index cf9c41930..356e9c0a7 100644 --- a/docs/router/examples/links.rs +++ b/docs/router/examples/links.rs @@ -32,7 +32,7 @@ fn NavBar(cx: Scope) -> Element { } } } - Outlet {} + Outlet:: {} } } // ANCHOR_END: nav @@ -41,7 +41,7 @@ fn NavBar(cx: Scope) -> Element { #[inline_props] fn App(cx: Scope) -> Element { render! { - Router {} + Router:: {} } } // ANCHOR_END: app diff --git a/docs/router/examples/navigator.rs b/docs/router/examples/navigator.rs index 4c6249366..9f32b7c12 100644 --- a/docs/router/examples/navigator.rs +++ b/docs/router/examples/navigator.rs @@ -14,7 +14,7 @@ enum Route { #[inline_props] fn App(cx: Scope) -> Element { render! { - Router {} + Router:: {} } } diff --git a/docs/router/examples/nested_routes.rs b/docs/router/examples/nested_routes.rs index 7462d8e74..63e080016 100644 --- a/docs/router/examples/nested_routes.rs +++ b/docs/router/examples/nested_routes.rs @@ -26,7 +26,7 @@ fn NavBar(cx: Scope) -> Element { } } // The Outlet component will render child routes (In this case just the Home component) inside the Outlet component - Outlet {} + Outlet:: {} } } // ANCHOR_END: nav @@ -35,7 +35,7 @@ fn NavBar(cx: Scope) -> Element { #[inline_props] fn App(cx: Scope) -> Element { render! { - Router {} + Router:: {} } } // ANCHOR_END: app diff --git a/docs/router/examples/outlet.rs b/docs/router/examples/outlet.rs index b28a61f66..5c7ee8dbf 100644 --- a/docs/router/examples/outlet.rs +++ b/docs/router/examples/outlet.rs @@ -16,7 +16,7 @@ fn Wrapper(cx: Scope) -> Element { render! { header { "header" } // The index route will be rendered here - Outlet { } + Outlet:: { } footer { "footer" } } } @@ -31,7 +31,7 @@ fn Index(cx: Scope) -> Element { fn App(cx: Scope) -> Element { render! { - Router {} + Router:: {} } } diff --git a/docs/router/examples/router_cfg.rs b/docs/router/examples/router_cfg.rs index 9b29af75c..5fd0402af 100644 --- a/docs/router/examples/router_cfg.rs +++ b/docs/router/examples/router_cfg.rs @@ -18,7 +18,7 @@ enum Route { #[inline_props] fn App(cx: Scope) -> Element { render! { - Router { + Router:: { config: || RouterConfig::default().history(WebHistory::default()) } } diff --git a/docs/router/examples/routing_update.rs b/docs/router/examples/routing_update.rs index 35097dbaf..a7f83d633 100644 --- a/docs/router/examples/routing_update.rs +++ b/docs/router/examples/routing_update.rs @@ -27,7 +27,7 @@ fn Index(cx: Scope) -> Element { fn app(cx: Scope) -> Element { render! { - Router { + Router:: { config: || RouterConfig::default().on_update(|state|{ (state.current() == Route::Index {}).then_some( NavigationTarget::Internal(Route::Home {}) diff --git a/examples/crm.rs b/examples/crm.rs index 5c89448bc..f3da8ab7a 100644 --- a/examples/crm.rs +++ b/examples/crm.rs @@ -46,7 +46,7 @@ fn App(cx: Scope) -> Element { h1 { "Dioxus CRM Example" } - Router {} + Router:: {} } } diff --git a/examples/flat_router.rs b/examples/flat_router.rs index 7163ab160..b8e3d6425 100644 --- a/examples/flat_router.rs +++ b/examples/flat_router.rs @@ -18,7 +18,7 @@ fn main() { fn app(cx: Scope) -> Element { render! { - Router {} + Router:: {} } } @@ -40,7 +40,7 @@ enum Route { fn Footer(cx: Scope) -> Element { render! { div { - Outlet { } + Outlet:: { } p { "----" diff --git a/examples/link.rs b/examples/link.rs index 01bd38a5b..c66b1abd1 100644 --- a/examples/link.rs +++ b/examples/link.rs @@ -23,7 +23,7 @@ fn app(cx: Scope) -> Element { } } div { - Router {} + Router:: {} } )) } @@ -46,7 +46,7 @@ fn Header(cx: Scope) -> Element { li { Link { to: Route::Home {}, "home" } } li { Link { to: Route::Settings {}, "settings" } } } - Outlet {} + Outlet:: {} } } diff --git a/examples/router.rs b/examples/router.rs index 1a561292e..11465c38f 100644 --- a/examples/router.rs +++ b/examples/router.rs @@ -39,7 +39,7 @@ enum Route { fn App(cx: Scope) -> Element { render! { - Router {} + Router:: {} } } @@ -52,7 +52,7 @@ fn NavBar(cx: Scope) -> Element { li { Link { to: Route::BlogList {}, "Blog" } } } } - Outlet {} + Outlet:: {} } } @@ -67,7 +67,7 @@ fn Home(cx: Scope) -> Element { fn Blog(cx: Scope) -> Element { render! { h1 { "Blog" } - Outlet {} + Outlet:: {} } } diff --git a/examples/simple_desktop.rs b/examples/simple_desktop.rs index 08d402e39..374b58a4e 100644 --- a/examples/simple_desktop.rs +++ b/examples/simple_desktop.rs @@ -14,7 +14,7 @@ fn main() { fn app(cx: Scope) -> Element { render! { - Router {} + Router:: {} } } @@ -47,7 +47,7 @@ fn NavBar(cx: Scope) -> Element { li { Link { to: Route::BlogPost { post: "bill".into() }, "bills' blog" } } li { Link { to: Route::BlogPost { post: "james".into() }, "james amazing' blog" } } } - Outlet {} + Outlet:: {} } } diff --git a/packages/fullstack/src/router.rs b/packages/fullstack/src/router.rs index 97bcdf5d1..8eb7ef536 100644 --- a/packages/fullstack/src/router.rs +++ b/packages/fullstack/src/router.rs @@ -16,7 +16,7 @@ where let cfg = *cx.props; render! { - dioxus_router::prelude::GenericRouter:: { + dioxus_router::prelude::Router:: { config: move || { RouterConfig::default() .failure_external_navigation(cfg.failure_external_navigation) @@ -54,7 +54,7 @@ where R: dioxus_router::prelude::Routable, ::Err: std::fmt::Display, { - dioxus_router::prelude::FailureExternalNavigation:: + dioxus_router::prelude::FailureExternalNavigation } /// The configeration for the router @@ -96,7 +96,7 @@ where { fn default() -> Self { Self { - failure_external_navigation: dioxus_router::prelude::FailureExternalNavigation::, + failure_external_navigation: dioxus_router::prelude::FailureExternalNavigation, scroll_restoration: true, phantom: std::marker::PhantomData, } diff --git a/packages/router-macro/src/lib.rs b/packages/router-macro/src/lib.rs index 708aa6891..771c9640f 100644 --- a/packages/router-macro/src/lib.rs +++ b/packages/router-macro/src/lib.rs @@ -211,38 +211,8 @@ pub fn routable(input: TokenStream) -> TokenStream { let parse_impl = route_enum.parse_impl(); let display_impl = route_enum.impl_display(); let routable_impl = route_enum.routable_impl(); - let name = &route_enum.name; - let vis = &route_enum.vis; quote! { - #vis fn Outlet(cx: dioxus::prelude::Scope) -> dioxus::prelude::Element { - dioxus_router::prelude::GenericOutlet::<#name>(cx) - } - - #vis fn Router(cx: dioxus::prelude::Scope>) -> dioxus::prelude::Element { - dioxus_router::prelude::GenericRouter(cx) - } - - #vis fn Link<'a>(cx: dioxus::prelude::Scope<'a, dioxus_router::prelude::GenericLinkProps<'a, #name>>) -> dioxus::prelude::Element<'a> { - dioxus_router::prelude::GenericLink(cx) - } - - #vis fn GoBackButton<'a>(cx: dioxus::prelude::Scope<'a, dioxus_router::prelude::GenericHistoryButtonProps<'a>>) -> dioxus::prelude::Element<'a> { - dioxus_router::prelude::GenericGoBackButton::<#name>(cx) - } - - #vis fn GoForwardButton<'a>(cx: dioxus::prelude::Scope<'a, dioxus_router::prelude::GenericHistoryButtonProps<'a>>) -> dioxus::prelude::Element<'a> { - dioxus_router::prelude::GenericGoForwardButton::<#name>(cx) - } - - #vis fn use_route(cx: &dioxus::prelude::ScopeState) -> Option<#name> { - dioxus_router::prelude::use_generic_route(cx) - } - - #vis fn use_navigator(cx: &dioxus::prelude::ScopeState) -> &dioxus_router::prelude::GenericNavigator<#name> { - dioxus_router::prelude::use_generic_navigator(cx) - } - #error_type #display_impl @@ -255,7 +225,6 @@ pub fn routable(input: TokenStream) -> TokenStream { } struct RouteEnum { - vis: syn::Visibility, name: Ident, redirects: Vec, routes: Vec, @@ -267,7 +236,6 @@ struct RouteEnum { impl RouteEnum { fn parse(data: syn::ItemEnum) -> syn::Result { let name = &data.ident; - let vis = &data.vis; let mut site_map = Vec::new(); let mut site_map_stack: Vec> = Vec::new(); @@ -457,7 +425,6 @@ impl RouteEnum { } let myself = Self { - vis: vis.clone(), name: name.clone(), routes, redirects, diff --git a/packages/router/README.md b/packages/router/README.md index 88f0fde5b..db6cfdf4f 100644 --- a/packages/router/README.md +++ b/packages/router/README.md @@ -51,7 +51,7 @@ enum Route { fn App(cx: Scope) -> Element { render! { - Router { } + Router:: { } } } @@ -70,7 +70,7 @@ fn Index(cx: Scope) -> Element { fn Blog(cx: Scope) -> Element { render! { h1 { "Blog" } - Outlet { } + Outlet:: { } } } diff --git a/packages/router/benches/incremental.rs b/packages/router/benches/incremental.rs index 0694e3636..0c2697a80 100644 --- a/packages/router/benches/incremental.rs +++ b/packages/router/benches/incremental.rs @@ -193,7 +193,7 @@ enum Route { fn RenderPath(cx: Scope, path: Route) -> Element { let path = path.clone(); render! { - Router { + Router:: { config: || RouterConfig::default().history(MemoryHistory::with_initial_path(path)) } } diff --git a/packages/router/examples/simple_routes.rs b/packages/router/examples/simple_routes.rs index acb5bffce..ac408bb72 100644 --- a/packages/router/examples/simple_routes.rs +++ b/packages/router/examples/simple_routes.rs @@ -14,7 +14,7 @@ fn main() { fn root(cx: Scope) -> Element { render! { - Router {} + Router:: {} } } @@ -27,7 +27,7 @@ fn UserFrame(cx: Scope, user_id: usize) -> Element { div { background_color: "rgba(0,0,0,50%)", "children:" - Outlet {} + Outlet:: {} } } } @@ -90,7 +90,7 @@ fn Route3(cx: Scope, dynamic: String) -> Element { "hello world link" } button { - onclick: move |_| { navigator.push(NavigationTarget::External("https://www.google.com".to_string())); }, + onclick: move |_| { navigator.push(NavigationTarget::::External("https://www.google.com".to_string())); }, "google link" } p { "Site Map" } diff --git a/packages/router/src/components/default_errors.rs b/packages/router/src/components/default_errors.rs index 16a680803..704c6b972 100644 --- a/packages/router/src/components/default_errors.rs +++ b/packages/router/src/components/default_errors.rs @@ -1,10 +1,10 @@ -use crate::{hooks::use_generic_router, routable::Routable}; +use crate::hooks::use_router; use dioxus::prelude::*; /// The default component to render when an external navigation fails. #[allow(non_snake_case)] -pub fn FailureExternalNavigation(cx: Scope) -> Element { - let router = use_generic_router::(cx); +pub fn FailureExternalNavigation(cx: Scope) -> Element { + let router = use_router(cx); render! { h1 { "External Navigation Failure!" } diff --git a/packages/router/src/components/history_buttons.rs b/packages/router/src/components/history_buttons.rs index a09bc66b6..6bd23d860 100644 --- a/packages/router/src/components/history_buttons.rs +++ b/packages/router/src/components/history_buttons.rs @@ -1,23 +1,23 @@ use dioxus::prelude::*; use log::error; -use crate::{prelude::*, utils::use_router_internal::use_router_internal}; +use crate::utils::use_router_internal::use_router_internal; -/// The properties for a [`GenericGoBackButton`] or a [`GenericGoForwardButton`]. +/// The properties for a [`GoBackButton`] or a [`GoForwardButton`]. #[derive(Debug, Props)] -pub struct GenericHistoryButtonProps<'a> { +pub struct HistoryButtonProps<'a> { /// The children to render within the generated HTML button tag. pub children: Element<'a>, } /// A button to go back through the navigation history. Similar to a browsers back button. /// -/// Only works as descendant of a [`GenericRouter`] component, otherwise it will be inactive. +/// Only works as descendant of a [`Link`] component, otherwise it will be inactive. /// /// The button will disable itself if it is known that no prior history is available. /// /// # Panic -/// - When the [`GenericGoBackButton`] is not nested within a [`GenericRouter`] component +/// - When the [`GoBackButton`] is not nested within a [`Link`] component /// hook, but only in debug builds. /// /// # Example @@ -32,7 +32,7 @@ pub struct GenericHistoryButtonProps<'a> { /// /// fn App(cx: Scope) -> Element { /// render! { -/// Router {} +/// Router:: {} /// } /// } /// @@ -53,13 +53,11 @@ pub struct GenericHistoryButtonProps<'a> { /// # ); /// ``` #[allow(non_snake_case)] -pub fn GenericGoBackButton<'a, R: Routable>( - cx: Scope<'a, GenericHistoryButtonProps<'a>>, -) -> Element { - let GenericHistoryButtonProps { children } = cx.props; +pub fn GoBackButton<'a>(cx: Scope<'a, HistoryButtonProps<'a>>) -> Element { + let HistoryButtonProps { children } = cx.props; // hook up to router - let router = match use_router_internal::(cx) { + let router = match use_router_internal(cx) { Some(r) => r, #[allow(unreachable_code)] None => { @@ -85,12 +83,12 @@ pub fn GenericGoBackButton<'a, R: Routable>( /// A button to go forward through the navigation history. Similar to a browsers forward button. /// -/// Only works as descendant of a [`GenericRouter`] component, otherwise it will be inactive. +/// Only works as descendant of a [`Link`] component, otherwise it will be inactive. /// /// The button will disable itself if it is known that no later history is available. /// /// # Panic -/// - When the [`GenericGoForwardButton`] is not nested within a [`GenericRouter`] component +/// - When the [`GoForwardButton`] is not nested within a [`Link`] component /// hook, but only in debug builds. /// /// # Example @@ -105,7 +103,7 @@ pub fn GenericGoBackButton<'a, R: Routable>( /// /// fn App(cx: Scope) -> Element { /// render! { -/// Router {} +/// Router:: {} /// } /// } /// @@ -126,13 +124,11 @@ pub fn GenericGoBackButton<'a, R: Routable>( /// # ); /// ``` #[allow(non_snake_case)] -pub fn GenericGoForwardButton<'a, R: Routable>( - cx: Scope<'a, GenericHistoryButtonProps<'a>>, -) -> Element { - let GenericHistoryButtonProps { children } = cx.props; +pub fn GoForwardButton<'a>(cx: Scope<'a, HistoryButtonProps<'a>>) -> Element { + let HistoryButtonProps { children } = cx.props; // hook up to router - let router = match use_router_internal::(cx) { + let router = match use_router_internal(cx) { Some(r) => r, #[allow(unreachable_code)] None => { diff --git a/packages/router/src/components/link.rs b/packages/router/src/components/link.rs index 00d5ee551..efed7fb5f 100644 --- a/packages/router/src/components/link.rs +++ b/packages/router/src/components/link.rs @@ -1,15 +1,57 @@ +use std::any::Any; use std::fmt::Debug; use dioxus::prelude::*; use log::error; use crate::navigation::NavigationTarget; -use crate::prelude::*; +use crate::prelude::{AnyDisplay, Routable}; use crate::utils::use_router_internal::use_router_internal; -/// The properties for a [`GenericLink`]. +/// Something that can be converted into a [`NavigationTarget`]. +pub enum IntoRoutable { + /// A raw string target. + FromStr(String), + /// A internal target. + Route(Box), +} + +impl From for IntoRoutable { + fn from(value: R) -> Self { + IntoRoutable::Route(Box::new(value)) + } +} + +impl From> for IntoRoutable { + fn from(value: NavigationTarget) -> Self { + match value { + NavigationTarget::Internal(route) => IntoRoutable::Route(Box::new(route)), + NavigationTarget::External(url) => IntoRoutable::FromStr(url), + } + } +} + +impl From for IntoRoutable { + fn from(value: String) -> Self { + IntoRoutable::FromStr(value) + } +} + +impl From<&String> for IntoRoutable { + fn from(value: &String) -> Self { + IntoRoutable::FromStr(value.to_string()) + } +} + +impl From<&str> for IntoRoutable { + fn from(value: &str) -> Self { + IntoRoutable::FromStr(value.to_string()) + } +} + +/// The properties for a [`Link`]. #[derive(Props)] -pub struct GenericLinkProps<'a, R: Routable> { +pub struct LinkProps<'a> { /// A class to apply to the generate HTML anchor tag if the `target` route is active. pub active_class: Option<&'a str>, /// The children to render within the generated HTML anchor tag. @@ -23,7 +65,7 @@ pub struct GenericLinkProps<'a, R: Routable> { pub id: Option<&'a str>, /// When [`true`], the `target` route will be opened in a new tab. /// - /// This does not change whether the [`GenericLink`] is active or not. + /// This does not change whether the [`Link`] is active or not. #[props(default)] pub new_tab: bool, /// The onclick event handler. @@ -42,10 +84,10 @@ pub struct GenericLinkProps<'a, R: Routable> { pub rel: Option<&'a str>, /// The navigation target. Roughly equivalent to the href attribute of an HTML anchor tag. #[props(into)] - pub to: NavigationTarget, + pub to: IntoRoutable, } -impl Debug for GenericLinkProps<'_, R> { +impl Debug for LinkProps<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("LinkProps") .field("active_class", &self.active_class) @@ -56,27 +98,26 @@ impl Debug for GenericLinkProps<'_, R> { .field("onclick", &self.onclick.as_ref().map(|_| "onclick is set")) .field("onclick_only", &self.onclick_only) .field("rel", &self.rel) - .field("to", &self.to.to_string()) .finish() } } /// A link to navigate to another route. /// -/// Only works as descendant of a [`GenericRouter`] component, otherwise it will be inactive. +/// Only works as descendant of a [`Router`] component, otherwise it will be inactive. /// -/// Unlike a regular HTML anchor, a [`GenericLink`] allows the router to handle the navigation and doesn't +/// Unlike a regular HTML anchor, a [`Link`] allows the router to handle the navigation and doesn't /// cause the browser to load a new page. /// -/// However, in the background a [`GenericLink`] still generates an anchor, which you can use for styling +/// However, in the background a [`Link`] still generates an anchor, which you can use for styling /// as normal. /// /// # External targets -/// When the [`GenericLink`]s target is an [`NavigationTarget::External`] target, that is used as the `href` directly. This -/// means that a [`GenericLink`] can always navigate to an [`NavigationTarget::External`] target, even if the [`HistoryProvider`] does not support it. +/// When the [`Link`]s target is an [`NavigationTarget::External`] target, that is used as the `href` directly. This +/// means that a [`Link`] can always navigate to an [`NavigationTarget::External`] target, even if the [`HistoryProvider`] does not support it. /// /// # Panic -/// - When the [`GenericLink`] is not nested within a [`GenericRouter`], but +/// - When the [`Link`] is not nested within a [`Router`], but /// only in debug builds. /// /// # Example @@ -92,7 +133,7 @@ impl Debug for GenericLinkProps<'_, R> { /// /// fn App(cx: Scope) -> Element { /// render! { -/// Router {} +/// Router:: {} /// } /// } /// @@ -122,8 +163,8 @@ impl Debug for GenericLinkProps<'_, R> { /// # ); /// ``` #[allow(non_snake_case)] -pub fn GenericLink<'a, R: Routable + Clone>(cx: Scope<'a, GenericLinkProps<'a, R>>) -> Element { - let GenericLinkProps { +pub fn Link<'a>(cx: Scope<'a, LinkProps<'a>>) -> Element { + let LinkProps { active_class, children, class, @@ -133,10 +174,11 @@ pub fn GenericLink<'a, R: Routable + Clone>(cx: Scope<'a, GenericLinkProps<'a, R onclick_only, rel, to, + .. } = cx.props; // hook up to router - let router = match use_router_internal::(cx) { + let router = match use_router_internal(cx) { Some(r) => r, #[allow(unreachable_code)] None => { @@ -148,9 +190,15 @@ pub fn GenericLink<'a, R: Routable + Clone>(cx: Scope<'a, GenericLinkProps<'a, R } }; - let current_route = router.current(); - let current_url = current_route.to_string(); - let href = to.to_string(); + let current_url = router.current_route_string(); + let href = match to { + IntoRoutable::FromStr(url) => url.to_string(), + IntoRoutable::Route(route) => route.to_string(), + }; + let parsed_route: NavigationTarget> = match router.route_from_str(&href) { + Ok(route) => NavigationTarget::Internal(route.into()), + Err(err) => NavigationTarget::External(err), + }; let ac = active_class .and_then(|active_class| (href == current_url).then(|| format!(" {active_class}"))) .unwrap_or_default(); @@ -159,7 +207,7 @@ pub fn GenericLink<'a, R: Routable + Clone>(cx: Scope<'a, GenericLinkProps<'a, R let class = format!("{}{ac}", class.unwrap_or_default()); let tag_target = new_tab.then_some("_blank").unwrap_or_default(); - let is_external = matches!(to, NavigationTarget::External(_)); + let is_external = matches!(parsed_route, NavigationTarget::External(_)); let is_router_nav = !is_external && !new_tab; let prevent_default = is_router_nav.then_some("onclick").unwrap_or_default(); let rel = rel @@ -169,7 +217,15 @@ pub fn GenericLink<'a, R: Routable + Clone>(cx: Scope<'a, GenericLinkProps<'a, R let do_default = onclick.is_none() || !onclick_only; let action = move |event| { if do_default && is_router_nav { - router.push(to.clone()); + let href = match to { + IntoRoutable::FromStr(url) => url.to_string(), + IntoRoutable::Route(route) => route.to_string(), + }; + let parsed_route: NavigationTarget> = match router.route_from_str(&href) { + Ok(route) => NavigationTarget::Internal(route.into()), + Err(err) => NavigationTarget::External(err), + }; + router.push_any(parsed_route); } if let Some(handler) = onclick { diff --git a/packages/router/src/components/outlet.rs b/packages/router/src/components/outlet.rs index da312402e..133a23543 100644 --- a/packages/router/src/components/outlet.rs +++ b/packages/router/src/components/outlet.rs @@ -3,13 +3,13 @@ use dioxus::prelude::*; /// An outlet for the current content. /// -/// Only works as descendant of a [`GenericRouter`] component, otherwise it will be inactive. +/// Only works as descendant of a [`Link`] component, otherwise it will be inactive. /// -/// The [`GenericOutlet`] is aware of how many [`GenericOutlet`]s it is nested within. It will render the content +/// The [`Outlet`] is aware of how many [`Outlet`]s it is nested within. It will render the content /// of the active route that is __exactly as deep__. /// /// # Panic -/// - When the [`GenericOutlet`] is not nested a [`GenericRouter`] component, +/// - When the [`Outlet`] is not nested a [`Link`] component, /// but only in debug builds. /// /// # Example @@ -42,7 +42,7 @@ use dioxus::prelude::*; /// fn Wrapper(cx: Scope) -> Element { /// render! { /// h1 { "App" } -/// Outlet {} // The content of child routes will be rendered here +/// Outlet:: {} // The content of child routes will be rendered here /// } /// } /// @@ -57,7 +57,7 @@ use dioxus::prelude::*; /// /// # fn App(cx: Scope) -> Element { /// # render! { -/// # Router { +/// # Router:: { /// # config: || RouterConfig::default().history(MemoryHistory::with_initial_path(Route::Child {})) /// # } /// # } @@ -67,6 +67,6 @@ use dioxus::prelude::*; /// # let _ = vdom.rebuild(); /// # assert_eq!(dioxus_ssr::render(&vdom), "

App

Child

"); /// ``` -pub fn GenericOutlet(cx: Scope) -> Element { +pub fn Outlet(cx: Scope) -> Element { OutletContext::::render(cx) } diff --git a/packages/router/src/components/router.rs b/packages/router/src/components/router.rs index 7c82cf19b..dae4e3e66 100644 --- a/packages/router/src/components/router.rs +++ b/packages/router/src/components/router.rs @@ -1,13 +1,9 @@ use dioxus::prelude::*; use std::{cell::RefCell, str::FromStr}; -use crate::{ - prelude::{GenericOutlet, GenericRouterContext}, - routable::Routable, - router_cfg::RouterConfig, -}; +use crate::{prelude::Outlet, routable::Routable, router_cfg::RouterConfig}; -/// The config for [`GenericRouter`]. +/// The config for [`Router`]. pub struct RouterConfigFactory { #[allow(clippy::type_complexity)] config: RefCell RouterConfig>>>, @@ -43,9 +39,9 @@ impl RouterConfig + 'static> From for RouterCo } #[cfg(feature = "serde")] -/// The props for [`GenericRouter`]. +/// The props for [`Router`]. #[derive(Props)] -pub struct GenericRouterProps +pub struct RouterProps where ::Err: std::fmt::Display, R: serde::Serialize + serde::de::DeserializeOwned, @@ -55,9 +51,9 @@ where } #[cfg(not(feature = "serde"))] -/// The props for [`GenericRouter`]. +/// The props for [`Router`]. #[derive(Props)] -pub struct GenericRouterProps +pub struct RouterProps where ::Err: std::fmt::Display, { @@ -66,7 +62,7 @@ where } #[cfg(not(feature = "serde"))] -impl Default for GenericRouterProps +impl Default for RouterProps where ::Err: std::fmt::Display, { @@ -78,7 +74,7 @@ where } #[cfg(feature = "serde")] -impl Default for GenericRouterProps +impl Default for RouterProps where ::Err: std::fmt::Display, R: serde::Serialize + serde::de::DeserializeOwned, @@ -91,7 +87,7 @@ where } #[cfg(not(feature = "serde"))] -impl PartialEq for GenericRouterProps +impl PartialEq for RouterProps where ::Err: std::fmt::Display, { @@ -102,7 +98,7 @@ where } #[cfg(feature = "serde")] -impl PartialEq for GenericRouterProps +impl PartialEq for RouterProps where ::Err: std::fmt::Display, R: serde::Serialize + serde::de::DeserializeOwned, @@ -115,14 +111,14 @@ where #[cfg(not(feature = "serde"))] /// A component that renders the current route. -pub fn GenericRouter(cx: Scope>) -> Element +pub fn Router(cx: Scope>) -> Element where ::Err: std::fmt::Display, { - use crate::prelude::outlet::OutletContext; + use crate::prelude::{outlet::OutletContext, RouterContext}; use_context_provider(cx, || { - GenericRouterContext::new( + RouterContext::new( (cx.props .config .config @@ -137,19 +133,19 @@ where }); render! { - GenericOutlet:: {} + Outlet:: {} } } #[cfg(feature = "serde")] /// A component that renders the current route. -pub fn GenericRouter(cx: Scope>) -> Element +pub fn Router(cx: Scope>) -> Element where ::Err: std::fmt::Display, R: serde::Serialize + serde::de::DeserializeOwned, { use_context_provider(cx, || { - GenericRouterContext::new( + RouterContext::new( (cx.props .config .config @@ -164,6 +160,6 @@ where }); render! { - GenericOutlet:: {} + Outlet:: {} } } diff --git a/packages/router/src/contexts/navigator.rs b/packages/router/src/contexts/navigator.rs index 57538dc58..d8cf6aa57 100644 --- a/packages/router/src/contexts/navigator.rs +++ b/packages/router/src/contexts/navigator.rs @@ -1,10 +1,10 @@ -use crate::prelude::{ExternalNavigationFailure, GenericRouterContext, NavigationTarget, Routable}; +use crate::prelude::{ExternalNavigationFailure, NavigationTarget, Routable, RouterContext}; /// A view into the navigation state of a router. #[derive(Clone)] -pub struct GenericNavigator(pub(crate) GenericRouterContext); +pub struct GenericNavigator(pub(crate) RouterContext); -impl GenericNavigator { +impl GenericNavigator { /// Check whether there is a previous page to navigate back to. #[must_use] pub fn can_go_back(&self) -> bool { @@ -34,7 +34,7 @@ impl GenericNavigator { /// Push a new location. /// /// The previous location will be available to go back to. - pub fn push( + pub fn push( &self, target: impl Into>, ) -> Option { @@ -44,7 +44,7 @@ impl GenericNavigator { /// Replace the current location. /// /// The previous location will **not** be available to go back to. - pub fn replace( + pub fn replace( &self, target: impl Into>, ) -> Option { diff --git a/packages/router/src/contexts/outlet.rs b/packages/router/src/contexts/outlet.rs index 6284e25f8..d4a070351 100644 --- a/packages/router/src/contexts/outlet.rs +++ b/packages/router/src/contexts/outlet.rs @@ -31,7 +31,7 @@ impl OutletContext { where R: Routable + Clone, { - let router = use_router_internal::(cx) + let router = use_router_internal(cx) .as_ref() .expect("Outlet must be inside of a router"); let outlet: &OutletContext = use_outlet_context(cx); @@ -51,6 +51,6 @@ impl OutletContext { } } - router.current().render(cx, current_level) + router.current::().render(cx, current_level) } } diff --git a/packages/router/src/contexts/router.rs b/packages/router/src/contexts/router.rs index a64b64b4c..136e9e3b7 100644 --- a/packages/router/src/contexts/router.rs +++ b/packages/router/src/contexts/router.rs @@ -1,4 +1,5 @@ use std::{ + any::Any, collections::HashSet, sync::{Arc, RwLock, RwLockWriteGuard}, }; @@ -6,7 +7,7 @@ use std::{ use dioxus::prelude::*; use crate::{ - history::HistoryProvider, navigation::NavigationTarget, routable::Routable, + navigation::NavigationTarget, prelude::AnyHistoryProvider, routable::Routable, router_cfg::RouterConfig, }; @@ -15,52 +16,31 @@ use crate::{ pub struct ExternalNavigationFailure(String); /// A function the router will call after every routing update. -pub(crate) type RoutingCallback = - Arc) -> Option>>; +pub(crate) type RoutingCallback = Arc) -> Option>>; -struct MutableRouterState -where - R: Routable, -{ +struct MutableRouterState { /// The current prefix. prefix: Option, - history: Box>, + history: Box, unresolved_error: Option, } /// A collection of router data that manages all routing functionality. -pub struct GenericRouterContext -where - R: Routable, -{ - state: Arc>>, +#[derive(Clone)] +pub struct RouterContext { + state: Arc>, subscribers: Arc>>, subscriber_update: Arc, - routing_callback: Option>, + routing_callback: Option Option>>>>, failure_external_navigation: fn(Scope) -> Element, } -impl Clone for GenericRouterContext { - fn clone(&self) -> Self { - Self { - state: self.state.clone(), - subscribers: self.subscribers.clone(), - subscriber_update: self.subscriber_update.clone(), - routing_callback: self.routing_callback.clone(), - failure_external_navigation: self.failure_external_navigation, - } - } -} - -impl GenericRouterContext -where - R: Routable, -{ - pub(crate) fn new( +impl RouterContext { + pub(crate) fn new( mut cfg: RouterConfig, mark_dirty: Arc, ) -> Self @@ -82,7 +62,21 @@ where subscribers: subscribers.clone(), subscriber_update, - routing_callback: cfg.on_update, + routing_callback: cfg.on_update.map(|update| { + Arc::new(move |ctx| { + let ctx = LinkContext { + inner: ctx, + _marker: std::marker::PhantomData, + }; + update(ctx).map(|t| match t { + NavigationTarget::Internal(r) => { + NavigationTarget::Internal(Box::new(r) as Box) + } + NavigationTarget::External(s) => NavigationTarget::External(s), + }) + }) + as Arc Option>>> + }), failure_external_navigation: cfg.failure_external_navigation, }; @@ -100,6 +94,11 @@ where myself } + pub(crate) fn route_from_str(&self, route: &str) -> Result, String> { + let state = self.state.read().unwrap(); + state.history.parse_route(route) + } + /// Check whether there is a previous page to navigate back to. #[must_use] pub fn can_go_back(&self) -> bool { @@ -134,14 +133,10 @@ where self.change_route(); } - /// Push a new location. - /// - /// The previous location will be available to go back to. - pub fn push( + pub(crate) fn push_any( &self, - target: impl Into>, + target: NavigationTarget>, ) -> Option { - let target = target.into(); match target { NavigationTarget::Internal(p) => { let mut state = self.state_mut(); @@ -153,10 +148,29 @@ where self.change_route() } + /// Push a new location. + /// + /// The previous location will be available to go back to. + pub fn push( + &self, + target: impl Into>, + ) -> Option { + let target = target.into(); + match target { + NavigationTarget::Internal(p) => { + let mut state = self.state_mut(); + state.history.push(Box::new(p)) + } + NavigationTarget::External(e) => return self.external(e), + } + + self.change_route() + } + /// Replace the current location. /// /// The previous location will **not** be available to go back to. - pub fn replace( + pub fn replace( &self, target: impl Into>, ) -> Option { @@ -165,7 +179,7 @@ where { let mut state = self.state_mut(); match target { - NavigationTarget::Internal(p) => state.history.replace(p), + NavigationTarget::Internal(p) => state.history.replace(Box::new(p)), NavigationTarget::External(e) => return self.external(e), } } @@ -174,11 +188,24 @@ where } /// The route that is currently active. - pub fn current(&self) -> R - where - R: Clone, - { - self.state.read().unwrap().history.current_route() + pub fn current(&self) -> R { + self.state + .read() + .unwrap() + .history + .current_route() + .downcast::() + .unwrap() + } + + /// The route that is currently active. + pub fn current_route_string(&self) -> String { + self.state + .read() + .unwrap() + .history + .current_route() + .to_string() } /// The prefix that is currently active. @@ -201,7 +228,7 @@ where } } - fn state_mut(&self) -> RwLockWriteGuard> { + fn state_mut(&self) -> RwLockWriteGuard { self.state.write().unwrap() } @@ -254,3 +281,87 @@ where None } } + +pub struct LinkContext { + inner: RouterContext, + _marker: std::marker::PhantomData, +} + +impl LinkContext +where + R: Routable, +{ + /// Check whether there is a previous page to navigate back to. + #[must_use] + pub fn can_go_back(&self) -> bool { + self.inner.can_go_back() + } + + /// Check whether there is a future page to navigate forward to. + #[must_use] + pub fn can_go_forward(&self) -> bool { + self.inner.can_go_forward() + } + + /// Go back to the previous location. + /// + /// Will fail silently if there is no previous location to go to. + pub fn go_back(&self) { + self.inner.go_back(); + } + + /// Go back to the next location. + /// + /// Will fail silently if there is no next location to go to. + pub fn go_forward(&self) { + self.inner.go_forward(); + } + + /// Push a new location. + /// + /// The previous location will be available to go back to. + pub fn push( + &self, + target: impl Into>, + ) -> Option { + self.inner.push(target) + } + + /// Replace the current location. + /// + /// The previous location will **not** be available to go back to. + pub fn replace( + &self, + target: impl Into>, + ) -> Option { + self.inner.replace(target) + } + + /// The route that is currently active. + pub fn current(&self) -> R + where + R: Clone, + { + self.inner.current() + } + + /// The prefix that is currently active. + pub fn prefix(&self) -> Option { + self.inner.prefix() + } + + /// Manually subscribe to the current route + pub fn subscribe(&self, id: ScopeId) { + self.inner.subscribe(id) + } + + /// Manually unsubscribe from the current route + pub fn unsubscribe(&self, id: ScopeId) { + self.inner.unsubscribe(id) + } + + /// Clear any unresolved errors + pub fn clear_error(&self) { + self.inner.clear_error() + } +} diff --git a/packages/router/src/history/mod.rs b/packages/router/src/history/mod.rs index 21c7b9e92..e666e8550 100644 --- a/packages/router/src/history/mod.rs +++ b/packages/router/src/history/mod.rs @@ -10,7 +10,7 @@ //! 1) [`MemoryHistory`] for desktop/mobile/ssr platforms //! 2) [`WebHistory`] for web platforms -use std::sync::Arc; +use std::{any::Any, fmt::Display, sync::Arc}; mod memory; pub use memory::*; @@ -277,3 +277,143 @@ pub trait HistoryProvider { #[allow(unused_variables)] fn updater(&mut self, callback: Arc) {} } + +/// Something that can be displayed and is also an [`Any`] +pub trait AnyDisplay: Display + Any { + /// Get a reference to the inner [`Any`] object. + fn as_any(&self) -> &dyn Any; +} + +impl dyn AnyDisplay { + /// Try to downcast the inner [`Any`] object to a concrete type. + pub fn downcast(self: Box) -> Option { + self.as_any().downcast_ref::().cloned() + } +} + +impl AnyDisplay for T { + fn as_any(&self) -> &dyn Any { + self + } +} + +pub(crate) trait AnyHistoryProvider { + #[must_use] + fn parse_route(&self, route: &str) -> Result, String>; + + #[must_use] + fn accepts_type_id(&self, type_id: &std::any::TypeId) -> bool; + + #[must_use] + fn current_route(&self) -> Box; + + #[must_use] + fn current_prefix(&self) -> Option { + None + } + + #[must_use] + fn can_go_back(&self) -> bool { + true + } + + fn go_back(&mut self); + + #[must_use] + fn can_go_forward(&self) -> bool { + true + } + + fn go_forward(&mut self); + + fn push(&mut self, route: Box); + + fn replace(&mut self, path: Box); + + #[allow(unused_variables)] + fn external(&mut self, url: String) -> bool { + false + } + + #[allow(unused_variables)] + fn updater(&mut self, callback: Arc) {} +} + +pub(crate) struct AnyHistoryProviderImplWrapper { + inner: H, + _marker: std::marker::PhantomData, +} + +impl AnyHistoryProviderImplWrapper { + pub fn new(inner: H) -> Self { + Self { + inner, + _marker: std::marker::PhantomData, + } + } +} + +impl Default for AnyHistoryProviderImplWrapper { + fn default() -> Self { + Self::new(H::default()) + } +} + +impl AnyHistoryProvider for AnyHistoryProviderImplWrapper +where + R: Routable, + ::Err: std::fmt::Display, + H: HistoryProvider, +{ + fn parse_route(&self, route: &str) -> Result, String> { + R::from_str(route) + .map_err(|err| err.to_string()) + .map(|route| Box::new(route) as Box) + } + + fn accepts_type_id(&self, type_id: &std::any::TypeId) -> bool { + type_id == &std::any::TypeId::of::() + } + + fn current_route(&self) -> Box { + let route = self.inner.current_route(); + println!("current_route {route}"); + Box::new(route) + } + + fn current_prefix(&self) -> Option { + self.inner.current_prefix() + } + + fn can_go_back(&self) -> bool { + self.inner.can_go_back() + } + + fn go_back(&mut self) { + self.inner.go_back() + } + + fn can_go_forward(&self) -> bool { + self.inner.can_go_forward() + } + + fn go_forward(&mut self) { + self.inner.go_forward() + } + + fn push(&mut self, route: Box) { + self.inner.push(*route.downcast().unwrap()) + } + + fn replace(&mut self, path: Box) { + self.inner.replace(*path.downcast().unwrap()) + } + + fn external(&mut self, url: String) -> bool { + self.inner.external(url) + } + + fn updater(&mut self, callback: Arc) { + self.inner.updater(callback) + } +} diff --git a/packages/router/src/hooks/use_navigator.rs b/packages/router/src/hooks/use_navigator.rs index 5cd0a0e83..aab64fdc2 100644 --- a/packages/router/src/hooks/use_navigator.rs +++ b/packages/router/src/hooks/use_navigator.rs @@ -1,9 +1,6 @@ use dioxus::prelude::ScopeState; -use crate::{ - prelude::{GenericNavigator, GenericRouterContext}, - routable::Routable, -}; +use crate::prelude::{GenericNavigator, RouterContext}; /// A hook that provides access to the navigator to change the router history. Unlike [`use_router`], this hook will not cause a rerender when the current route changes /// @@ -22,7 +19,7 @@ use crate::{ /// /// fn App(cx: Scope) -> Element { /// render! { -/// Router {} +/// Router:: {} /// } /// } /// @@ -50,10 +47,10 @@ use crate::{ /// # let mut vdom = VirtualDom::new(App); /// # let _ = vdom.rebuild(); /// ``` -pub fn use_generic_navigator(cx: &ScopeState) -> &GenericNavigator { +pub fn use_navigator(cx: &ScopeState) -> &GenericNavigator { &*cx.use_hook(|| { let router = cx - .consume_context::>() + .consume_context::() .expect("Must be called in a descendant of a Router component"); GenericNavigator(router) diff --git a/packages/router/src/hooks/use_route.rs b/packages/router/src/hooks/use_route.rs index a0ba34ce8..e6aa906d5 100644 --- a/packages/router/src/hooks/use_route.rs +++ b/packages/router/src/hooks/use_route.rs @@ -8,11 +8,11 @@ use crate::utils::use_router_internal::use_router_internal; /// > The Routable macro will define a version of this hook with an explicit type. /// /// # Return values -/// - None, when not called inside a [`GenericRouter`] component. +/// - None, when not called inside a [`Link`] component. /// - Otherwise the current route. /// /// # Panic -/// - When the calling component is not nested within a [`GenericRouter`] component durring a debug build. +/// - When the calling component is not nested within a [`Link`] component durring a debug build. /// /// # Example /// ```rust @@ -28,7 +28,7 @@ use crate::utils::use_router_internal::use_router_internal; /// fn App(cx: Scope) -> Element { /// render! { /// h1 { "App" } -/// Router {} +/// Router:: {} /// } /// } /// @@ -45,7 +45,7 @@ use crate::utils::use_router_internal::use_router_internal; /// # let _ = vdom.rebuild(); /// # assert_eq!(dioxus_ssr::render(&vdom), "

App

Current Path

/

") /// ``` -pub fn use_generic_route(cx: &ScopeState) -> Option { +pub fn use_route(cx: &ScopeState) -> Option { match use_router_internal(cx) { Some(r) => Some(r.current()), None => { diff --git a/packages/router/src/hooks/use_router.rs b/packages/router/src/hooks/use_router.rs index b9485577a..1b7556665 100644 --- a/packages/router/src/hooks/use_router.rs +++ b/packages/router/src/hooks/use_router.rs @@ -1,12 +1,9 @@ use dioxus::prelude::ScopeState; -use crate::{ - prelude::GenericRouterContext, routable::Routable, - utils::use_router_internal::use_router_internal, -}; +use crate::{prelude::RouterContext, utils::use_router_internal::use_router_internal}; /// A hook that provides access to information about the router. -pub fn use_generic_router(cx: &ScopeState) -> &GenericRouterContext { +pub fn use_router(cx: &ScopeState) -> &RouterContext { use_router_internal(cx) .as_ref() .expect("use_route must have access to a router") diff --git a/packages/router/src/incremental.rs b/packages/router/src/incremental.rs index 2299be614..b89a2fc09 100644 --- a/packages/router/src/incremental.rs +++ b/packages/router/src/incremental.rs @@ -95,7 +95,7 @@ where { let path = path.clone(); render! { - GenericRouter:: { + Link:: { config: || RouterConfig::default().history(MemoryHistory::with_initial_path(path)) } } diff --git a/packages/router/src/navigation.rs b/packages/router/src/navigation.rs index 71ca9a4ab..c0a85fe67 100644 --- a/packages/router/src/navigation.rs +++ b/packages/router/src/navigation.rs @@ -11,7 +11,7 @@ use crate::routable::Routable; /// A target for the router to navigate to. #[derive(Clone, PartialEq, Eq, Debug)] -pub enum NavigationTarget { +pub enum NavigationTarget { /// An internal path that the router can navigate to by itself. /// /// ```rust diff --git a/packages/router/src/router_cfg.rs b/packages/router/src/router_cfg.rs index 31eeeb4d5..23731810c 100644 --- a/packages/router/src/router_cfg.rs +++ b/packages/router/src/router_cfg.rs @@ -26,7 +26,7 @@ use crate::prelude::*; /// ``` pub struct RouterConfig { pub(crate) failure_external_navigation: fn(Scope) -> Element, - pub(crate) history: Option>>, + pub(crate) history: Option>, pub(crate) on_update: Option>, } @@ -69,7 +69,7 @@ where { fn default() -> Self { Self { - failure_external_navigation: FailureExternalNavigation::, + failure_external_navigation: FailureExternalNavigation, history: None, on_update: None, } @@ -81,18 +81,22 @@ impl RouterConfig where ::Err: std::fmt::Display, { - pub(crate) fn take_history(&mut self) -> Box> { + pub(crate) fn take_history(&mut self) -> Box { self.history.take().unwrap_or_else(|| { #[cfg(all(target_arch = "wasm32", feature = "web"))] - let history = Box::>::default(); + let history = Box::>>::default(); #[cfg(not(all(target_arch = "wasm32", feature = "web")))] - let history = Box::>::default(); + let history = Box::>>::default(); history }) } } -impl RouterConfig { +impl RouterConfig +where + R: Routable, + ::Err: std::fmt::Display, +{ /// A function to be called whenever the routing is updated. /// /// The callback is invoked after the routing is updated, but before components and hooks are @@ -108,7 +112,7 @@ impl RouterConfig { /// Defaults to [`None`]. pub fn on_update( self, - callback: impl Fn(GenericRouterContext) -> Option> + 'static, + callback: impl Fn(LinkContext) -> Option> + 'static, ) -> Self { Self { on_update: Some(Arc::new(callback)), @@ -121,7 +125,7 @@ impl RouterConfig { /// Defaults to a default [`MemoryHistory`]. pub fn history(self, history: impl HistoryProvider + 'static) -> Self { Self { - history: Some(Box::new(history)), + history: Some(Box::new(AnyHistoryProviderImplWrapper::new(history))), ..self } } diff --git a/packages/router/src/utils/use_router_internal.rs b/packages/router/src/utils/use_router_internal.rs index 898ef539f..9ac33f5fb 100644 --- a/packages/router/src/utils/use_router_internal.rs +++ b/packages/router/src/utils/use_router_internal.rs @@ -1,6 +1,6 @@ use dioxus::prelude::{ScopeId, ScopeState}; -use crate::{contexts::router::GenericRouterContext, prelude::*}; +use crate::prelude::*; /// A private hook to subscribe to the router. /// @@ -8,13 +8,11 @@ use crate::{contexts::router::GenericRouterContext, prelude::*}; /// single component, but not recommended. Multiple subscriptions will be discarded. /// /// # Return values -/// - [`None`], when the current component isn't a descendant of a [`GenericRouter`] component. +/// - [`None`], when the current component isn't a descendant of a [`Link`] component. /// - Otherwise [`Some`]. -pub(crate) fn use_router_internal( - cx: &ScopeState, -) -> &Option> { +pub(crate) fn use_router_internal(cx: &ScopeState) -> &Option { let inner = cx.use_hook(|| { - let router = cx.consume_context::>()?; + let router = cx.consume_context::()?; let id = cx.scope_id(); router.subscribe(id); @@ -24,12 +22,12 @@ pub(crate) fn use_router_internal( cx.use_hook(|| inner.as_ref().map(|s| s.router.clone())) } -struct Subscription { - router: GenericRouterContext, +struct Subscription { + router: RouterContext, id: ScopeId, } -impl Drop for Subscription { +impl Drop for Subscription { fn drop(&mut self) { self.router.unsubscribe(self.id); } diff --git a/packages/router/tests/via_ssr/link.rs b/packages/router/tests/via_ssr/link.rs index 764a9f699..3fe899128 100644 --- a/packages/router/tests/via_ssr/link.rs +++ b/packages/router/tests/via_ssr/link.rs @@ -33,7 +33,7 @@ where { render! { h1 { "App" } - GenericRouter:: { + Router:: { config: || RouterConfig::default().history(MemoryHistory::default()) } } @@ -97,7 +97,7 @@ fn href_external() { fn Root(cx: Scope) -> Element { render! { Link { - to: NavigationTarget::External("https://dioxuslabs.com/".into()), + to: "https://dioxuslabs.com/", "Link" } } @@ -318,7 +318,7 @@ fn with_new_tab_external() { fn Root(cx: Scope) -> Element { render! { Link { - to: NavigationTarget::External("https://dioxuslabs.com/".into()), + to: "https://dioxuslabs.com/", new_tab: true, "Link" } diff --git a/packages/router/tests/via_ssr/outlet.rs b/packages/router/tests/via_ssr/outlet.rs index ba8eb8873..d48b355d0 100644 --- a/packages/router/tests/via_ssr/outlet.rs +++ b/packages/router/tests/via_ssr/outlet.rs @@ -37,7 +37,7 @@ fn prepare(path: impl Into) -> VirtualDom { fn App(cx: Scope) -> Element { render! { h1 { "App" } - Router { + Router:: { config: { let path = cx.props.path.parse().unwrap(); move || RouterConfig::default().history(MemoryHistory::with_initial_path(path)) @@ -57,7 +57,7 @@ fn prepare(path: impl Into) -> VirtualDom { fn Fixed(cx: Scope) -> Element { render! { h2 { "Fixed" } - Outlet { } + Outlet:: { } } } @@ -79,7 +79,7 @@ fn prepare(path: impl Into) -> VirtualDom { fn Parameter(cx: Scope, id: u8) -> Element { render! { h2 { "Parameter {id}" } - Outlet { } + Outlet:: { } } } From e7a9161066b80c293522a008d35756ddbc817914 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 26 Jul 2023 10:18:39 -0700 Subject: [PATCH 2/6] fix link component --- examples/read_size.rs | 2 +- packages/cli/src/cli/check/mod.rs | 8 +++++-- packages/router/src/components/link.rs | 14 ++++++------ packages/router/src/contexts/router.rs | 30 ++++++++++++++++++++------ packages/router/src/history/mod.rs | 26 ++++------------------ packages/router/src/routable.rs | 1 - 6 files changed, 42 insertions(+), 39 deletions(-) diff --git a/examples/read_size.rs b/examples/read_size.rs index 20635eeab..806f71f80 100644 --- a/examples/read_size.rs +++ b/examples/read_size.rs @@ -48,7 +48,7 @@ fn app(cx: Scope) -> Element { let read = div_element.read(); let client_rect = read.as_ref().map(|el| el.get_client_rect()); if let Some(client_rect) = client_rect { - if let Ok(rect) = dbg!(client_rect.await) { + if let Ok(rect) = client_rect.await { dimentions.set(rect); } } diff --git a/packages/cli/src/cli/check/mod.rs b/packages/cli/src/cli/check/mod.rs index ad086af5a..a4d84addb 100644 --- a/packages/cli/src/cli/check/mod.rs +++ b/packages/cli/src/cli/check/mod.rs @@ -106,12 +106,16 @@ async fn check_files_and_report(files_to_check: Vec) -> Result<()> { } fn collect_rs_files(folder: &Path, files: &mut Vec) { - let Ok(folder) = folder.read_dir() else { return }; + let Ok(folder) = folder.read_dir() else { + return; + }; // load the gitignore for entry in folder { - let Ok(entry) = entry else { continue; }; + let Ok(entry) = entry else { + continue; + }; let path = entry.path(); diff --git a/packages/router/src/components/link.rs b/packages/router/src/components/link.rs index efed7fb5f..f6840b5b4 100644 --- a/packages/router/src/components/link.rs +++ b/packages/router/src/components/link.rs @@ -5,7 +5,7 @@ use dioxus::prelude::*; use log::error; use crate::navigation::NavigationTarget; -use crate::prelude::{AnyDisplay, Routable}; +use crate::prelude::Routable; use crate::utils::use_router_internal::use_router_internal; /// Something that can be converted into a [`NavigationTarget`]. @@ -13,19 +13,21 @@ pub enum IntoRoutable { /// A raw string target. FromStr(String), /// A internal target. - Route(Box), + Route(Box), } impl From for IntoRoutable { fn from(value: R) -> Self { - IntoRoutable::Route(Box::new(value)) + IntoRoutable::Route(Box::new(value) as Box) } } impl From> for IntoRoutable { fn from(value: NavigationTarget) -> Self { match value { - NavigationTarget::Internal(route) => IntoRoutable::Route(Box::new(route)), + NavigationTarget::Internal(route) => { + IntoRoutable::Route(Box::new(route) as Box) + } NavigationTarget::External(url) => IntoRoutable::FromStr(url), } } @@ -193,7 +195,7 @@ pub fn Link<'a>(cx: Scope<'a, LinkProps<'a>>) -> Element { let current_url = router.current_route_string(); let href = match to { IntoRoutable::FromStr(url) => url.to_string(), - IntoRoutable::Route(route) => route.to_string(), + IntoRoutable::Route(route) => router.any_route_to_string(&**route), }; let parsed_route: NavigationTarget> = match router.route_from_str(&href) { Ok(route) => NavigationTarget::Internal(route.into()), @@ -219,7 +221,7 @@ pub fn Link<'a>(cx: Scope<'a, LinkProps<'a>>) -> Element { if do_default && is_router_nav { let href = match to { IntoRoutable::FromStr(url) => url.to_string(), - IntoRoutable::Route(route) => route.to_string(), + IntoRoutable::Route(route) => router.any_route_to_string(&**route), }; let parsed_route: NavigationTarget> = match router.route_from_str(&href) { Ok(route) => NavigationTarget::Internal(route.into()), diff --git a/packages/router/src/contexts/router.rs b/packages/router/src/contexts/router.rs index 136e9e3b7..70b493a56 100644 --- a/packages/router/src/contexts/router.rs +++ b/packages/router/src/contexts/router.rs @@ -37,6 +37,8 @@ pub struct RouterContext { routing_callback: Option Option>>>>, failure_external_navigation: fn(Scope) -> Element, + + any_route_to_string: fn(&dyn Any) -> String, } impl RouterContext { @@ -79,6 +81,20 @@ impl RouterContext { }), failure_external_navigation: cfg.failure_external_navigation, + + any_route_to_string: |route| { + route + .downcast_ref::() + .unwrap_or_else(|| { + panic!( + "Route is not of the expected type: {}\n found typeid: {:?}\n expected typeid: {:?}", + std::any::type_name::(), + route.type_id(), + std::any::TypeId::of::() + ) + }) + .to_string() + }, }; // set the updater @@ -189,7 +205,8 @@ impl RouterContext { /// The route that is currently active. pub fn current(&self) -> R { - self.state + *self + .state .read() .unwrap() .history @@ -200,12 +217,11 @@ impl RouterContext { /// The route that is currently active. pub fn current_route_string(&self) -> String { - self.state - .read() - .unwrap() - .history - .current_route() - .to_string() + self.any_route_to_string(&*self.state.read().unwrap().history.current_route()) + } + + pub(crate) fn any_route_to_string(&self, route: &dyn Any) -> String { + (self.any_route_to_string)(route) } /// The prefix that is currently active. diff --git a/packages/router/src/history/mod.rs b/packages/router/src/history/mod.rs index e666e8550..591bdb326 100644 --- a/packages/router/src/history/mod.rs +++ b/packages/router/src/history/mod.rs @@ -10,7 +10,7 @@ //! 1) [`MemoryHistory`] for desktop/mobile/ssr platforms //! 2) [`WebHistory`] for web platforms -use std::{any::Any, fmt::Display, sync::Arc}; +use std::{any::Any, sync::Arc}; mod memory; pub use memory::*; @@ -278,25 +278,6 @@ pub trait HistoryProvider { fn updater(&mut self, callback: Arc) {} } -/// Something that can be displayed and is also an [`Any`] -pub trait AnyDisplay: Display + Any { - /// Get a reference to the inner [`Any`] object. - fn as_any(&self) -> &dyn Any; -} - -impl dyn AnyDisplay { - /// Try to downcast the inner [`Any`] object to a concrete type. - pub fn downcast(self: Box) -> Option { - self.as_any().downcast_ref::().cloned() - } -} - -impl AnyDisplay for T { - fn as_any(&self) -> &dyn Any { - self - } -} - pub(crate) trait AnyHistoryProvider { #[must_use] fn parse_route(&self, route: &str) -> Result, String>; @@ -305,7 +286,7 @@ pub(crate) trait AnyHistoryProvider { fn accepts_type_id(&self, type_id: &std::any::TypeId) -> bool; #[must_use] - fn current_route(&self) -> Box; + fn current_route(&self) -> Box; #[must_use] fn current_prefix(&self) -> Option { @@ -375,9 +356,10 @@ where type_id == &std::any::TypeId::of::() } - fn current_route(&self) -> Box { + fn current_route(&self) -> Box { let route = self.inner.current_route(); println!("current_route {route}"); + println!("current_route type {}", std::any::type_name::()); Box::new(route) } diff --git a/packages/router/src/routable.rs b/packages/router/src/routable.rs index 2eb7f5b7b..cd3dd354d 100644 --- a/packages/router/src/routable.rs +++ b/packages/router/src/routable.rs @@ -141,7 +141,6 @@ pub trait Routable: std::fmt::Display + std::str::FromStr + Clone + 'static { let self_segments = self_str.split('/'); let other_segments = other_str.split('/'); for (self_seg, other_seg) in self_segments.zip(other_segments) { - dbg!(self_seg, other_seg); if self_seg != other_seg { return false; } From 0ebcb5f1be05baf3cc4deb1c50aa2cf2c7a26376 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 26 Jul 2023 10:28:49 -0700 Subject: [PATCH 3/6] remove some logging --- packages/router/examples/static_generation.rs | 45 ++++++++++--------- packages/router/src/history/mod.rs | 2 - packages/router/src/incremental.rs | 2 +- 3 files changed, 25 insertions(+), 24 deletions(-) diff --git a/packages/router/examples/static_generation.rs b/packages/router/examples/static_generation.rs index ca05ae774..4bdc1df5f 100644 --- a/packages/router/examples/static_generation.rs +++ b/packages/router/examples/static_generation.rs @@ -9,24 +9,10 @@ use dioxus_ssr::incremental::{DefaultRenderer, IncrementalRendererConfig}; #[tokio::main] async fn main() { - let mut renderer = IncrementalRendererConfig::new(DefaultRenderer { - before_body: r#" - - - - - Dioxus Application - - "# - .to_string(), - after_body: r#" - "# - .to_string(), - }) - .static_dir("./static") - .invalidate_after(Duration::from_secs(10)) - .build(); + let mut renderer = IncrementalRendererConfig::new() + .static_dir("./static") + .invalidate_after(Duration::from_secs(10)) + .build(); println!( "SITE MAP:\n{}", @@ -44,9 +30,26 @@ async fn main() { .join("\n") ); - pre_cache_static_routes::(&mut renderer) - .await - .unwrap(); + pre_cache_static_routes::( + &mut renderer, + &DefaultRenderer { + before_body: r#" + + + + + Dioxus Application + + "# + .to_string(), + after_body: r#" + "# + .to_string(), + }, + ) + .await + .unwrap(); } #[inline_props] diff --git a/packages/router/src/history/mod.rs b/packages/router/src/history/mod.rs index 591bdb326..961a4bd96 100644 --- a/packages/router/src/history/mod.rs +++ b/packages/router/src/history/mod.rs @@ -358,8 +358,6 @@ where fn current_route(&self) -> Box { let route = self.inner.current_route(); - println!("current_route {route}"); - println!("current_route type {}", std::any::type_name::()); Box::new(route) } diff --git a/packages/router/src/incremental.rs b/packages/router/src/incremental.rs index b89a2fc09..79f4e24bf 100644 --- a/packages/router/src/incremental.rs +++ b/packages/router/src/incremental.rs @@ -95,7 +95,7 @@ where { let path = path.clone(); render! { - Link:: { + Router:: { config: || RouterConfig::default().history(MemoryHistory::with_initial_path(path)) } } From 947a15334728b11c680c7124454c0af7af2ac984 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 26 Jul 2023 11:08:45 -0700 Subject: [PATCH 4/6] make navigator non-generic --- packages/router/examples/simple_routes.rs | 2 +- packages/router/src/components/link.rs | 10 +------ packages/router/src/contexts/navigator.rs | 20 ++++++------- packages/router/src/contexts/router.rs | 34 ++++++++++++++++++++++- 4 files changed, 44 insertions(+), 22 deletions(-) diff --git a/packages/router/examples/simple_routes.rs b/packages/router/examples/simple_routes.rs index ac408bb72..673658870 100644 --- a/packages/router/examples/simple_routes.rs +++ b/packages/router/examples/simple_routes.rs @@ -90,7 +90,7 @@ fn Route3(cx: Scope, dynamic: String) -> Element { "hello world link" } button { - onclick: move |_| { navigator.push(NavigationTarget::::External("https://www.google.com".to_string())); }, + onclick: move |_| { navigator.push("https://www.google.com"); }, "google link" } p { "Site Map" } diff --git a/packages/router/src/components/link.rs b/packages/router/src/components/link.rs index f6840b5b4..eb53c9547 100644 --- a/packages/router/src/components/link.rs +++ b/packages/router/src/components/link.rs @@ -219,15 +219,7 @@ pub fn Link<'a>(cx: Scope<'a, LinkProps<'a>>) -> Element { let do_default = onclick.is_none() || !onclick_only; let action = move |event| { if do_default && is_router_nav { - let href = match to { - IntoRoutable::FromStr(url) => url.to_string(), - IntoRoutable::Route(route) => router.any_route_to_string(&**route), - }; - let parsed_route: NavigationTarget> = match router.route_from_str(&href) { - Ok(route) => NavigationTarget::Internal(route.into()), - Err(err) => NavigationTarget::External(err), - }; - router.push_any(parsed_route); + router.push_any(router.resolve_into_routable(to)); } if let Some(handler) = onclick { diff --git a/packages/router/src/contexts/navigator.rs b/packages/router/src/contexts/navigator.rs index d8cf6aa57..2d8623aa8 100644 --- a/packages/router/src/contexts/navigator.rs +++ b/packages/router/src/contexts/navigator.rs @@ -1,4 +1,4 @@ -use crate::prelude::{ExternalNavigationFailure, NavigationTarget, Routable, RouterContext}; +use crate::prelude::{ExternalNavigationFailure, IntoRoutable, RouterContext}; /// A view into the navigation state of a router. #[derive(Clone)] @@ -34,20 +34,18 @@ impl GenericNavigator { /// Push a new location. /// /// The previous location will be available to go back to. - pub fn push( - &self, - target: impl Into>, - ) -> Option { - self.0.push(target) + pub fn push(&self, target: impl Into) -> Option { + let target = target.into(); + let as_any_navigation_target = self.0.resolve_into_routable(&target); + self.0.push_any(as_any_navigation_target) } /// Replace the current location. /// /// The previous location will **not** be available to go back to. - pub fn replace( - &self, - target: impl Into>, - ) -> Option { - self.0.replace(target) + pub fn replace(&self, target: impl Into) -> Option { + let target = target.into(); + let as_any_navigation_target = self.0.resolve_into_routable(&target); + self.0.replace_any(as_any_navigation_target) } } diff --git a/packages/router/src/contexts/router.rs b/packages/router/src/contexts/router.rs index 70b493a56..f0e67fff8 100644 --- a/packages/router/src/contexts/router.rs +++ b/packages/router/src/contexts/router.rs @@ -7,7 +7,9 @@ use std::{ use dioxus::prelude::*; use crate::{ - navigation::NavigationTarget, prelude::AnyHistoryProvider, routable::Routable, + navigation::NavigationTarget, + prelude::{AnyHistoryProvider, IntoRoutable}, + routable::Routable, router_cfg::RouterConfig, }; @@ -203,6 +205,21 @@ impl RouterContext { self.change_route() } + pub(crate) fn replace_any( + &self, + target: NavigationTarget>, + ) -> Option { + match target { + NavigationTarget::Internal(p) => { + let mut state = self.state_mut(); + state.history.replace(p) + } + NavigationTarget::External(e) => return self.external(e), + } + + self.change_route() + } + /// The route that is currently active. pub fn current(&self) -> R { *self @@ -224,6 +241,21 @@ impl RouterContext { (self.any_route_to_string)(route) } + pub(crate) fn resolve_into_routable( + &self, + into_routable: &IntoRoutable, + ) -> NavigationTarget> { + let href = match into_routable { + IntoRoutable::FromStr(url) => url.to_string(), + IntoRoutable::Route(route) => self.any_route_to_string(&**route), + }; + let parsed_route: NavigationTarget> = match self.route_from_str(&href) { + Ok(route) => NavigationTarget::Internal(route.into()), + Err(err) => NavigationTarget::External(err), + }; + parsed_route + } + /// The prefix that is currently active. pub fn prefix(&self) -> Option { self.state.read().unwrap().prefix.clone() From cc94711d626001e24557d0db43420387f85ce98c Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 26 Jul 2023 11:09:40 -0700 Subject: [PATCH 5/6] rename generic navigator to navigator --- packages/router/src/contexts/navigator.rs | 4 ++-- packages/router/src/hooks/use_navigator.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/router/src/contexts/navigator.rs b/packages/router/src/contexts/navigator.rs index 2d8623aa8..d6c08f485 100644 --- a/packages/router/src/contexts/navigator.rs +++ b/packages/router/src/contexts/navigator.rs @@ -2,9 +2,9 @@ use crate::prelude::{ExternalNavigationFailure, IntoRoutable, RouterContext}; /// A view into the navigation state of a router. #[derive(Clone)] -pub struct GenericNavigator(pub(crate) RouterContext); +pub struct Navigator(pub(crate) RouterContext); -impl GenericNavigator { +impl Navigator { /// Check whether there is a previous page to navigate back to. #[must_use] pub fn can_go_back(&self) -> bool { diff --git a/packages/router/src/hooks/use_navigator.rs b/packages/router/src/hooks/use_navigator.rs index aab64fdc2..b435e7f9e 100644 --- a/packages/router/src/hooks/use_navigator.rs +++ b/packages/router/src/hooks/use_navigator.rs @@ -1,6 +1,6 @@ use dioxus::prelude::ScopeState; -use crate::prelude::{GenericNavigator, RouterContext}; +use crate::prelude::{Navigator, RouterContext}; /// A hook that provides access to the navigator to change the router history. Unlike [`use_router`], this hook will not cause a rerender when the current route changes /// @@ -47,12 +47,12 @@ use crate::prelude::{GenericNavigator, RouterContext}; /// # let mut vdom = VirtualDom::new(App); /// # let _ = vdom.rebuild(); /// ``` -pub fn use_navigator(cx: &ScopeState) -> &GenericNavigator { +pub fn use_navigator(cx: &ScopeState) -> &Navigator { &*cx.use_hook(|| { let router = cx .consume_context::() .expect("Must be called in a descendant of a Router component"); - GenericNavigator(router) + Navigator(router) }) } From d2ec27e761ce55d8692e1ebbc5551e91cf568680 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 26 Jul 2023 11:29:34 -0700 Subject: [PATCH 6/6] fix clippy --- packages/fullstack/src/router.rs | 8 ++------ packages/router/src/components/link.rs | 2 +- packages/router/src/contexts/router.rs | 6 ++++-- packages/router/src/history/mod.rs | 1 - 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/packages/fullstack/src/router.rs b/packages/fullstack/src/router.rs index 8eb7ef536..eee282c01 100644 --- a/packages/fullstack/src/router.rs +++ b/packages/fullstack/src/router.rs @@ -49,11 +49,7 @@ where } } -fn default_external_navigation_handler() -> fn(Scope) -> Element -where - R: dioxus_router::prelude::Routable, - ::Err: std::fmt::Display, -{ +fn default_external_navigation_handler() -> fn(Scope) -> Element { dioxus_router::prelude::FailureExternalNavigation } @@ -65,7 +61,7 @@ where ::Err: std::fmt::Display, { #[serde(skip)] - #[serde(default = "default_external_navigation_handler::")] + #[serde(default = "default_external_navigation_handler")] failure_external_navigation: fn(Scope) -> Element, scroll_restoration: bool, #[serde(skip)] diff --git a/packages/router/src/components/link.rs b/packages/router/src/components/link.rs index eb53c9547..15784016d 100644 --- a/packages/router/src/components/link.rs +++ b/packages/router/src/components/link.rs @@ -198,7 +198,7 @@ pub fn Link<'a>(cx: Scope<'a, LinkProps<'a>>) -> Element { IntoRoutable::Route(route) => router.any_route_to_string(&**route), }; let parsed_route: NavigationTarget> = match router.route_from_str(&href) { - Ok(route) => NavigationTarget::Internal(route.into()), + Ok(route) => NavigationTarget::Internal(route), Err(err) => NavigationTarget::External(err), }; let ac = active_class diff --git a/packages/router/src/contexts/router.rs b/packages/router/src/contexts/router.rs index f0e67fff8..89008b0dd 100644 --- a/packages/router/src/contexts/router.rs +++ b/packages/router/src/contexts/router.rs @@ -19,6 +19,8 @@ pub struct ExternalNavigationFailure(String); /// A function the router will call after every routing update. pub(crate) type RoutingCallback = Arc) -> Option>>; +pub(crate) type AnyRoutingCallback = + Arc Option>>>; struct MutableRouterState { /// The current prefix. @@ -36,7 +38,7 @@ pub struct RouterContext { subscribers: Arc>>, subscriber_update: Arc, - routing_callback: Option Option>>>>, + routing_callback: Option, failure_external_navigation: fn(Scope) -> Element, @@ -250,7 +252,7 @@ impl RouterContext { IntoRoutable::Route(route) => self.any_route_to_string(&**route), }; let parsed_route: NavigationTarget> = match self.route_from_str(&href) { - Ok(route) => NavigationTarget::Internal(route.into()), + Ok(route) => NavigationTarget::Internal(route), Err(err) => NavigationTarget::External(err), }; parsed_route diff --git a/packages/router/src/history/mod.rs b/packages/router/src/history/mod.rs index 961a4bd96..4c5b2a3e9 100644 --- a/packages/router/src/history/mod.rs +++ b/packages/router/src/history/mod.rs @@ -279,7 +279,6 @@ pub trait HistoryProvider { } pub(crate) trait AnyHistoryProvider { - #[must_use] fn parse_route(&self, route: &str) -> Result, String>; #[must_use]