create non generic wrappers for each route
This commit is contained in:
1 parent
3678fa1d3f
commit
d3b21879fb
9 files changed
+58
-32
No files matched your search
@@ -32,8 +32,26 @@ 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_router::prelude::GenericRouterProps<#name>>) -> 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 use_router<R: dioxus_router::prelude::Routable + Clone>(cx: &dioxus::prelude::ScopeState) -> &dioxus_router::prelude::GenericRouterContext<R> {
|
||||
dioxus_router::prelude::use_generic_router::<R>(cx)
|
||||
}
|
||||
|
||||
#route_enum
|
||||
|
||||
#error_type
|
||||
@@ -48,6 +66,7 @@ pub fn routable(input: TokenStream) -> TokenStream {
|
||||
}
|
||||
|
||||
struct RouteEnum {
|
||||
vis: syn::Visibility,
|
||||
name: Ident,
|
||||
routes: Vec<Route>,
|
||||
nests: Vec<Nest>,
|
||||
@@ -58,6 +77,7 @@ struct RouteEnum {
|
||||
impl RouteEnum {
|
||||
fn parse(data: syn::ItemEnum) -> syn::Result<Self> {
|
||||
let name = &data.ident;
|
||||
let vis = &data.vis;
|
||||
|
||||
let mut site_map = Vec::new();
|
||||
let mut site_map_stack: Vec<Vec<SiteMapSegment>> = Vec::new();
|
||||
@@ -201,6 +221,7 @@ impl RouteEnum {
|
||||
}
|
||||
|
||||
let myself = Self {
|
||||
vis: vis.clone(),
|
||||
name: name.clone(),
|
||||
routes,
|
||||
nests,
|
||||
|
||||
@@ -15,7 +15,7 @@ fn main() {
|
||||
|
||||
fn root(cx: Scope) -> Element {
|
||||
render! {
|
||||
Router::<Route> {
|
||||
Router {
|
||||
config: RouterConfiguration {
|
||||
history: {
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
@@ -39,7 +39,7 @@ fn UserFrame(cx: Scope, user_id: usize) -> Element {
|
||||
div {
|
||||
background_color: "rgba(0,0,0,50%)",
|
||||
"children:"
|
||||
Outlet::<Route> {}
|
||||
Outlet {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,12 +50,12 @@ fn Route1(cx: Scope, user_id: usize, dynamic: usize, extra: String) -> Element {
|
||||
pre {
|
||||
"Route1{{\n\tuser_id:{user_id},\n\tdynamic:{dynamic},\n\textra:{extra}\n}}"
|
||||
}
|
||||
Link::<Route> {
|
||||
Link {
|
||||
target: Route::Route1 { user_id: *user_id, dynamic: *dynamic, extra: extra.clone() + "." },
|
||||
"Route1 with extra+\".\""
|
||||
}
|
||||
p { "Footer" }
|
||||
Link::<Route> {
|
||||
Link {
|
||||
target: Route::Route3 { dynamic: String::new() },
|
||||
"Home"
|
||||
}
|
||||
@@ -70,7 +70,7 @@ fn Route2(cx: Scope, user_id: usize) -> Element {
|
||||
}
|
||||
(0..*user_id).map(|i| rsx!{ p { "{i}" } }),
|
||||
p { "Footer" }
|
||||
Link::<Route> {
|
||||
Link {
|
||||
target: Route::Route3 { dynamic: String::new() },
|
||||
"Home"
|
||||
}
|
||||
@@ -97,7 +97,7 @@ fn Route3(cx: Scope, dynamic: String) -> Element {
|
||||
value: "{current_route.read()}"
|
||||
}
|
||||
"dynamic: {dynamic}"
|
||||
Link::<Route> {
|
||||
Link {
|
||||
target: Route::Route2 { user_id: 8888 },
|
||||
"hello world link"
|
||||
}
|
||||
@@ -107,7 +107,7 @@ fn Route3(cx: Scope, dynamic: String) -> Element {
|
||||
if let Ok(route) = parsed {
|
||||
if route != router_route {
|
||||
render! {
|
||||
Link::<Route> {
|
||||
Link {
|
||||
target: route.clone(),
|
||||
"{route}"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
use crate::{components::Link, hooks::use_route, navigation::NavigationTarget, routable::Routable};
|
||||
use crate::{
|
||||
components::GenericLink, hooks::use_route, navigation::NavigationTarget, routable::Routable,
|
||||
};
|
||||
use dioxus::prelude::*;
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
@@ -35,7 +37,7 @@ pub fn FailureNamedNavigation<R: Routable + Clone>(cx: Scope) -> Element {
|
||||
"We are sorry for the inconvenience. The link below may help to fix the problem, but "
|
||||
"there is no guarantee."
|
||||
}
|
||||
Link::<R> {
|
||||
GenericLink::<R> {
|
||||
target: NavigationTarget::External("https://google.com".into()),
|
||||
"Click here to try to fix the failure."
|
||||
}
|
||||
@@ -55,7 +57,7 @@ pub fn FailureRedirectionLimit<R: Routable + Clone>(cx: Scope) -> Element {
|
||||
"We are sorry for the inconvenience. The link below may help to fix the problem, but "
|
||||
"there is no guarantee."
|
||||
}
|
||||
Link::<R> {
|
||||
GenericLink::<R> {
|
||||
target: NavigationTarget::External("https://google.com".into()),
|
||||
"Click here to try to fix the failure."
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ use crate::utils::use_router_internal::use_router_internal;
|
||||
|
||||
/// The properties for a [`Link`].
|
||||
#[derive(Props)]
|
||||
pub struct LinkProps<'a, R: Routable> {
|
||||
pub struct GenericLinkProps<'a, R: Routable> {
|
||||
/// 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.
|
||||
@@ -45,7 +45,7 @@ pub struct LinkProps<'a, R: Routable> {
|
||||
pub target: NavigationTarget<R>,
|
||||
}
|
||||
|
||||
impl<R: Routable> Debug for LinkProps<'_, R> {
|
||||
impl<R: Routable> Debug for GenericLinkProps<'_, R> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("LinkProps")
|
||||
.field("active_class", &self.active_class)
|
||||
@@ -125,8 +125,8 @@ impl<R: Routable> Debug for LinkProps<'_, R> {
|
||||
/// # );
|
||||
/// ```
|
||||
#[allow(non_snake_case)]
|
||||
pub fn Link<'a, R: Routable + Clone>(cx: Scope<'a, LinkProps<'a, R>>) -> Element {
|
||||
let LinkProps {
|
||||
pub fn GenericLink<'a, R: Routable + Clone>(cx: Scope<'a, GenericLinkProps<'a, R>>) -> Element {
|
||||
let GenericLinkProps {
|
||||
active_class,
|
||||
children,
|
||||
class,
|
||||
|
||||
@@ -44,6 +44,6 @@ use dioxus::prelude::*;
|
||||
/// # let _ = vdom.rebuild();
|
||||
/// # assert_eq!(dioxus_ssr::render(&vdom), "<h1>App</h1><p>Content</p>");
|
||||
/// ```
|
||||
pub fn Outlet<R: Routable + Clone>(cx: Scope) -> Element {
|
||||
pub fn GenericOutlet<R: Routable + Clone>(cx: Scope) -> Element {
|
||||
OutletContext::render::<R>(cx)
|
||||
}
|
||||
@@ -3,7 +3,7 @@ use log::error;
|
||||
use std::{cell::RefCell, str::FromStr};
|
||||
|
||||
use crate::{
|
||||
prelude::{Outlet, RouterContext},
|
||||
prelude::{GenericOutlet, GenericRouterContext},
|
||||
routable::Routable,
|
||||
router_cfg::RouterConfiguration,
|
||||
};
|
||||
@@ -34,7 +34,7 @@ impl<R: Routable> From<RouterConfiguration<R>> for RouterCfg<R> {
|
||||
|
||||
/// The props for [`Router`].
|
||||
#[derive(Props)]
|
||||
pub struct RouterProps<R: Routable>
|
||||
pub struct GenericRouterProps<R: Routable>
|
||||
where
|
||||
<R as FromStr>::Err: std::fmt::Display,
|
||||
{
|
||||
@@ -44,7 +44,7 @@ where
|
||||
config: RouterCfg<R>,
|
||||
}
|
||||
|
||||
impl<R: Routable> PartialEq for RouterProps<R>
|
||||
impl<R: Routable> PartialEq for GenericRouterProps<R>
|
||||
where
|
||||
<R as FromStr>::Err: std::fmt::Display,
|
||||
{
|
||||
@@ -55,19 +55,19 @@ where
|
||||
}
|
||||
|
||||
/// A component that renders the current route.
|
||||
pub fn Router<R: Routable + Clone>(cx: Scope<RouterProps<R>>) -> Element
|
||||
pub fn GenericRouter<R: Routable + Clone>(cx: Scope<GenericRouterProps<R>>) -> Element
|
||||
where
|
||||
<R as FromStr>::Err: std::fmt::Display,
|
||||
{
|
||||
use_context_provider(cx, || {
|
||||
#[allow(unreachable_code, unused_variables)]
|
||||
if let Some(outer) = cx.consume_context::<RouterContext<R>>() {
|
||||
if let Some(outer) = cx.consume_context::<GenericRouterContext<R>>() {
|
||||
let msg = "Router components should not be nested within each other";
|
||||
error!("{msg}, inner will be inactive and transparent");
|
||||
#[cfg(debug_assertions)]
|
||||
panic!("{}", msg);
|
||||
}
|
||||
let router = RouterContext::new(
|
||||
let router = GenericRouterContext::new(
|
||||
cx.props.config.config.take().unwrap_or_default(),
|
||||
cx.schedule_update_any(),
|
||||
);
|
||||
@@ -82,6 +82,6 @@ where
|
||||
});
|
||||
|
||||
render! {
|
||||
Outlet::<R> {}
|
||||
GenericOutlet::<R> {}
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ pub enum NavigationFailure<R: Routable> {
|
||||
}
|
||||
|
||||
/// A function the router will call after every routing update.
|
||||
pub type RoutingCallback<R> = Arc<dyn Fn(RouterContext<R>) -> Option<NavigationTarget<R>>>;
|
||||
pub type RoutingCallback<R> = Arc<dyn Fn(GenericRouterContext<R>) -> Option<NavigationTarget<R>>>;
|
||||
|
||||
struct MutableRouterState<R>
|
||||
where
|
||||
@@ -43,7 +43,7 @@ where
|
||||
}
|
||||
|
||||
/// A collection of router data that manages all routing functionality.
|
||||
pub struct RouterContext<R>
|
||||
pub struct GenericRouterContext<R>
|
||||
where
|
||||
R: Routable,
|
||||
{
|
||||
@@ -58,7 +58,7 @@ where
|
||||
failure_redirection_limit: fn(Scope) -> Element,
|
||||
}
|
||||
|
||||
impl<R: Routable> Clone for RouterContext<R> {
|
||||
impl<R: Routable> Clone for GenericRouterContext<R> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
state: self.state.clone(),
|
||||
@@ -72,7 +72,7 @@ impl<R: Routable> Clone for RouterContext<R> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> RouterContext<R>
|
||||
impl<R> GenericRouterContext<R>
|
||||
where
|
||||
R: Routable,
|
||||
{
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
use dioxus::prelude::ScopeState;
|
||||
|
||||
use crate::{
|
||||
prelude::RouterContext, routable::Routable, utils::use_router_internal::use_router_internal,
|
||||
prelude::GenericRouterContext, routable::Routable,
|
||||
utils::use_router_internal::use_router_internal,
|
||||
};
|
||||
|
||||
/// A hook that provides access to information about the router
|
||||
pub fn use_router<R: Routable + Clone>(cx: &ScopeState) -> &RouterContext<R> {
|
||||
pub fn use_generic_router<R: Routable + Clone>(cx: &ScopeState) -> &GenericRouterContext<R> {
|
||||
use_router_internal(cx)
|
||||
.as_ref()
|
||||
.expect("use_route must have access to a router")
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use dioxus::prelude::{ScopeId, ScopeState};
|
||||
|
||||
use crate::{contexts::router::RouterContext, routable::Routable};
|
||||
use crate::{contexts::router::GenericRouterContext, routable::Routable};
|
||||
|
||||
/// A private hook to subscribe to the router.
|
||||
///
|
||||
@@ -12,9 +12,11 @@ use crate::{contexts::router::RouterContext, routable::Routable};
|
||||
/// - Otherwise [`Some`].
|
||||
///
|
||||
/// [`use_router`]: crate::hooks::use_router
|
||||
pub(crate) fn use_router_internal<R: Routable>(cx: &ScopeState) -> &Option<RouterContext<R>> {
|
||||
pub(crate) fn use_router_internal<R: Routable>(
|
||||
cx: &ScopeState,
|
||||
) -> &Option<GenericRouterContext<R>> {
|
||||
let inner = cx.use_hook(|| {
|
||||
let router = cx.consume_context::<RouterContext<R>>()?;
|
||||
let router = cx.consume_context::<GenericRouterContext<R>>()?;
|
||||
|
||||
let id = cx.scope_id();
|
||||
router.subscribe(id);
|
||||
@@ -25,7 +27,7 @@ pub(crate) fn use_router_internal<R: Routable>(cx: &ScopeState) -> &Option<Route
|
||||
}
|
||||
|
||||
struct Subscription<R: Routable> {
|
||||
router: RouterContext<R>,
|
||||
router: GenericRouterContext<R>,
|
||||
id: ScopeId,
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user