feat: correctly support relative routing for FlatRoutes

This commit is contained in:
Greg Johnston 2024-09-04 20:43:59 -04:00
parent 4784b2ddab
commit 88004e5042

View file

@ -1,4 +1,5 @@
use crate::{
hooks::Matched,
location::{LocationProvider, Url},
matching::Routes,
params::ParamsMap,
@ -49,7 +50,8 @@ where
owner: Owner,
params: ArcRwSignal<ParamsMap>,
path: String,
url: ArcRwSignal<Url>
url: ArcRwSignal<Url>,
matched: ArcRwSignal<String>
}
impl<Defs, Fal, R> Mountable<R> for FlatRoutesViewState<Defs, Fal, R>
@ -98,6 +100,12 @@ where
// we always need to match the new route
let new_match = routes.match_route(current_url.path());
let id = new_match.as_ref().map(|n| n.as_id());
let matched = ArcRwSignal::new(
new_match
.as_ref()
.map(|n| n.as_matched().to_owned())
.unwrap_or_default(),
);
// create default starting points for owner, url, path, and params
// these will be held in state so that future navigations can update or replace them
@ -120,10 +128,10 @@ where
params,
path,
url,
matched,
})),
Some(matched) => {
let matched_str = matched.as_matched();
let (view, child) = matched.into_view_and_child();
Some(new_match) => {
let (view, child) = new_match.into_view_and_child();
#[cfg(debug_assertions)]
if child.is_some() {
@ -135,9 +143,11 @@ where
let mut view = Box::pin(owner.with(|| {
ScopedFuture::new({
let url = url.clone();
let matched = matched.clone();
async move {
provide_context(params_memo);
provide_context(url);
provide_context(Matched(ArcMemo::from(matched)));
view.choose().await
}
})
@ -151,6 +161,7 @@ where
params,
path,
url,
matched,
})),
None => {
let state =
@ -161,6 +172,7 @@ where
params,
path,
url,
matched,
}));
Executor::spawn_local({
@ -208,6 +220,10 @@ where
// otherwise, match the new route
let new_match = routes.match_route(url_snapshot.path());
let new_id = new_match.as_ref().map(|n| n.as_id());
let matched_string = new_match
.as_ref()
.map(|n| n.as_matched().to_owned())
.unwrap_or_default();
let matched_params = new_match
.as_ref()
.map(|n| n.to_params().into_iter().collect())
@ -216,6 +232,7 @@ where
// if it's the same route, we just update the params
if new_id == initial_state.id {
initial_state.params.set(matched_params);
initial_state.matched.set(matched_string);
if let Some(location) = location {
location.ready_to_complete();
}
@ -236,6 +253,9 @@ where
let old_url = mem::replace(&mut initial_state.url, url.clone());
let old_params =
mem::replace(&mut initial_state.params, params.clone());
let new_matched = ArcRwSignal::new(matched_string);
let old_matched =
mem::replace(&mut initial_state.matched, new_matched.clone());
// we drop the route state here, in case there is a <Redirect/> or similar that occurs
// while rendering either the fallback or the new route
@ -247,12 +267,13 @@ where
owner.with(|| {
provide_context(url);
provide_context(params_memo);
provide_context(Matched(ArcMemo::from(new_matched)));
EitherOf3::B(fallback())
.rebuild(&mut state.borrow_mut().view)
});
}
Some(matched) => {
let (view, child) = matched.into_view_and_child();
Some(new_match) => {
let (view, child) = new_match.into_view_and_child();
#[cfg(debug_assertions)]
if child.is_some() {
@ -269,6 +290,9 @@ where
async move {
provide_context(url);
provide_context(params_memo);
provide_context(Matched(ArcMemo::from(
new_matched,
)));
let view =
if let Some(set_is_routing) = set_is_routing {
set_is_routing.set(true);
@ -296,6 +320,7 @@ where
drop(old_owner);
drop(old_params);
drop(old_url);
drop(old_matched);
}
})
}));
@ -349,16 +374,23 @@ where
.map(|n| n.to_params().into_iter().collect::<ParamsMap>())
.unwrap_or_default(),
);
let matched = ArcRwSignal::new(
new_match
.as_ref()
.map(|n| n.as_matched().to_owned())
.unwrap_or_default(),
);
let params_memo = ArcMemo::from(params.clone());
let view = match new_match {
None => Either::Left((self.fallback)()),
Some(matched) => {
let (view, _) = matched.into_view_and_child();
Some(new_match) => {
let (view, _) = new_match.into_view_and_child();
let view = owner
.with(|| {
ScopedFuture::new(async move {
provide_context(url);
provide_context(params_memo);
provide_context(Matched(ArcMemo::from(matched)));
view.choose().await
})
})
@ -491,6 +523,12 @@ where
// we always need to match the new route
let new_match = routes.match_route(current_url.path());
let id = new_match.as_ref().map(|n| n.as_id());
let matched = ArcRwSignal::new(
new_match
.as_ref()
.map(|n| n.as_matched().to_owned())
.unwrap_or_default(),
);
// create default starting points for owner, url, path, and params
// these will be held in state so that future navigations can update or replace them
@ -514,9 +552,10 @@ where
params,
path,
url,
matched,
})),
Some(matched) => {
let (view, child) = matched.into_view_and_child();
Some(new_match) => {
let (view, child) = new_match.into_view_and_child();
#[cfg(debug_assertions)]
if child.is_some() {
@ -528,9 +567,11 @@ where
let mut view = Box::pin(owner.with(|| {
ScopedFuture::new({
let url = url.clone();
let matched = matched.clone();
async move {
provide_context(params_memo);
provide_context(url);
provide_context(Matched(ArcMemo::from(matched)));
view.choose().await
}
})
@ -545,6 +586,7 @@ where
params,
path,
url,
matched,
})),
None => {
// see comment at the top of this function