Skip to content

Commit

Permalink
support lateral navigation
Browse files Browse the repository at this point in the history
  • Loading branch information
koa committed Sep 19, 2024
1 parent 3b6be9c commit 7aae449
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 14 deletions.
13 changes: 13 additions & 0 deletions src/history.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ impl History {
pub fn push_state(state: JsValue, url: &str) -> Result<(), JsValue> {
INSTANCE.with(|instance| instance.borrow_mut().push_state(state, url))
}
/// Replace current state in the history stack
///
/// This will send out events and update the browser's history. Ultimately calling
/// [`web_sys::History::replace_state_with_url`].
pub fn replace_state(state: JsValue, url: &str) -> Result<(), JsValue> {
INSTANCE.with(|instance| instance.borrow_mut().replace_state(state, url))
}
}

type CallbackFn = dyn Fn() + 'static;
Expand Down Expand Up @@ -87,6 +94,12 @@ impl InnerHistory {
result
}

fn replace_state(&mut self, state: JsValue, url: &str) -> Result<(), JsValue> {
let result = gloo_utils::history().replace_state_with_url(&state, "", Some(url));
self.listeners.borrow_mut().notify();
result
}

fn listener<F: Fn() + 'static>(&mut self, f: F) -> HistoryListener {
let callback = Rc::new(f) as Rc<CallbackFn>;
self.listeners.borrow_mut().add(Rc::downgrade(&callback));
Expand Down
27 changes: 23 additions & 4 deletions src/router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,19 @@ where
pub fn push(&self, target: T) {
self.scope.push(target);
}
/// Replace current state on the history. This changes the current page, but doesn't actually leave the page.
pub fn replace(&self, target: T) {
self.scope.replace(target);
}

/// Push a new state to the history, allow setting page state at the same time.
pub fn push_with(&self, target: T, state: State) {
self.scope.push_with(target, state.0);
}
/// Replace current state on the history, allow setting page state at the same time.
pub fn replace_with(&self, target: T, state: State) {
self.scope.replace_with(target, state.0);
}

/// Render the path of target.
///
Expand Down Expand Up @@ -146,6 +154,12 @@ where
pub base: Option<String>,
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum StackOperation {
Push,
Replace,
}

#[derive(Debug)]
#[doc(hidden)]
pub enum Msg<T: Target> {
Expand All @@ -154,7 +168,7 @@ pub enum Msg<T: Target> {
/// This can happen either by navigating to a new target, or by the history API's popstate event.
RouteChanged,
/// Change to a new target
ChangeTarget(NavigationTarget<T>),
ChangeTarget(NavigationTarget<T>, StackOperation),
}

/// Top-level router component.
Expand Down Expand Up @@ -215,9 +229,12 @@ where
return true;
}
}
Msg::ChangeTarget(target) => {
Msg::ChangeTarget(target, operation) => {
let route = Self::render_target(&self.base, &target.target);
let _ = History::push_state(target.state, &route);
let _ = match operation {
StackOperation::Push => History::push_state(target.state, &route),
StackOperation::Replace => History::replace_state(target.state, &route),
};
ctx.link().send_message(Msg::RouteChanged)
}
}
Expand Down Expand Up @@ -297,7 +314,9 @@ impl<T: Target> Router<T> {
ctx: &Context<Self>,
) -> (Rc<ScopeContext<T>>, RouterContext<T>) {
let scope = Rc::new(ScopeContext {
upwards: ctx.link().callback(Msg::ChangeTarget),
upwards: ctx
.link()
.callback(|(target, operation)| Msg::ChangeTarget(target, operation)),
collect: {
let base = base.clone();
Callback::from(move |target| Self::render_target(&base, &target))
Expand Down
40 changes: 30 additions & 10 deletions src/scope.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::router::RouterContext;
use crate::router::{RouterContext, StackOperation};
use crate::target::{Mapper, Target};
use wasm_bindgen::JsValue;
use yew::prelude::*;
Expand Down Expand Up @@ -34,7 +34,7 @@ pub struct ScopeContext<C>
where
C: Target,
{
pub(crate) upwards: Callback<NavigationTarget<C>>,
pub(crate) upwards: Callback<(NavigationTarget<C>, StackOperation)>,
pub(crate) collect: Callback<C, String>,
}

Expand All @@ -43,14 +43,32 @@ where
C: Target,
{
pub(crate) fn push(&self, target: C) {
self.upwards.emit(NavigationTarget {
target,
state: JsValue::null(),
});
self.upwards.emit((
(NavigationTarget {
target,
state: JsValue::null(),
}),
StackOperation::Push,
));
}

pub(crate) fn replace(&self, target: C) {
self.upwards.emit((
(NavigationTarget {
target,
state: JsValue::null(),
}),
StackOperation::Replace,
));
}

pub(crate) fn push_with(&self, target: C, state: JsValue) {
self.upwards.emit(NavigationTarget { target, state })
self.upwards
.emit((NavigationTarget { target, state }, StackOperation::Push))
}
pub(crate) fn replace_with(&self, target: C, state: JsValue) {
self.upwards
.emit((NavigationTarget { target, state }, StackOperation::Replace))
}

pub(crate) fn collect(&self, target: C) -> String {
Expand Down Expand Up @@ -90,9 +108,11 @@ where
upwards: {
let parent = parent.upwards.clone();
let upwards = upwards.clone();
Callback::from(move |child: NavigationTarget<C>| {
parent.emit(child.map(|child| upwards.emit(child)));
})
Callback::from(
move |(target, operation): (NavigationTarget<C>, StackOperation)| {
parent.emit((target.map(|target| upwards.emit(target)), operation));
},
)
},
collect: {
let parent = parent.collect.clone();
Expand Down

0 comments on commit 7aae449

Please sign in to comment.